what are the steps to properly close a voice agent...
# ask-ai
p
what are the steps to properly close a voice agent conversation with gemini realtime plugin
t
Thanks for reaching out, adit-kulkarni. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’ll walk you through the proper steps to close a voice agent conversation when using the Gemini Realtime plugin. 1. Wait for any in-progress speech to finish ◦ Ensure the agent finishes playout before teardown. Use
ctx.wait_for_playout()
(Python) or equivalent to let current audio finish. 1. Optionally send a closing message ◦ Generate a final reply such as “Goodbye” with
session.generate_reply()
so the user hears a natural close. 1. Shut down the agent session gracefully ◦ Drain pending work with
session.shutdown(drain=True)
to allow queued speech to complete. To force-close immediately, use
session.aclose()
. 1. End the LiveKit room (terminate call for all participants) ◦ Call the LiveKit server API to delete the room (e.g.,
ctx.api.room.delete_room(api.DeleteRoomRequest(room=ctx.room.name))
). Ending only the agent session leaves the user in the room/silence, so delete the room to fully end the call. 1. Run post-shutdown cleanup tasks (optional) ◦ Add callbacks like
ctx.add_shutdown_callback()
to save logs, state, or perform any other cleanup after shutdown completes. If you want, tell me which SDK/language you’re using (Python, JS) and whether you prefer a graceful drain or immediate close—I can provide exact code snippets. Sources: Agent speech and audio | LiveKit docs | Agents telephony integration | LiveKit docs | SIP Lifecycle Management Agent | LiveKit docs | Job lifecycle | LiveKit docs
p
should i be creations new session/localmedia objects for every vonversation my user has or just have one and keep reusing it?
t
Thanks — quick answer: create a new session for each conversation. Why: • Each
AgentSession
manages a single, isolated conversation lifecycle (init, media I/O, activity tracking, cleanup). Reusing a session can cause state conflicts. • Local media is managed per session; you don’t need to persist
LocalMedia
yourself. Let the session create and dispose media resources so tracks and state stay clean. If you’d like, tell me which language/SDK you’re using (Python or JS) and I’ll share a short example for creating and tearing down sessions. Sources: Agent session | LiveKit docs | Client SDKs | livekit/livekit_composite | DeepWiki
p
let me rephrase: We're experiencing crashes when starting a second LiveKit conversation after ending the first one. Looking at the agent-starter-swift example app, I noticed a key architectural difference: Example app approach: // VoiceAgentApp.swift @main struct VoiceAgentApp: App { private let session = Session(...) // Created ONCE at app level var body: some Scene { WindowGroup { AppView() .environmentObject(session) .environmentObject(LocalMedia(session: session)) } } } The Session and LocalMedia are created once and reused - session.end() is called to disconnect, but the same objects are reused for the next session.start(). Our current approach: We create NEW Session and LocalMedia objects for each conversation (in a SwiftUI view or manager). When the conversation ends, these objects are destroyed. When starting a new conversation, we create fresh Session/LocalMedia objects. Question: Is the example app's pattern (creating Session/LocalMedia once at app-level and reusing them) the recommended approach for avoiding native resource conflicts? Should we avoid destroying and recreating Session/LocalMedia objects, and instead reuse a single persistent instance across multiple conversations?
t
Thanks — I’m responding to your question about whether to reuse Session/LocalMedia or create new ones per conversation. Short answer: Reuse a single app-level
Session
and
LocalMedia
instance across conversations (the example app pattern). This is the recommended approach. Why: • `Session`/`LocalMedia` own native WebRTC and AVFoundation resources (audio units, capture devices, sockets). Recreating them frequently causes race conditions, resource contention, AVAudioSession interruptions, and crashes. • Calling
session.end()
cleanly disconnects and releases session resources while keeping the object usable for a new
session.start()
with a fresh room/token. • Letting the session manage media lifecycle ensures clean teardown and prevents stale native state. Recommended actions: 1. Create
Session
and
LocalMedia
once at app startup (e.g., as EnvironmentObjects). 2. On conversation end, call
session.end()
(drain/cleanup) — do not destroy the objects. 3. For a new conversation, call
session.start()
with the new room URL/token. If you’d like, share crash logs or the sequence you use to end/start sessions (calls and timing). I can point out likely race points and give exact Swift code snippets to switch to the persistent pattern. Sources: client-sdk-swift | livekit/livekit_composite | DeepWiki