limited-pillow-7054
12/21/2025, 8:59 AMtall-airline-16756
12/21/2025, 8:59 AMtall-airline-16756
12/21/2025, 8:59 AMlimited-pillow-7054
12/21/2025, 9:00 AMtall-airline-16756
12/21/2025, 9:00 AMinstructions and max_tokens are not accepted as constructor kwargs for RealtimeModel.
• Use model.update_options(...) to set runtime options (instructions, max tokens, turn detection, STT/TTS, etc.).
• Use AgentSession(llm=model) and the provided agent helpers (e.g., VoiceAssistantAgent) unless you need a custom agent.
Question 1 — How to pass system prompt/instructions to RealtimeModel?
• You cannot pass instructions in the RealtimeModel(...) constructor.
• Create the model, then call model.update_options(instructions="..."). That is the supported way to set a system prompt.
Question 2 — How to set max_response_output_tokens?
• max_response_output_tokens is not a valid parameter name.
• Use max_tokens and set it via model.update_options(max_tokens=512).
• Yes — calling update_options() immediately after creation is the correct pattern for these settings.
Question 3 — Correct AgentSession + RealtimeModel pattern?
• Pattern:
a. Create RealtimeModel(...) (minimal constructor args).
b. Call model.update_options(...) for instructions, max_tokens, input_audio_transcription, turn_detection, etc.
c. Create session = AgentSession(llm=model).
d. Start with await session.start(room=ctx.room, agent=agent).
• Where should the system prompt live? In the RealtimeModel via update_options(instructions=...). You can keep a copy in your Agent for bookkeeping, but the model uses the instructions for generation.
• AgentSession(llm=model) is correct.
Question 4 — RealtimeAgent class overrides — are these correct?
• Don’t pass instructions through super().__init__ for LiveKit’s Realtime flow. Set instructions on the RealtimeModel instead.
• Lifecycle hooks differ by SDK; common useful overrides:
◦ a method called when the agent is ready / session starts (e.g., on_agent_ready or on_room_connected depending on base class)
◦ handler for end of user utterance / turn (e.g., on_user_utterance_end or on_user_turn_completed if present)
◦ cleanup on exit
• Your on_enter, on_exit, on_user_turn_completed may be fine if those match the base Agent API you use — verify names against your installed livekit-agents package. If unsure, prefer the built-in VoiceAssistantAgent unless you need custom behavior.
Question 5 — Voice test room dispatch pattern
• Use your dispatch to create a room and include metadata; that metadata is available to the agent via ctx.room.metadata in the entrypoint.
• The decorator @FlashCall Server.rtc_session looks like a custom/internal decorator — the standard pattern is an entrypoint function the worker runs (e.g., CLI worker entrypoint). If your environment expects @rtc_session, keep using what your infra requires. The important part: metadata passed in create_dispatch ends up in ctx.room.metadata for the agent to read.
Question 6 — Minimal working example (concise, corrected)
# minimal_realtime_agent.py
from livekit.agents import AgentSession
from livekit.plugins.openai.realtime import RealtimeModel
from livekit.agents.helpers import VoiceAssistantAgent # or your Agent subclass
async def entrypoint(ctx):
# 1) Create model with basic constructor args
model = RealtimeModel(
model="gpt-4o-realtime-preview",
voice="ash",
modalities=["audio", "text"],
temperature=0.7,
)
# 2) Set runtime options (instructions, token limits, STT/TTS, turn detection)
model.update_options(
instructions="You are a helpful assistant that speaks concisely.",
max_tokens=512,
input_audio_transcription={"model": "whisper-1"},
input_audio_noise_reduction={"type": "passive"},
)
# 3) Create session using the RealtimeModel as LLM
session = AgentSession(llm=model)
# 4) Use provided agent helper or your custom agent
agent = VoiceAssistantAgent(session) # or your RealtimeAgent(session, ...)
# 5) Start session for the room (ctx.room is populated by dispatch)
await session.start(room=ctx.room, agent=agent)
Additional tips
• Keep a copy of system prompt in your agent if you want to log or update it dynamically, but set it on the model for behavior.
• For custom lifecycle method names, check your installed livekit-agents version to confirm exact hook names — common names are similar to on_agent_ready, on_room_connected, on_user_utterance_end, but your package may expose different method names.
• Metadata from dispatch is accessible via ctx.room.metadata.
If you want, tell me:
• The exact method names available on your Agent base class (I can look them up if you paste the class or version), and I’ll confirm which lifecycle hooks to override; and
• Whether you want the minimal example adapted to your existing RealtimeAgent subclass (I can show the precise changes). Sources: OpenAI Realtime API plugin guide | LiveKit docs | Realtime model plugins | LiveKit Docs | examples/voice_agents | livekit/livekit_composite | DeepWiki | OpenAI and LiveKit partner to turn Advanced Voice into an API | Agents (Node.js) | livekit/livekit_composite | DeepWikilimited-pillow-7054
12/21/2025, 9:12 AMtall-airline-16756
12/21/2025, 9:12 AMinstructions) — AgentSession will load those into the session at start; you only need to call a session/agent update API if you change instructions mid-session.
• Use model.update_options() for runtime options. Most option names you listed are valid; the one name that differs across examples is subtle (see below).
• temperature is deprecated/unused in RealtimeModel v1.
• Your overall implementation is valid with the versions you listed.
Details (by question)
Question 1 — RealtimeModel constructor
• Yes: model, voice, modalities, input_audio_transcription=AudioTranscription(...), turn_detection=TurnDetection(...), and input_audio_noise_reduction set to None or strings like "near_field" are correct.
• AudioTranscription(model="gpt-4o-transcribe") is the correct shape and model name.
• Using TurnDetection from openai.types.beta.realtime.session is acceptable (examples use the beta import).
• input_audio_noise_reduction can be None or a named value (string) per examples.
Question 2 — Where instructions go
• Your approach is correct: set instructions on your Agent (super().__init__(instructions=system_prompt)).
• When you call await session.start(agent=agent, room=ctx.room), the session loads the agent’s instructions into the realtime LLM context automatically.
• Only call a special session.update_instructions(...) if you need to change the instructions dynamically after session start.
Question 3 — update_options() parameters
• The parameter name you used in one place differs across examples:
◦ max_response_output_tokens is shown in some LiveKit examples and test code and is valid for limiting response length.
◦ You may also see max_tokens in other contexts; for the Realtime plugin the documented example uses max_response_output_tokens.
• Valid update_options fields include (common ones): voice, turn_detection, tool_choice, input_audio_transcription, input_audio_noise_reduction, max_response_output_tokens, speed, tracing. Your list is correct; use max_response_output_tokens for RealtimeModel per examples.
Question 4 — temperature
• temperature is deprecated/unused in RealtimeModel v1. You cannot rely on it to control response randomness in the current Realtime flow.
Question 5 — Minimal working example
from livekit.agents import Agent, AgentSession, JobContext
from livekit.plugins.openai import realtime
from openai.types.beta.realtime.session import TurnDetection
from openai.types.realtime import AudioTranscription
class RealtimeAgent(Agent):
def __init__(self, system_prompt: str):
super().__init__(instructions=system_prompt)
async def on_enter(self) -> None:
# example hook — verify exact hook name in your installed package
self.session.generate_reply()
def create_realtime_model(max_tokens: int = 512) -> realtime.RealtimeModel:
turn_detection = TurnDetection(
type="semantic_vad",
eagerness="low",
create_response=True,
interrupt_response=True,
)
model = realtime.RealtimeModel(
model="gpt-4o-realtime-preview",
voice="ash",
modalities=["audio", "text"],
input_audio_transcription=AudioTranscription(model="gpt-4o-transcribe"),
input_audio_noise_reduction=None,
turn_detection=turn_detection,
)
# runtime options (instructions set on Agent; runtime limits here)
model.update_options(max_response_output_tokens=max_tokens)
return model
async def realtime_entrypoint(ctx: JobContext):
await ctx.connect(auto_subscribe=True)
model = create_realtime_model(max_tokens=512)
agent = RealtimeAgent(system_prompt="You are a helpful assistant.")
session = AgentSession(llm=model)
await session.start(agent=agent, room=ctx.room)
Question 6 — versions & types
• Your versions (livekit-agents >=1.0.0 and livekit-plugins-openai >=1.3.8) are compatible with the Realtime API patterns used in examples.
• Use openai.types.beta.realtime.session for TurnDetection as in the examples. openai.types.realtime can contain other types; follow the example imports for the pieces you need.
• Breaking-note: temperature is effectively not used in v1 Realtime; rely on the provided runtime options instead.
Minor suggestions / gotchas
• Verify lifecycle hook names (on_enter, on_exit, etc.) against the exact installed Agent base class — method names can vary; if in doubt use the built-in VoiceAssistantAgent or inspect your package.
• Keep a copy of system prompt on both Agent (for bookkeeping/logging) and rely on the Agent→Session startup sync for injection into the LLM.
• Use model.update_options(...) for any runtime reconfiguration (including dynamic changes), and only call session/agent update calls if you need to change behavior mid-session.
If you’d like, I can:
• Check your exact installed package’s Agent base class methods (paste the class or version) and confirm the exact hook names to implement.
• Provide a version-adapted snippet replacing on_enter with the correct hook name for your install. Sources: OpenAI Realtime API plugin guide | LiveKit docs | Agents and handoffs | LiveKit docs | Agents (Python) | livekit/livekit_composite | DeepWiki | Using the Testing Framework with Realtime Models | examples/voice_agents | livekit/livekit_composite | DeepWikilimited-pillow-7054
12/21/2025, 9:19 AMtall-airline-16756
12/21/2025, 9:20 AMagent.instructions and the RealtimeModel options immediately before session.start().
• Enable plugin/SDK debug logging (environment variable or Python logging DEBUG) to capture WebSocket frames. Example: set LK_OPENAI_REALTIME_DEBUG=true or set logging.basicConfig(level=logging.DEBUG) for the process.
• Add event listeners on session.llm for: input_speech_started, input_speech_stopped, generation_created, generation_updated (these show input and generation lifecycle).
• Inspect the first generation content — if instructions had applied the greeting style/content, you’ll see expected output. If not, the WS frames will show the session payload that went to OpenAI.
Minimal checklist to run now
1. Add logs:
◦ logger.info("Agent.instructions=%s", agent.instructions)
◦ logger.info("RealtimeModel options=%s", model._model_opts or model.inspect_options())
1. Wire event listeners:
◦ session.llm.on("input_speech_started", lambda e: logger.info("speech started"))
◦ session.llm.on("input_speech_stopped", lambda e: logger.info("speech stopped"))
◦ session.llm.on("generation_created", lambda e: logger.info("generation started"))
1. Enable DEBUG logging for the process / plugin.
2. Confirm client audio is actually published to the room (client side test).
3. If agent still replies in Spanish, paste the debug logs (first session creation frame + first generation) and I’ll help interpret.
Minimal working example (concise)
import logging
from livekit.agents import Agent, AgentSession, JobContext, cli
from livekit.plugins.openai import realtime
from openai.types.beta.realtime.session import TurnDetection
from openai.types.realtime import AudioTranscription
logging.basicConfig(level=<http://logging.INFO|logging.INFO>)
logger = logging.getLogger("realtime-agent")
class RealtimeAgent(Agent):
def __init__(self, system_prompt: str):
super().__init__(instructions=system_prompt)
async def on_enter(self):
<http://logger.info|logger.info>("on_enter: generating greeting")
await self.session.generate_reply()
async def entrypoint(ctx: JobContext):
# create model with semantic VAD
td = TurnDetection(type="semantic_vad", eagerness="low", create_response=True, interrupt_response=True)
model = realtime.RealtimeModel(
model="gpt-4o-realtime-preview",
voice="ash",
modalities=["audio", "text"],
input_audio_transcription=AudioTranscription(model="gpt-4o-transcribe"),
turn_detection=td,
)
model.update_options(max_response_output_tokens=512)
session = AgentSession(llm=model)
# debug listeners
session.llm.on("input_speech_started", lambda e: <http://logger.info|logger.info>("event: input_speech_started"))
session.llm.on("input_speech_stopped", lambda e: <http://logger.info|logger.info>("event: input_speech_stopped"))
session.llm.on("generation_created", lambda e: <http://logger.info|logger.info>("event: generation_created"))
agent = RealtimeAgent(system_prompt="You are a helpful assistant. Always respond in English.")
<http://logger.info|logger.info>("Agent.instructions=%s", agent.instructions)
await session.start(agent=agent, room=ctx.room)
If this still yields a Spanish greeting:
• Enable debug logging and share the session creation frame and first generation logs (I can help read them).
• Confirm the client publishes audio (no audio → no input events).
• If you want, I can point to exact log lines to look for in the WS trace that show initialMessages/instructions.
Would you like help reading the debug WebSocket frames if you paste them here?
Sources: examples/voice_agents | livekit/livekit_composite | DeepWiki | Ultravox plugin guide | LiveKit docs | Pipeline nodes and hooks | LiveKit docs | OpenAI Realtime API plugin guide | LiveKit docs | Building an Automated IVR Menu Caller | LiveKit docslimited-pillow-7054
12/21/2025, 9:32 AMtall-airline-16756
12/21/2025, 9:32 AM# pseudo-code (concise)
await ctx.connect(auto_subscribe=True)
participant = await ctx.wait_for_participant()
# optional: wait for track publication/subscription events here
# create model
model = realtime.RealtimeModel(
model="gpt-4o-realtime-preview",
voice="ash",
modalities=["audio","text"],
input_audio_transcription=AudioTranscription(model="gpt-4o-transcribe"),
turn_detection=TurnDetection(type="semantic_vad", create_response=True, interrupt_response=True),
)
model.update_options(max_response_output_tokens=512)
session = AgentSession(llm=model)
# room track listeners (verify audio)
@ctx.room.on("track_published")
def on_track_published(tp, participant):
<http://logger.info|logger.info>(f"track_published: {tp.kind} {tp.track_name}")
@ctx.room.on("track_subscribed")
def on_track_subscribed(track, publication, participant):
<http://logger.info|logger.info>("track_subscribed: kind=%s name=%s", publication.kind, publication.track_name)
# Realtime event listeners (if exposed)
session.llm.on("input_speech_started", lambda e: <http://logger.info|logger.info>("input_speech_started"))
session.llm.on("input_speech_stopped", lambda e: <http://logger.info|logger.info>("input_speech_stopped"))
session.llm.on("generation_created", lambda e: <http://logger.info|logger.info>("generation_created"))
agent = RealtimeAgent(system_prompt="You are a helpful assistant. Respond in English.")
<http://logger.info|logger.info>("Agent.instructions=%s", agent.instructions)
await session.start(room=ctx.room, agent=agent)
Debugging tips (what to look for)
• Track events: you should see track_published and track_subscribed entries when the user joins/publishes.
• WS/session creation frame: contains initialMessages/system prompt — confirm it includes your instructions.
• input_speech_started/stopped events after user speaks; generation_created when model starts replying.
• If track_subscribed never appears, audio never reached the agent process.
Common fixes that solve input_audio_tokens=0
• Start session only after participant and track exist.
• Ensure the agent process token has audio read permissions.
• Ensure client publishes audio (e.g., set mic track enabled).
• Use the track_subscribed listener to assert the agent actually receives the audio track.
If you want I can:
• Review logs (track_published/track_subscribed, session creation WS frame, and any generation logs) and point to the exact failure.
• Provide a node or fuller Python example matched to your environment.
Which would you like next — paste the track_subscribed logs and the session creation WS frame, or I can give a slightly expanded runnable example you can drop in and test?
Sources: Voice AI quickstart | LiveKit docs | OpenAI Realtime API plugin guide | LiveKit docs | Agents (Node.js) | livekit/livekit_composite | DeepWiki | OpenAI and LiveKit | LiveKit docs | examples/voice_agents | livekit/livekit_composite | DeepWikilimited-pillow-7054
12/21/2025, 1:00 PMtall-airline-16756
12/21/2025, 1:01 PM