Manage agent sessions
A session is one conversation with an agent. init() returns a VoiceAgentSession: you subscribe to its events, mute or unmute the microphone, wait for it to end, and close it. This page is for developers taking an agent past the first demo. It assumes you have an agent running, see the quickstart. The session works the same way in Python, in Node.js, and in the browser, where initSession() returns it.
Lifecycle
A session connects, exchanges audio and events while the conversation runs, then ends. Mute the microphone with set_input_enabled(False), wait for the end with wait(), and always call close() when you're done.
await session.set_input_enabled(False) # mute
await session.set_input_enabled(True) # unmute
await session.wait() # blocks until disconnected
await session.close() # close the session, should always be calledinit() creates the session with POST /v1/audio/sessions, and close() removes it with DELETE /v1/audio/sessions/{id}. To call these endpoints yourself, use client.audio.sessions.create(...) and client.audio.sessions.close(session_id).
Events
Register a handler with session.on(event, handler).
| Event | Payload | Your app should |
|---|---|---|
connected | session_id | Mark the session as ready. |
disconnected | session_id, reason | Stop audio and clean up. |
transcript | id, role, content, final | Show partial transcripts live (final is false), and keep the final ones. |
audio | bytes | Play the agent's audio yourself, if you handle audio manually. See Custom audio. |
audio_track | track, source | In the browser, attach the media track. |
agent_state_changed | state (listening, thinking, speaking, and more) | Update the interface. |
tool_call_started | id, name | Show that the agent is working. The arguments aren't known yet. |
tool_call_ended | id, name, arguments, result | Show the result. |
unhandled_tool | name, arguments | Log it: the agent called a client tool that has no handler. |
error | message, fatal, code, source | Report it. If fatal is true, the session is closing, see Errors and cleanup. |
disconnected has no reason after a normal close. Otherwise, reason is user_interrupt, start_failed, audio_input_error, audio_output_error, or error.
from mistralai.extra.voice_agents import (
VoiceAgentErrorEvent,
VoiceAgentStateChangedEvent,
VoiceAgentToolCallEndedEvent,
VoiceAgentToolCallStartedEvent,
VoiceAgentTranscriptEvent,
)
def on_transcript(event: VoiceAgentTranscriptEvent) -> None:
print(f"{event.role}: {event.content}")
def on_tool_call_started(event: VoiceAgentToolCallStartedEvent) -> None:
print(f"tool call started: {event.name}")
def on_tool_call_ended(event: VoiceAgentToolCallEndedEvent) -> None:
print(f"tool call ended: {event.name} -> {event.result!r}")
def on_agent_state_changed(event: VoiceAgentStateChangedEvent) -> None:
print(f"state: {event.state}")
def on_error(event: VoiceAgentErrorEvent) -> None:
print(f"error (fatal={event.fatal}): {event.message}")
session.on("transcript", on_transcript)
session.on("tool_call_started", on_tool_call_started)
session.on("tool_call_ended", on_tool_call_ended)
session.on("agent_state_changed", on_agent_state_changed)
session.on("error", on_error)session.on() returns a function that unsubscribes the handler. You can also call session.off() with the original handler:
unsubscribe = session.on("transcript", on_transcript)
unsubscribe() # stop receiving
# or, equivalently:
session.off("transcript", on_transcript)Errors and cleanup
Every error carries fatal:
- Recoverable errors (
fatalis false) leave the session open. Log them and continue. - Fatal errors close the session:
wait()returns, and audio stops. Startup failures and unexpected disconnections are fatal.
Register an error handler to decide what your app does. Without one, the SDK logs the error (Python logging, console.error in Node.js), so errors are never silent. Because init() starts the session before it returns, a startup failure also raises VoiceAgentConnectionException, with the error in error_event (Python) or errorEvent (TypeScript).
In both cases, call close() in a finally block, as in the quickstart, so the session is always released.