busy-spoon-35253
03/13/2026, 10:40 AMtall-airline-16756
03/13/2026, 10:40 AMtall-airline-16756
03/13/2026, 10:41 AMbusy-spoon-35253
03/13/2026, 10:42 AMtall-airline-16756
03/13/2026, 10:42 AMhttps://cdn.example.com/slide1.png▾
session = AgentSession(
llm=openai.realtime.RealtimeModel(
voice="alloy",
modalities=["text","audio"],
turn_detection=TurnDetection(type="semantic_vad", eagerness="medium"),
),
vad=some_vad_if_needed,
)
Python: RAG lookup in on_user_turn_completed (conceptual)
async def on_user_turn_completed(self, turn_ctx, new_message):
user_text = new_message.text_content()
retrieved = await my_llamaindex_retriever.search(user_text, top_k=3)
turn_ctx.add_message(role="system", content=f"RAG_CONTEXT:{retrieved}")
# optionally instruct client to show slide
if should_show_slide(user_text):
await turn_ctx.session.send_data({"type":"show_slide", "url": slide_url, "slide": slide_idx})
# generate reply (agent will synthesize audio via RealtimeModel)
await turn_ctx.generate_reply(instructions="Answer and then continue presentation")
React frontend: listen for data messages (conceptual)
room.on('dataReceived', (payload, participant) => {
const msg = JSON.parse(new TextDecoder().decode(payload));
switch(msg.type) {
case 'show_slide':
setSlideUrl(msg.url);
setSlideIndex(msg.slide);
break;
case 'show_pdf':
setPdfUrl(msg.url);
setPdfPage(msg.page);
break;
case 'highlight':
highlightOnCanvas(msg.coords);
break;
}
});
Practical tips and considerations
• Keep the slide assets accessible via HTTPS (CDN) and small enough for quick loading. Preload next slide in the frontend when possible.
• Use shorter retrieved contexts for RAG to keep latency low; fetch top-3 documents and summarize before injecting into prompts.
• Test interruption flows thoroughly: mid-speech interruptions, quick follow-ups, and long questions during a slide walk-through.
• Maintain a simple presentation state machine in the backend (current_slide, paused_for_question, last_user_turn_id) to make resumption deterministic.
Next actions I can provide for you (pick one or more)
• A starter Python project scaffold (LiveKit agent + OpenAI Realtime config + LlamaIndex RAG wiring) tailored to LiveKit Cloud.
• A React example that subscribes to data messages and renders images/PDFs with page sync and highlight support.
• A combined minimal demo repo that ties backend + frontend together (code snippets for auth tokens, send_data usage, and a basic state machine).
• Detailed code for interruption handling and resume logic showing Realtime turn switching and session state usage.
Which of these would you like next? I can begin by generating the Python scaffold (agent + RAG hook) plus the React data listener and slide viewer if you want a full starter demo.busy-spoon-35253
03/13/2026, 10:43 AMtall-airline-16756
03/13/2026, 10:44 AMon_user_turn_completed intended for retrieval-augmented generation. Use this to run your LlamaIndex (or other retriever) lookups after each user turn and inject retrieved context into the assistant response.
• Use for: Placing RAG lookups at the right point in the conversation and injecting retrieved text into replies.
• Link: External data and RAG (Agents logic)
https://docs.livekit.io/agents/logic/external-data/
4) Examples for structured, stateful flows (presentation sequencing)
• What they show: examples/survey and examples/bank-ivr illustrate stateful, step-by-step conversational flows and how to progress through steps/tasks deterministically.
• Use for: Modeling slide sequencing, pause/resume logic, and deterministic state machines for your presentation flow.
• Link: Examples overview (deepwiki)
https://deepwiki.com/livekit/livekit_composite/1.5-examples
5) React starter + voice UI examples
• What they show: Starter React agent frontends (e.g., agent-starter-react, agent widgets) illustrating how to connect to LiveKit rooms, publish audio, receive audio, show transcriptions, and listen for data messages.
• Use for: Implementing the slide/PDF viewer that listens to data messages and updates view/page/highlights.
• Link: Examples and starter templates (examples list)
https://deepwiki.com/livekit/livekit_composite/1.5-examples
6) Kitt / LemonSlice (additional patterns)
• What they show: Voice-driven meeting assistants and avatar-driven agents that sync visuals/avatars with agent states. Useful patterns for state-to-visual mapping.
• Use for: Inspiration for styling, state mapping, and frontend asset switching.
• Links:
◦ Meet Kitt (LiveKit blog) — voice agents in meetings
https://livekit.com/blog/meet-kitt
• LemonSlice avatar example — avatar + visuals tied to state
https://livekit.com/blog/build-salary-negotiation-coach-lemonslice-avatar
How to combine these into your slide-presenter agent (high level)
• Backend (Python):
◦ Use the RealtimeModel for audio+text and set turn_detection to semantic_vad for interruption handling.
◦ Implement on_user_turn_completed to run RAG (LlamaIndex or your retriever), decide whether to show a slide, and inject retrieved context into the assistant reply.
◦ Use session.send_data or RPC to push JSON commands (show_slide, show_pdf, highlight, resume_presentation) to the frontend.
◦ Maintain a simple presentation state machine: current_slide, paused_for_question, last_user_turn_id.
• Frontend (React):
◦ Connect via LiveKit JS SDK and listen for data messages (room.on('dataReceived', ...)) to receive show/resume/highlight commands.
◦ Render images or PDF pages (pdf.js or <embed>), preload the next slide, and support highlight overlays.
◦ Update UI state (current slide, agent speaking/paused) based on messages from the backend.
• Test interruptions:
◦ Verify that mid-speech interruptions are detected, the backend switches turns, performs RAG, and either answers then resumes or directly resumes presentation flow.
If you’d like, I can do one of these next:
• Provide a focused starter repo scaffold (Python agent + RAG hook + minimal React viewer) that ties the Anam-style RPC pattern to slide commands.
• Produce a short walkthrough showing the exact backend send_data payloads and the React handler code to render images/PDFs and resume the flow.
• Share a compact checklist and minimal code snippets to wire RealtimeModel + on_user_turn_completed + LlamaIndex retrieval.
Which of those would be most helpful to you now?
Sources: Build a healthcare intake assistant with an Anam avatar | LiveKit | OpenAI Realtime API plugin guide | LiveKit Documentation | Pipeline nodes and hooks | LiveKit Documentation | Examples | livekit/livekit_composite | DeepWiki | Live conversations with AI using ChatGPT and WebRTC | LiveKit