You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Runway enforces a hard 5-minute limit on realtime avatar sessions at runtime. Their Characters "Core Concepts" docs state "Sessions have a maximum duration of 5 minutes" — and it is enforced, even though POST /v1/realtime_sessions happily accepts maxDuration up to 1800 (that bound appears to be billing-only; values >1800 are rejected with 400 "Too big: expected number to be <=1800").
Measured timeline from a live session:
AvatarSession.start() → video track subscribed +5.4s (nice warm start)
avatar lip-syncs a real conversation flawlessly
+301s: the runway-avatar-agent participant disconnects mid-utterance — Runway completed the session server-side
Because the plugin routes agent audio into the avatar's DataStreamAudioOutput, two things follow for anyone running conversations longer than 5 minutes:
The avatar silently disappears mid-conversation.
The in-flight utterance is lost — TTS frames already handed to the dying session's stream never play, and subsequent frames go to a dead sink until the app intervenes. There is no plugin-level signal that the session expired (vs. any other disconnect).
Neither the plugin docs nor the LiveKit avatar integration page mention the cap, so this surfaces as a mystery disconnect in production. Two other integration notes that cost us time: AvatarSession.start() returns right after the POST (it does not wait for the worker to join, and first-ever provisioning can exceed 30s), and max_duration > 1800 fails session creation outright.
Workaround we built (works, but everyone will have to reinvent it)
Using the hot-swap machinery from #5863 (AgentOutput.replace_audio_tail, shipped in 1.6.x):
Proactive rotation: from ~240s of session age, wait for session.current_speech to be idle, then start a second runway.AvatarSession under the same participant identity. The old worker keeps rendering through the new session's ~5s provisioning; when the new worker joins, the server drops the old one — visible gap ≈ track switchover, zero speech loss. aclose() the old session to stop billing.
Reactive fallback: if the kill lands mid-speech anyway (no idle boundary in minutes 4–5), respawn on participant_disconnected and prompt the LLM to continue from the cut-off, since the utterance remainder is unrecoverable.
Proposal
Any (or all) of:
auto_renew: bool (or renew_before: float) on runway.AvatarSession — the plugin rotates the underlying realtime session before the provider cap, ideally at a speech boundary, using the same identity-takeover + replace_audio_tail mechanics as fix(avatar): preserve audio wrappers across avatar hot-swaps #5863. The plugin already owns every primitive needed.
A typed event (e.g. avatar_session_expired) distinguishing provider-side session completion from network loss, so apps can implement renewal themselves without sid-tracking heuristics.
At minimum, document the 5-minute cap (and the maxDuration ≤ 1800 validation + "start() returns before the worker joins") on the runway plugin page — it currently reads as if sessions last as long as max_duration.
Happy to share more logs/timings or test a patch — we have a working environment that reproduces this on every session >5 min.
Environment
livekit-agents1.6.5,livekit-plugins-runway1.6.5 (Python 3.13, LiveKit Cloud)gwm1_avatarsrealtime sessions, custom Character, LiveKit agent owns STT/LLM/TTS (ElevenLabs)Problem
Runway enforces a hard 5-minute limit on realtime avatar sessions at runtime. Their Characters "Core Concepts" docs state "Sessions have a maximum duration of 5 minutes" — and it is enforced, even though
POST /v1/realtime_sessionshappily acceptsmaxDurationup to 1800 (that bound appears to be billing-only; values >1800 are rejected with400 "Too big: expected number to be <=1800").Measured timeline from a live session:
AvatarSession.start()→ video track subscribed +5.4s (nice warm start)runway-avatar-agentparticipant disconnects mid-utterance — Runway completed the session server-sideBecause the plugin routes agent audio into the avatar's
DataStreamAudioOutput, two things follow for anyone running conversations longer than 5 minutes:Neither the plugin docs nor the LiveKit avatar integration page mention the cap, so this surfaces as a mystery disconnect in production. Two other integration notes that cost us time:
AvatarSession.start()returns right after the POST (it does not wait for the worker to join, and first-ever provisioning can exceed 30s), andmax_duration > 1800fails session creation outright.Workaround we built (works, but everyone will have to reinvent it)
Using the hot-swap machinery from #5863 (
AgentOutput.replace_audio_tail, shipped in 1.6.x):session.current_speechto be idle, then start a secondrunway.AvatarSessionunder the same participant identity. The old worker keeps rendering through the new session's ~5s provisioning; when the new worker joins, the server drops the old one — visible gap ≈ track switchover, zero speech loss.aclose()the old session to stop billing.participant_disconnectedand prompt the LLM to continue from the cut-off, since the utterance remainder is unrecoverable.Proposal
Any (or all) of:
auto_renew: bool(orrenew_before: float) onrunway.AvatarSession— the plugin rotates the underlying realtime session before the provider cap, ideally at a speech boundary, using the same identity-takeover +replace_audio_tailmechanics as fix(avatar): preserve audio wrappers across avatar hot-swaps #5863. The plugin already owns every primitive needed.avatar_session_expired) distinguishing provider-side session completion from network loss, so apps can implement renewal themselves without sid-tracking heuristics.maxDuration ≤ 1800validation + "start() returns before the worker joins") on the runway plugin page — it currently reads as if sessions last as long asmax_duration.Happy to share more logs/timings or test a patch — we have a working environment that reproduces this on every session >5 min.