feat(voice): support runtime model updates#2052
Open
rosetta-livekit-bot[bot] wants to merge 8 commits into
Open
feat(voice): support runtime model updates#2052rosetta-livekit-bot[bot] wants to merge 8 commits into
rosetta-livekit-bot[bot] wants to merge 8 commits into
Conversation
🦋 Changeset detectedLatest commit: d1d06d4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 37 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Keep live model replacement coherent with activity teardown and correctly propagate user VAD ownership after replacing the session default. Co-authored-by: Cursor <cursoragent@cursor.com>
Lock in cleanup, fallback, listener, keyterm, and VAD task ownership semantics across concurrent runtime updates. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Prevent queued updates from reattaching resources to stale handoff activities while preserving model changes for a later resume. Co-authored-by: Cursor <cursoragent@cursor.com>
Preflight model warmup and roll back recognition, keyterm, listener, and model ownership when operational swaps fail. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep synchronous preflight rejection outside operational rollback so unchanged recognition pipelines and turn context remain intact. Co-authored-by: Cursor <cursoragent@cursor.com>
Normalize explicit-null disable state at public getters while resolving activity fallbacks from raw internal fields. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ports livekit/agents#6440 runtime model swapping to Agents JS.
Adds awaitable
Agent.updateOptions()to swap STT, VAD, LLM, and TTS while inactive or while the live pipeline is active.nullexplicitly disables an agent-level model and overrides session fallback, matching PythonNonesemantics.The JS adaptation preserves Python's synchronous atomicity across asynchronous pipeline teardown:
nulldisable fromundefinedinheritance.AgentUpdateOptionsthrough the publicvoiceAPI.Source diff coverage
livekit-agents/livekit/agents/voice/agent.pyagents/src/voice/agent.tswith JS camelCase, string resolution, running/inactive behavior, and internalnulldisable semantics without widening existing getter contracts.livekit-agents/livekit/agents/voice/agent_activity.pylivekit-agents/livekit/agents/voice/audio_recognition.pylivekit-agents/livekit/agents/voice/keyterm_detection.pyswapStt()with existing-keyterm propagation and rollback coverage.tests/test_agent_update_options.pyTarget-only adaptation:
agents/src/voice/agent_v2.tsnormalizes nullable agent model fields toundefinedin existing optional hook contexts.Validation
pnpm --filter @livekit/agents typecheck.pnpm --filter @livekit/agents build.pnpm buildpassed.export * as ___syntax inagents/dist/index.d.ts.Changeset
Added a patch changeset for
@livekit/agents.Cue voice E2E
Verified exact commit
8b2ea3547edf7f0a20ed00daf3aa6b6f8867e705in fresh Cue voice mode.sid_3f553776f1ef.nova-3STT and Cartesiasonic-3TTS; initial OpenAIgpt-4.1-mini, replacementgpt-4.1-nano.swap_runtime_llmtool awaitedagent.updateOptions({ llm: replacement }).chat()event → successful tool output → replacement model actualchat()event → speaking → assistant commit → listening.events.jsonl, command result JSON, command WAV, and session WAV. Both channels in both WAVs are non-zero.Ported from livekit/agents#6440
Original PR description
Agent.update_models(*, stt, vad, llm, tts)swaps a model in place. Only the models passed are changed; strings resolve to inference models like the constructor, andNonedisables a model (overriding the session), matchingAgent(stt=None).When the agent isn't running it replaces the stored model, applied on the next start. When running, it applies to the live pipeline: the STT and VAD streams are rewired, the LLM and TTS take effect on the next generation and synthesis respectively, and each model's
metrics_collected/errorlisteners follow the new instance. The call is synchronous and atomic.The Agent is the source of truth — the activity resolves
agent.<model> if given else session.<model>live — soupdate_modelsjust writes to the agent. This is distinct fromAgentSession.update_agent(full handoff, new instance) and from a model's ownupdate_options(same instance, provider options).Realtime models
A
RealtimeModelowns a live session created when the agent starts, so it can't be swapped in place. While running, passing aRealtimeModelasllm(or swapping away from one) raisesRuntimeErrorpointing toAgentSession.update_agent. Validation happens before any mutation, so the call stays all-or-nothing.