creamy-tiger-14805
12/16/2025, 11:15 AMtall-airline-16756
12/16/2025, 11:16 AMtall-airline-16756
12/16/2025, 11:16 AMasync def on_user_turn_completed(self, turn_ctx, new_message):
if new_message.participant_kind == rtc.ParticipantKind.PARTICIPANT_KIND_AGENT:
raise StopResponse()
1. Restrict which participant kinds the agent listens to
• Start sessions so agents only accept STANDARD (and SIP if needed) participants:
await session.start(
room_input_options=RoomInputOptions(
participant_kinds=[rtc.ParticipantKind.PARTICIPANT_KIND_STANDARD]
)
)
1. Use tools for internal logic instead of spoken turns
• Run internal checks or follow-ups as silent function tools so they don’t generate speech:
@function_tool()
async def internal_check(self):
result = await self.run_internal_logic()
return result, "Internal result"
1. Only call speech APIs when user input requires it
• Avoid generating replies from internal events; use session.say() or generate_reply() only for deliberate, user-facing responses. Optionally disable interruptions:
session.say("Hello", allow_interruptions=False)
1. Validate message origin and identity
• Check `participant_identity`/metadata on incoming messages; reject or ignore messages that originate from the bot itself.
If you want, tell me which SDK/language you’re using (Python or Node), and I’ll give the exact code snippets to drop into your agent.
Sources: Pipeline nodes and hooks | LiveKit docs | Prompting guide | LiveKit docs | How to test your agent using another agent | Agents and handoffs | LiveKit docs | Agent speech and audio | LiveKit docs