realtime-avatar 0.27.0 → 0.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -1
- package/dist/{chunk-SUKZ77GL.js → chunk-SP5SYYSS.js} +1 -1
- package/dist/{chunk-NMJQEGYW.js → chunk-YR5NJTEO.js} +8 -3
- 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 +2 -2
- package/dist/index.js +1 -1
- package/dist/nextjs.d.ts +2 -2
- package/dist/nextjs.js +2 -2
- package/dist/{proxy-client-D75TLU5X.d.ts → proxy-client-DW_EOvmE.d.ts} +27 -5
- package/dist/react-native.d.ts +2 -2
- package/dist/react-native.js +168 -36
- package/dist/react.d.ts +2 -2
- package/dist/react.js +168 -36
- 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-JtCwa0Ip.d.ts → types-BH9O5leB.d.ts} +1 -1
- package/dist/{types-6MUqx800.d.ts → types-D_s7ff7w.d.ts} +7 -0
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1074,6 +1074,8 @@ function RealtimeAvatarLiveKitRoom(props) {
|
|
|
1074
1074
|
LiveKitRoom,
|
|
1075
1075
|
{
|
|
1076
1076
|
...roomProps,
|
|
1077
|
+
// A new grant owns a new room and bridge; an old room must not report its agent into it.
|
|
1078
|
+
key: grant?.session_id ?? "no-session",
|
|
1077
1079
|
serverUrl: grant?.livekit_url,
|
|
1078
1080
|
token: grant?.participant_token,
|
|
1079
1081
|
connect: shouldConnect,
|
|
@@ -2331,6 +2333,8 @@ var transcriptionOptionsSchema = z.object({
|
|
|
2331
2333
|
languageCodes: transcriptionWireSchema.shape.language_codes,
|
|
2332
2334
|
customVocabulary: transcriptionWireSchema.shape.custom_vocabulary
|
|
2333
2335
|
}).strict();
|
|
2336
|
+
var schema02 = z.enum(["minor-sexual-content-v1"]);
|
|
2337
|
+
var contentPolicySchema = schema02;
|
|
2334
2338
|
|
|
2335
2339
|
// ../client/src/wire.ts
|
|
2336
2340
|
var DEFAULT_AVATAR_ID = "maria";
|
|
@@ -2497,7 +2501,8 @@ z.object({
|
|
|
2497
2501
|
support_edits: sessionSupportEditsSchema.optional(),
|
|
2498
2502
|
transcript_webhook: transcriptWebhookSchema.optional(),
|
|
2499
2503
|
client_metadata: clientMetadataSchema.optional(),
|
|
2500
|
-
connection_history: z.boolean().optional()
|
|
2504
|
+
connection_history: z.boolean().optional(),
|
|
2505
|
+
content_policy: contentPolicySchema.optional()
|
|
2501
2506
|
}).strict().superRefine((value, ctx) => {
|
|
2502
2507
|
if (value.support_edits && value.render_backend === "generative") {
|
|
2503
2508
|
ctx.addIssue({
|
|
@@ -2565,7 +2570,8 @@ z.object({
|
|
|
2565
2570
|
supportEdits: sessionSupportEditsSchema.optional(),
|
|
2566
2571
|
transcriptWebhook: transcriptWebhookSchema.optional(),
|
|
2567
2572
|
clientMetadata: clientMetadataSchema.optional(),
|
|
2568
|
-
connectionHistory: z.boolean().optional()
|
|
2573
|
+
connectionHistory: z.boolean().optional(),
|
|
2574
|
+
contentPolicy: contentPolicySchema.optional()
|
|
2569
2575
|
}).strict();
|
|
2570
2576
|
z.object({
|
|
2571
2577
|
recording: recordingArtifactSchema.optional(),
|
|
@@ -3019,7 +3025,8 @@ function lifecyclePhaseFrom(args) {
|
|
|
3019
3025
|
kind: "reconnectable",
|
|
3020
3026
|
reconnecting: true,
|
|
3021
3027
|
attempt: recovery.attempt,
|
|
3022
|
-
strategy: "fresh-grant"
|
|
3028
|
+
strategy: "fresh-grant",
|
|
3029
|
+
...recovery.reason ? { reason: recovery.reason } : {}
|
|
3023
3030
|
};
|
|
3024
3031
|
}
|
|
3025
3032
|
if (recovery.kind === "failed") {
|
|
@@ -3027,11 +3034,16 @@ function lifecyclePhaseFrom(args) {
|
|
|
3027
3034
|
kind: "reconnectable",
|
|
3028
3035
|
reconnecting: false,
|
|
3029
3036
|
attempt: MAX_RECONNECT_ATTEMPTS,
|
|
3030
|
-
strategy: "fresh-grant"
|
|
3037
|
+
strategy: "fresh-grant",
|
|
3038
|
+
...recovery.reason ? { reason: recovery.reason } : {}
|
|
3031
3039
|
};
|
|
3032
3040
|
}
|
|
3033
3041
|
if (recovery.kind === "ended") {
|
|
3034
|
-
return
|
|
3042
|
+
return {
|
|
3043
|
+
kind: "ended",
|
|
3044
|
+
...recovery.reason ? { reason: recovery.reason } : {},
|
|
3045
|
+
...recovery.code ? { code: recovery.code } : {}
|
|
3046
|
+
};
|
|
3035
3047
|
}
|
|
3036
3048
|
switch (capacity.kind) {
|
|
3037
3049
|
case "idle":
|
|
@@ -3044,7 +3056,7 @@ function lifecyclePhaseFrom(args) {
|
|
|
3044
3056
|
return { kind: "ended", reason: "error" };
|
|
3045
3057
|
case "active": {
|
|
3046
3058
|
if (!connected || !agentPresent) {
|
|
3047
|
-
return { kind: "connecting", grant: capacity.grant };
|
|
3059
|
+
return { kind: "connecting", grant: capacity.grant, waitingFor: connected ? "agent" : "transport" };
|
|
3048
3060
|
}
|
|
3049
3061
|
if (idle.kind === "idle-warning") {
|
|
3050
3062
|
return { kind: "idle-warning", secondsRemaining: idle.secondsRemaining, deadlineAt: idle.deadlineAt };
|
|
@@ -3072,6 +3084,7 @@ function resolveIdleTimeoutMs(args) {
|
|
|
3072
3084
|
return DEFAULT_IDLE_SECONDS * 1e3;
|
|
3073
3085
|
}
|
|
3074
3086
|
var DEFAULT_CONNECT_WATCHDOG_SECONDS = 12;
|
|
3087
|
+
var DEFAULT_READY_TIMEOUT_SECONDS = 30;
|
|
3075
3088
|
function resolveWarnBeforeMs(idleTimeoutMs, override, idleWarnLeadSeconds) {
|
|
3076
3089
|
if (idleTimeoutMs <= 0) return 0;
|
|
3077
3090
|
const maxLeadMs = Math.max(0, idleTimeoutMs - 1e3);
|
|
@@ -3097,6 +3110,7 @@ function useSessionLifecycle(input) {
|
|
|
3097
3110
|
maxReconnectAttempts,
|
|
3098
3111
|
autoRetryBusy = true,
|
|
3099
3112
|
connectWatchdogSeconds,
|
|
3113
|
+
readyTimeoutSeconds,
|
|
3100
3114
|
requestOptions,
|
|
3101
3115
|
onBehaviorChange
|
|
3102
3116
|
} = input;
|
|
@@ -3107,17 +3121,27 @@ function useSessionLifecycle(input) {
|
|
|
3107
3121
|
const reconnectPolicyRef = useRef(reconnectPolicy);
|
|
3108
3122
|
reconnectPolicyRef.current = reconnectPolicy;
|
|
3109
3123
|
const connectWatchdogMs = typeof connectWatchdogSeconds === "number" && Number.isFinite(connectWatchdogSeconds) ? Math.max(0, Math.floor(connectWatchdogSeconds)) * 1e3 : DEFAULT_CONNECT_WATCHDOG_SECONDS * 1e3;
|
|
3124
|
+
const readyTimeoutMs = typeof readyTimeoutSeconds === "number" && Number.isFinite(readyTimeoutSeconds) && readyTimeoutSeconds > 0 ? Math.max(1, Math.floor(readyTimeoutSeconds)) * 1e3 : DEFAULT_READY_TIMEOUT_SECONDS * 1e3;
|
|
3110
3125
|
const [userEnded, setUserEnded] = useState(false);
|
|
3111
3126
|
const userEndedRef = useRef(false);
|
|
3127
|
+
const [readinessFailed, setReadinessFailed] = useState(false);
|
|
3128
|
+
const readinessFailureRef = useRef(null);
|
|
3129
|
+
const readinessRef = useRef(null);
|
|
3130
|
+
const readyGrantRef = useRef(null);
|
|
3131
|
+
const agentWaitRef = useRef(null);
|
|
3112
3132
|
const phaseRef = useRef({ kind: "idle" });
|
|
3113
3133
|
const grantState = useLiveKitAvatarGrant({
|
|
3114
3134
|
client,
|
|
3115
3135
|
session,
|
|
3116
|
-
active: active && !userEnded,
|
|
3136
|
+
active: active && !userEnded && !readinessFailed,
|
|
3117
3137
|
autoRetryBusy,
|
|
3118
3138
|
requestOptions
|
|
3119
3139
|
});
|
|
3120
3140
|
const capacity = grantState.capacity;
|
|
3141
|
+
const grantId = grantState.grant?.session_id ?? null;
|
|
3142
|
+
const grantIdRef = useRef(null);
|
|
3143
|
+
grantIdRef.current = grantId;
|
|
3144
|
+
const retiredGrantRef = useRef(null);
|
|
3121
3145
|
const [recovery, setRecovery] = useState({ kind: "connected" });
|
|
3122
3146
|
const recoveryRef = useRef(recovery);
|
|
3123
3147
|
recoveryRef.current = recovery;
|
|
@@ -3140,8 +3164,19 @@ function useSessionLifecycle(input) {
|
|
|
3140
3164
|
grantIdleSeconds: grantState.grant?.idle_timeout_seconds ?? 0
|
|
3141
3165
|
});
|
|
3142
3166
|
const warnAtMs = resolveWarnBeforeMs(idleTimeoutMs, warnBeforeMs, idleWarnLeadSeconds);
|
|
3143
|
-
const [
|
|
3144
|
-
const [
|
|
3167
|
+
const [agentObservation, setAgentObservation] = useState({ grantId: null, present: false });
|
|
3168
|
+
const [connectionObservation, setConnectionObservation] = useState({ grantId: null, connected: false });
|
|
3169
|
+
const agentPresent = agentObservation.grantId === grantId && agentObservation.present;
|
|
3170
|
+
const connected = connectionObservation.grantId === grantId && connectionObservation.connected;
|
|
3171
|
+
connectedRef.current = connected;
|
|
3172
|
+
const setAgentPresentState = useCallback((present) => {
|
|
3173
|
+
const owner = grantIdRef.current;
|
|
3174
|
+
setAgentObservation((prev) => prev.grantId === owner && prev.present === present ? prev : { grantId: owner, present });
|
|
3175
|
+
}, []);
|
|
3176
|
+
const setConnected = useCallback((value) => {
|
|
3177
|
+
const owner = grantIdRef.current;
|
|
3178
|
+
setConnectionObservation((prev) => prev.grantId === owner && prev.connected === value ? prev : { grantId: owner, connected: value });
|
|
3179
|
+
}, []);
|
|
3145
3180
|
const lastActivityRef = useRef(Date.now());
|
|
3146
3181
|
const leaveRoomRef = useRef(null);
|
|
3147
3182
|
const [, setClockTick] = useState(0);
|
|
@@ -3158,7 +3193,11 @@ function useSessionLifecycle(input) {
|
|
|
3158
3193
|
refreshBaselineCapacityRef.current = null;
|
|
3159
3194
|
attemptRef.current = 0;
|
|
3160
3195
|
setAttempt(0);
|
|
3161
|
-
|
|
3196
|
+
readinessRef.current = null;
|
|
3197
|
+
readyGrantRef.current = null;
|
|
3198
|
+
agentWaitRef.current = null;
|
|
3199
|
+
retiredGrantRef.current = null;
|
|
3200
|
+
setRecovery(userEndedRef.current ? { kind: "ended", reason: "user" } : readinessFailureRef.current ? { kind: "ended", reason: "error", code: readinessFailureRef.current } : { kind: "connected" });
|
|
3162
3201
|
setConnected(false);
|
|
3163
3202
|
setAgentPresentState(false);
|
|
3164
3203
|
lastActivityRef.current = Date.now();
|
|
@@ -3167,26 +3206,33 @@ function useSessionLifecycle(input) {
|
|
|
3167
3206
|
if (active) return;
|
|
3168
3207
|
userEndedRef.current = false;
|
|
3169
3208
|
setUserEnded(false);
|
|
3209
|
+
readinessFailureRef.current = null;
|
|
3210
|
+
setReadinessFailed(false);
|
|
3170
3211
|
reset();
|
|
3171
3212
|
}, [active, reset]);
|
|
3172
3213
|
const markActivity = useCallback(() => {
|
|
3214
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3173
3215
|
lastActivityRef.current = Date.now();
|
|
3174
3216
|
setClockTick((value) => value + 1);
|
|
3175
|
-
}, []);
|
|
3217
|
+
}, [grantId]);
|
|
3176
3218
|
const stayConnected = useCallback(() => {
|
|
3219
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3177
3220
|
if (!connectedRef.current) return;
|
|
3178
3221
|
lastActivityRef.current = Date.now();
|
|
3179
3222
|
setClockTick((value) => value + 1);
|
|
3180
|
-
}, []);
|
|
3223
|
+
}, [grantId]);
|
|
3181
3224
|
const setAgentPresent = useCallback((present) => {
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3225
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3226
|
+
if (userEndedRef.current || readinessFailureRef.current || retiredGrantRef.current !== null && retiredGrantRef.current === grantIdRef.current) return;
|
|
3227
|
+
setAgentObservation((prev) => {
|
|
3228
|
+
if (present && (prev.grantId !== grantId || !prev.present)) lastActivityRef.current = Date.now();
|
|
3229
|
+
return prev.grantId === grantId && prev.present === present ? prev : { grantId, present };
|
|
3185
3230
|
});
|
|
3186
|
-
}, []);
|
|
3231
|
+
}, [grantId]);
|
|
3187
3232
|
const registerLeaveRoom = useCallback((leave) => {
|
|
3233
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3188
3234
|
leaveRoomRef.current = leave;
|
|
3189
|
-
}, []);
|
|
3235
|
+
}, [grantId]);
|
|
3190
3236
|
const endIdle = useCallback(() => {
|
|
3191
3237
|
if (!connectedRef.current) return;
|
|
3192
3238
|
clearTimer();
|
|
@@ -3198,24 +3244,25 @@ function useSessionLifecycle(input) {
|
|
|
3198
3244
|
leaveRoomRef.current?.();
|
|
3199
3245
|
}, [clearTimer]);
|
|
3200
3246
|
const onConnected = useCallback(() => {
|
|
3201
|
-
if (
|
|
3247
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3248
|
+
if (userEndedRef.current || readinessFailureRef.current || retiredGrantRef.current !== null && retiredGrantRef.current === grantIdRef.current) return;
|
|
3202
3249
|
clearTimer();
|
|
3203
3250
|
connectedRef.current = true;
|
|
3204
3251
|
manualReconnectPendingRef.current = false;
|
|
3205
3252
|
refreshBaselineCapacityRef.current = null;
|
|
3206
3253
|
setConnected(true);
|
|
3207
|
-
|
|
3208
|
-
setAttempt(0);
|
|
3254
|
+
if (readinessRef.current) readinessRef.current.sawTransport = true;
|
|
3209
3255
|
setRecovery({ kind: "connected" });
|
|
3210
3256
|
lastActivityRef.current = Date.now();
|
|
3211
|
-
}, [clearTimer]);
|
|
3257
|
+
}, [clearTimer, grantId]);
|
|
3212
3258
|
const onDisconnected = useCallback(
|
|
3213
3259
|
(reason) => {
|
|
3214
|
-
if (
|
|
3260
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3261
|
+
if (!active || userEndedRef.current || readinessFailureRef.current) return;
|
|
3215
3262
|
const action = disconnectAction(reason, connectedRef.current);
|
|
3216
3263
|
if (action === "noop") return;
|
|
3217
3264
|
if (action === "reset") {
|
|
3218
|
-
if (recoveryRef.current.kind === "refreshing") return;
|
|
3265
|
+
if (recoveryRef.current.kind === "refreshing" || recoveryRef.current.kind === "reconnecting") return;
|
|
3219
3266
|
reset();
|
|
3220
3267
|
return;
|
|
3221
3268
|
}
|
|
@@ -3232,11 +3279,12 @@ function useSessionLifecycle(input) {
|
|
|
3232
3279
|
refreshBaselineCapacityRef.current = null;
|
|
3233
3280
|
setRecovery({ kind: "reconnecting", attempt: attemptRef.current });
|
|
3234
3281
|
},
|
|
3235
|
-
[active, reset]
|
|
3282
|
+
[active, reset, grantId]
|
|
3236
3283
|
);
|
|
3237
3284
|
const onConnectionError = useCallback(
|
|
3238
3285
|
(error) => {
|
|
3239
|
-
if (
|
|
3286
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3287
|
+
if (!active || userEndedRef.current || readinessFailureRef.current || !isRecoverableConnectionError(error)) return;
|
|
3240
3288
|
connectedRef.current = false;
|
|
3241
3289
|
setConnected(false);
|
|
3242
3290
|
setAgentPresentState(false);
|
|
@@ -3247,7 +3295,7 @@ function useSessionLifecycle(input) {
|
|
|
3247
3295
|
return { kind: "reconnecting", attempt: attemptRef.current };
|
|
3248
3296
|
});
|
|
3249
3297
|
},
|
|
3250
|
-
[active]
|
|
3298
|
+
[active, grantId]
|
|
3251
3299
|
);
|
|
3252
3300
|
useEffect(() => {
|
|
3253
3301
|
if (capacity.kind === "error" && recovery.kind === "connected") manualReconnectPendingRef.current = false;
|
|
@@ -3257,11 +3305,12 @@ function useSessionLifecycle(input) {
|
|
|
3257
3305
|
const baseline = refreshBaselineCapacityRef.current;
|
|
3258
3306
|
if (baseline?.kind === "error" && baseline.error === capacity.error) return;
|
|
3259
3307
|
refreshBaselineCapacityRef.current = null;
|
|
3260
|
-
setRecovery({ kind: "reconnecting", attempt: recovery.attempt });
|
|
3308
|
+
setRecovery({ kind: "reconnecting", attempt: recovery.attempt, ...recovery.reason ? { reason: recovery.reason } : {} });
|
|
3261
3309
|
}, [capacity, recovery]);
|
|
3262
3310
|
const onConnectionStateChange = useCallback(
|
|
3263
3311
|
(state) => {
|
|
3264
|
-
if (
|
|
3312
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
3313
|
+
if (!active || userEndedRef.current || readinessFailureRef.current) return;
|
|
3265
3314
|
if (state === "connected") {
|
|
3266
3315
|
onConnected();
|
|
3267
3316
|
return;
|
|
@@ -3275,14 +3324,78 @@ function useSessionLifecycle(input) {
|
|
|
3275
3324
|
}
|
|
3276
3325
|
}
|
|
3277
3326
|
},
|
|
3278
|
-
[active, onConnected]
|
|
3327
|
+
[active, onConnected, grantId]
|
|
3279
3328
|
);
|
|
3329
|
+
useEffect(() => {
|
|
3330
|
+
if (!active || userEnded || readinessFailed || !connected || !agentPresent || !grantState.grant) return;
|
|
3331
|
+
readyGrantRef.current = grantState.grant.session_id;
|
|
3332
|
+
readinessRef.current = null;
|
|
3333
|
+
agentWaitRef.current = null;
|
|
3334
|
+
attemptRef.current = 0;
|
|
3335
|
+
setAttempt(0);
|
|
3336
|
+
}, [active, userEnded, readinessFailed, connected, agentPresent, grantState.grant]);
|
|
3337
|
+
const failReadiness = useCallback((code) => {
|
|
3338
|
+
if (userEndedRef.current || readinessFailureRef.current) return;
|
|
3339
|
+
readinessFailureRef.current = code;
|
|
3340
|
+
clearTimer();
|
|
3341
|
+
connectedRef.current = false;
|
|
3342
|
+
manualReconnectPendingRef.current = false;
|
|
3343
|
+
refreshBaselineCapacityRef.current = null;
|
|
3344
|
+
const ended = { kind: "ended", reason: "error", code };
|
|
3345
|
+
recoveryRef.current = ended;
|
|
3346
|
+
setRecovery(ended);
|
|
3347
|
+
setConnected(false);
|
|
3348
|
+
setAgentPresentState(false);
|
|
3349
|
+
releaseRef.current("disconnected");
|
|
3350
|
+
setReadinessFailed(true);
|
|
3351
|
+
leaveRoomRef.current?.();
|
|
3352
|
+
}, [clearTimer]);
|
|
3353
|
+
useEffect(() => {
|
|
3354
|
+
if (!active || userEnded || readinessFailed) return;
|
|
3355
|
+
if (recovery.kind === "ended" || recovery.kind === "failed") return;
|
|
3356
|
+
if (grantState.grant && readyGrantRef.current === grantState.grant.session_id) return;
|
|
3357
|
+
if (!readinessRef.current && grantState.grant) {
|
|
3358
|
+
readinessRef.current = { startedAt: Date.now(), sawTransport: connected };
|
|
3359
|
+
}
|
|
3360
|
+
const budget = readinessRef.current;
|
|
3361
|
+
if (!budget) return;
|
|
3362
|
+
const timer = window.setTimeout(() => {
|
|
3363
|
+
if (readinessRef.current !== budget) return;
|
|
3364
|
+
failReadiness(budget.sawTransport ? "agent_timeout" : "connection_timeout");
|
|
3365
|
+
}, Math.max(0, budget.startedAt + readyTimeoutMs - Date.now()));
|
|
3366
|
+
return () => window.clearTimeout(timer);
|
|
3367
|
+
}, [active, userEnded, readinessFailed, connected, agentPresent, grantState.grant, recovery.kind, readyTimeoutMs, failReadiness]);
|
|
3368
|
+
useEffect(() => {
|
|
3369
|
+
const sessionId = grantState.grant?.session_id;
|
|
3370
|
+
if (!active || userEnded || readinessFailed || !sessionId || readyGrantRef.current === sessionId || agentPresent) return;
|
|
3371
|
+
if (recovery.kind === "reconnecting" || recovery.kind === "failed" || recovery.kind === "ended") return;
|
|
3372
|
+
if (agentWaitRef.current?.sessionId !== sessionId) {
|
|
3373
|
+
if (!connected) return;
|
|
3374
|
+
agentWaitRef.current = { sessionId, startedAt: Date.now() };
|
|
3375
|
+
}
|
|
3376
|
+
const wait = agentWaitRef.current;
|
|
3377
|
+
if (connectWatchdogMs <= 0) return;
|
|
3378
|
+
const timer = window.setTimeout(() => {
|
|
3379
|
+
if (agentWaitRef.current !== wait || readinessFailureRef.current || userEndedRef.current) return;
|
|
3380
|
+
retiredGrantRef.current = sessionId;
|
|
3381
|
+
connectedRef.current = false;
|
|
3382
|
+
setConnected(false);
|
|
3383
|
+
setAgentPresentState(false);
|
|
3384
|
+
const next = { kind: "reconnecting", attempt: attemptRef.current, reason: "agent_timeout" };
|
|
3385
|
+
recoveryRef.current = next;
|
|
3386
|
+
setRecovery(next);
|
|
3387
|
+
releaseRef.current("disconnected");
|
|
3388
|
+
leaveRoomRef.current?.();
|
|
3389
|
+
}, Math.max(0, wait.startedAt + connectWatchdogMs - Date.now()));
|
|
3390
|
+
return () => window.clearTimeout(timer);
|
|
3391
|
+
}, [active, userEnded, readinessFailed, connected, agentPresent, grantState.grant, recovery.kind, connectWatchdogMs]);
|
|
3280
3392
|
useEffect(() => {
|
|
3281
3393
|
if (!active || connected || connectWatchdogMs <= 0) return;
|
|
3282
3394
|
if (grantState.status !== "ready" || !grantState.grant) return;
|
|
3283
3395
|
if (recovery.kind === "failed" || recovery.kind === "ended") return;
|
|
3284
3396
|
if (recovery.kind === "in-place-reconnecting") return;
|
|
3285
3397
|
const timer = window.setTimeout(() => {
|
|
3398
|
+
if (readinessFailureRef.current || userEndedRef.current) return;
|
|
3286
3399
|
releaseRef.current("disconnected");
|
|
3287
3400
|
setRecovery({ kind: "reconnecting", attempt: attemptRef.current });
|
|
3288
3401
|
}, connectWatchdogMs);
|
|
@@ -3292,6 +3405,10 @@ function useSessionLifecycle(input) {
|
|
|
3292
3405
|
if (!active || !needsFreshGrant(recovery)) return;
|
|
3293
3406
|
const step2 = retryStep(attemptRef.current, reconnectPolicyRef.current);
|
|
3294
3407
|
if (step2.kind === "give-up") {
|
|
3408
|
+
if (readinessRef.current) {
|
|
3409
|
+
failReadiness(readinessRef.current.sawTransport ? "agent_timeout" : "connection_timeout");
|
|
3410
|
+
return;
|
|
3411
|
+
}
|
|
3295
3412
|
manualReconnectPendingRef.current = false;
|
|
3296
3413
|
refreshBaselineCapacityRef.current = null;
|
|
3297
3414
|
releaseRef.current("disconnected");
|
|
@@ -3300,15 +3417,16 @@ function useSessionLifecycle(input) {
|
|
|
3300
3417
|
}
|
|
3301
3418
|
timerRef.current = window.setTimeout(() => {
|
|
3302
3419
|
timerRef.current = null;
|
|
3420
|
+
if (readinessFailureRef.current || userEndedRef.current) return;
|
|
3303
3421
|
attemptRef.current = step2.attempt;
|
|
3304
3422
|
setAttempt(step2.attempt);
|
|
3305
3423
|
refreshBaselineCapacityRef.current = capacityRef.current;
|
|
3306
3424
|
releaseRef.current("superseded");
|
|
3307
|
-
setRecovery({ kind: "refreshing", attempt: step2.attempt });
|
|
3425
|
+
setRecovery({ kind: "refreshing", attempt: step2.attempt, ...recovery.reason ? { reason: recovery.reason } : {} });
|
|
3308
3426
|
refreshRef.current();
|
|
3309
3427
|
}, step2.delayMs);
|
|
3310
3428
|
return clearTimer;
|
|
3311
|
-
}, [recovery.kind, active, attempt, clearTimer]);
|
|
3429
|
+
}, [recovery.kind, active, attempt, clearTimer, failReadiness]);
|
|
3312
3430
|
const end = useCallback(() => {
|
|
3313
3431
|
if (!active || userEndedRef.current || phaseRef.current.kind === "ended") return;
|
|
3314
3432
|
userEndedRef.current = true;
|
|
@@ -3325,6 +3443,13 @@ function useSessionLifecycle(input) {
|
|
|
3325
3443
|
}, [active, clearTimer]);
|
|
3326
3444
|
const reconnect = useCallback(() => {
|
|
3327
3445
|
if (!active) return;
|
|
3446
|
+
if (readinessFailureRef.current) {
|
|
3447
|
+
readinessFailureRef.current = null;
|
|
3448
|
+
setReadinessFailed(false);
|
|
3449
|
+
reset();
|
|
3450
|
+
manualReconnectPendingRef.current = true;
|
|
3451
|
+
return;
|
|
3452
|
+
}
|
|
3328
3453
|
if (userEndedRef.current) {
|
|
3329
3454
|
userEndedRef.current = false;
|
|
3330
3455
|
setUserEnded(false);
|
|
@@ -3335,6 +3460,12 @@ function useSessionLifecycle(input) {
|
|
|
3335
3460
|
if (manualReconnectPendingRef.current || recovery.kind === "in-place-reconnecting") return;
|
|
3336
3461
|
manualReconnectPendingRef.current = true;
|
|
3337
3462
|
clearTimer();
|
|
3463
|
+
readinessRef.current = null;
|
|
3464
|
+
agentWaitRef.current = null;
|
|
3465
|
+
readyGrantRef.current = null;
|
|
3466
|
+
connectedRef.current = false;
|
|
3467
|
+
setConnected(false);
|
|
3468
|
+
setAgentPresentState(false);
|
|
3338
3469
|
attemptRef.current = 0;
|
|
3339
3470
|
setAttempt(0);
|
|
3340
3471
|
refreshBaselineCapacityRef.current = capacityRef.current;
|
|
@@ -3454,6 +3585,7 @@ function SessionLifecycleRoomBridge({
|
|
|
3454
3585
|
const assistant = useVoiceAssistant();
|
|
3455
3586
|
const transcriptions = useTranscriptions();
|
|
3456
3587
|
const room = useRoomContext();
|
|
3588
|
+
const roomMatchesGrant = lifecycle.grant === void 0 || lifecycle.grant !== null && room.name === lifecycle.grant.room_name;
|
|
3457
3589
|
useCallMedia(room, {
|
|
3458
3590
|
setMicrophoneFacts,
|
|
3459
3591
|
setAudioPlayback,
|
|
@@ -3607,11 +3739,11 @@ function SessionLifecycleRoomBridge({
|
|
|
3607
3739
|
detailsEnabled ? video?.publication : void 0
|
|
3608
3740
|
]);
|
|
3609
3741
|
useEffect(() => {
|
|
3610
|
-
onConnectionStateChange(connectionState);
|
|
3611
|
-
}, [connectionState, onConnectionStateChange]);
|
|
3742
|
+
if (roomMatchesGrant) onConnectionStateChange(connectionState);
|
|
3743
|
+
}, [connectionState, onConnectionStateChange, roomMatchesGrant]);
|
|
3612
3744
|
useEffect(() => {
|
|
3613
|
-
setAgentPresent(agentPresent);
|
|
3614
|
-
}, [agentPresent, setAgentPresent]);
|
|
3745
|
+
if (roomMatchesGrant) setAgentPresent(agentPresent);
|
|
3746
|
+
}, [agentPresent, setAgentPresent, roomMatchesGrant]);
|
|
3615
3747
|
useEffect(() => {
|
|
3616
3748
|
const active = isCallActivity({
|
|
3617
3749
|
assistantState,
|
|
@@ -4675,4 +4807,4 @@ function RecordingPlayer({ assets, className }) {
|
|
|
4675
4807
|
] });
|
|
4676
4808
|
}
|
|
4677
4809
|
|
|
4678
|
-
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, RecordingPlayer, SessionLifecycleRoomBridge, capacityErrorFromBusy, capacityStateFromGrant, createProxyClient, knownBehaviorStates, mapTurnState, readInboundRtp, sessionBehaviorSchema, sessionClipSchema, shouldReplayPendingTurn, splitCallTranscript, useAvatarAdaptivePlayoutDelay, useAvatarCall, useAvatarCamera, useAvatarPlayoutDelay, useAvatarQualityGovernor, useCallTranscript, useCharacterTools, useLiveKitAvatarGrant, useMicLease, useRealtimeSession, useReleaseMicLeaseOnTrackEnded, useSessionLifecycle };
|
|
4810
|
+
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_READY_TIMEOUT_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, RecordingPlayer, SessionLifecycleRoomBridge, capacityErrorFromBusy, capacityStateFromGrant, createProxyClient, knownBehaviorStates, mapTurnState, readInboundRtp, sessionBehaviorSchema, sessionClipSchema, shouldReplayPendingTurn, splitCallTranscript, useAvatarAdaptivePlayoutDelay, useAvatarCall, useAvatarCamera, useAvatarPlayoutDelay, useAvatarQualityGovernor, useCallTranscript, useCharacterTools, useLiveKitAvatarGrant, useMicLease, useRealtimeSession, useReleaseMicLeaseOnTrackEnded, useSessionLifecycle };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, RealtimeAvatarOptions, StartCallOptions, clipLibraryDeclarationSchema, verifyTranscript } from './index.js';
|
|
2
|
-
export { h as Asset, g as AssetKind, A as Avatar, o as AvatarClip, c as AvatarSourceSwap, b as AvatarUpdate, p as CallConnection, C as CallMode, a as CallPolicy, q as CallQueued, r as ClipDeclaration, f as ClipLibrary, d as ClipLibraryDeclaration, s as ClipLibraryPlan, e as ClipLibraryUpdate, t as ClipSource, u as ContextMessage, n as CreditBalance, E as EndCallOptions, v as EndCallReason, w as ExternalLlm, k as ListRecordingsQuery, l as ListRecordingsResponse, i as ListSessionsOptions, L as LoopRedirect, m as RecordingAccessResponse, R as RecordingArtifact, x as RecordingArtifactStatus, y as RecordingMode, S as StartCallResult, T as TranscriptPayload, j as UsageSession, U as UsageSessionPage, V as VideoPolicy, z as isQueued, B as listRecordingsResponseSchema, D as recordingAccessResponseSchema, F as recordingArtifactSchema, G as recordingModeSchema } from './types-
|
|
2
|
+
export { h as Asset, g as AssetKind, A as Avatar, o as AvatarClip, c as AvatarSourceSwap, b as AvatarUpdate, p as CallConnection, C as CallMode, a as CallPolicy, q as CallQueued, r as ClipDeclaration, f as ClipLibrary, d as ClipLibraryDeclaration, s as ClipLibraryPlan, e as ClipLibraryUpdate, t as ClipSource, u as ContextMessage, n as CreditBalance, E as EndCallOptions, v as EndCallReason, w as ExternalLlm, k as ListRecordingsQuery, l as ListRecordingsResponse, i as ListSessionsOptions, L as LoopRedirect, m as RecordingAccessResponse, R as RecordingArtifact, x as RecordingArtifactStatus, y as RecordingMode, S as StartCallResult, T as TranscriptPayload, j as UsageSession, U as UsageSessionPage, V as VideoPolicy, z as isQueued, B as listRecordingsResponseSchema, D as recordingAccessResponseSchema, F as recordingArtifactSchema, G as recordingModeSchema } from './types-D_s7ff7w.js';
|
|
3
3
|
import './connection-history.js';
|
|
4
4
|
import 'zod';
|
package/dist/server.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, listRecordingsResponseSchema, recordingAccessResponseSchema, recordingArtifactSchema, recordingModeSchema, verifyTranscript } from './chunk-
|
|
1
|
+
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, listRecordingsResponseSchema, recordingAccessResponseSchema, recordingArtifactSchema, recordingModeSchema, verifyTranscript } from './chunk-YR5NJTEO.js';
|
|
2
2
|
import './chunk-MCIXU6XP.js';
|
package/dist/tanstack-start.d.ts
CHANGED
package/dist/tanstack-start.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CallMode, a as CallPolicy } from './types-
|
|
1
|
+
import { C as CallMode, a as CallPolicy } from './types-D_s7ff7w.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";
|
|
@@ -170,6 +170,11 @@ interface components {
|
|
|
170
170
|
url: string;
|
|
171
171
|
secret: string;
|
|
172
172
|
};
|
|
173
|
+
/**
|
|
174
|
+
* @description Server-authored content enforcement policy. API-key integrators may request it; browser mints strip it. No default. Requires worker enforcement before emission; transport alone does not provide protection.
|
|
175
|
+
* @enum {string}
|
|
176
|
+
*/
|
|
177
|
+
content_policy?: "minor-sexual-content-v1";
|
|
173
178
|
/**
|
|
174
179
|
* @description Server-owned recording policy; omitted means off. Legacy audio includes user and avatar audio. participants saves one continuous audio/video file per participant, without mixing their voices.
|
|
175
180
|
* @enum {string}
|
|
@@ -1663,6 +1668,8 @@ interface ExternalLlm {
|
|
|
1663
1668
|
}
|
|
1664
1669
|
/** What YOUR SERVER decides about a call. Never accept any of this from a browser. */
|
|
1665
1670
|
interface CallPolicy {
|
|
1671
|
+
/** Optional server-owned content safety policy. Never accept a selection or disable from the browser. */
|
|
1672
|
+
contentPolicy?: Wire["LiveKitSessionRequest"]["content_policy"];
|
|
1666
1673
|
/** Ask the platform to grant the SDK's optional LiveKit connection history collector. */
|
|
1667
1674
|
connectionHistory?: boolean;
|
|
1668
1675
|
/** Optional server recording policy. Omitted means off; obtain user consent before enabling. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "realtime-avatar",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.2",
|
|
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",
|