gentle-needle-76462
03/17/2026, 2:08 PMtall-airline-16756
03/17/2026, 2:08 PMtall-airline-16756
03/17/2026, 2:09 PM_process_responses.
What this means
• The Nova Sonic realtime model rejected the input it received when your transfer attempted to start the new agent’s reply. The model returned a ValidationException: “Invalid input request,” so the request payload sent to Bedrock/Realtime was malformed or used unsupported fields.
What you can check and try next
• Ensure you trigger the new agent’s reply with text input (not raw agent objects).
◦ Use session.generate_reply() with instructions or user_input (string) to start the new agent’s intro instead of passing an agent instance or non-string payload.
◦ Example pattern:
await self.session.generate_reply(
instructions="Transfer to support agent and greet the user"
)
• Confirm the model instance is Nova Sonic 2.0 and configured for text input:
◦ Use with_nova_sonic_2(...) and set modalities="mixed" so text input is accepted.
session = AgentSession(
llm=aws.realtime.RealtimeModel.with_nova_sonic_2(
voice="tiffany",
turn_detection="MEDIUM",
modalities="mixed"
),
)
• Verify the agent’s on_enter() (or equivalent entry hook) calls generate_reply() to produce the greeting. The new agent must actively call generate_reply() to create the model request.
• Validate the exact payload being sent to the Bedrock/Realtime API:
◦ Look for non-string fields, nested objects, or unexpected keys in the request body.
◦ Ensure fields expected by generate_reply() are present and are strings (e.g., instructions, user_input).
• Check AWS credentials/region:
◦ Make sure AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION are set (Bedrock requires a region).
• Confirm you aren’t using Nova Sonic 1.0 (audio-only). Nova Sonic 1.x does not accept text input in the same way; Nova Sonic 2.0 supports text via generate_reply().
If you’re still seeing the error, please share one of the following (so I can pinpoint the malformed field):
• The snippet of code you use to perform the agent transfer (the function that returns the new Agent and the new agent’s on_enter()), with any secrets redacted.
• The exact generate_reply() call arguments you pass when the transfer happens.
• The raw request payload (or sanitized copy) that ends up being sent to the AWS realtime/BEDROCK API.
I’ll look at that and give concrete fixes — for example, identifying which key in the payload is invalid and how to reformat it so Nova Sonic accepts it.
Sources: Amazon Nova Sonic integration guide | LiveKit Documentation | TTS Comparison | LiveKit Documentation | AWS AI and LiveKit | LiveKit Documentation, with interactive elementsgentle-needle-76462
03/17/2026, 2:11 PMtall-airline-16756
03/17/2026, 2:12 PMawait session.start(...) followed by `await ctx.connect()`; awaiting ctx.connect() ensures the session/room connection and startup are complete before you proceed.
• Listen for the agent_state_changed event and wait until the agent enters the listening state. When the agent emits listening, initialization is finished and it’s ready to process input.
Example sequence (conceptual):
1. await session.start(room=ctx.room, agent=YourAgent())
2. await ctx.connect() # wait for session/room connection and initialization
3. Optionally, subscribe to agent_state_changed and proceed when state == "listening"
If you’d like, share which SDK/language you’re using (Python, JS, etc.) and I can show a small code example that awaits ctx.connect() and/or waits for the agent_state_changed event in that environment.
Sources: Agent session | LiveKit Documentation | Gemini Realtime Agent with Live Vision | LiveKit Documentation, with interactive elementsgentle-needle-76462
03/17/2026, 2:19 PMtall-airline-16756
03/17/2026, 2:19 PMctx.connect()) after session.start() — ensures the session/room setup is established.
• Waiting for the agent to emit the agent_state_changed event and reach the listening state — indicates the agent is fully ready.
Example (conceptual Python; adapt names to your codebase):
import asyncio
# Example callback that listens for agent state changes.
# Adjust event names to match your SDK if they differ.
async def wait_for_listening_state(ctx, timeout=10):
"""
Wait until agent_state_changed -> 'listening' or timeout.
Returns True if reached listening, False if timed out.
"""
fut = asyncio.get_event_loop().create_future()
def on_state_change(new_state):
# If event delivers richer payload, inspect it and check for 'listening'
if new_state == "listening":
if not fut.done():
fut.set_result(True)
# subscribe to the event; replace with your actual subscription API
unsubscribe = ctx.on("agent_state_changed", on_state_change)
try:
await asyncio.wait_for(fut, timeout=timeout)
return True
except asyncio.TimeoutError:
return False
finally:
# clean up listener
unsubscribe()
# Usage when starting a session and performing a transfer
async def start_and_wait_for_agent(session, ctx, agent_instance):
# Start the session (creates AgentSession, etc.)
await session.start(room=ctx.room, agent=agent_instance)
# Ensure connection and initialization are established
await ctx.connect()
# Wait until agent transitions to 'listening' (or timeout)
ready = await wait_for_listening_state(ctx, timeout=15)
if not ready:
raise RuntimeError("Agent did not enter listening state within timeout")
# At this point the agent is initialized and ready
# Safe to perform actions like transferring flows or calling generate_reply()
Practical notes and tips
• Use both steps: await ctx.connect() ensures the session/room connection is established; the agent_state_changed -> listening is the signal your agent is ready to process input.
• Pick a reasonable timeout (e.g., 10–30s) and surface helpful errors if initialization fails.
• If your SDK’s event payload provides an object (not a plain string), inspect the payload in on_state_change() and check the appropriate field for "listening".
• If you need to wait for the agent to finish its initial greeting (e.g., the initial generate_reply() to complete), you can also:
◦ Have the agent call generate_reply() in on_enter() and emit/resolve a custom event when generate_reply() returns, then await that event from the caller.
◦ Or listen for a model output/completion event if your SDK exposes one.
If you’d like, paste the exact APIs your ctx object exposes (how you subscribe to events and what the agent_state_changed payload looks like) and I’ll adapt the snippet to your concrete SDK methods and event signatures.
, with interactive elements