Skip to content

Listener

AgentListener is a callback interface that lets you react to session lifecycle events — transcript completions, speaking state changes, errors, and session boundaries. It is the primary integration point for building UIs, logging pipelines, or any code that needs to observe what the agent is doing.


Overview

Subclass AgentListener, override the methods you need, and pass an instance to RealtimeAgent:

from rtvoice import RealtimeAgent, AgentListener

class MyListener(AgentListener):
    async def on_user_transcript(self, transcript: str) -> None:
        print(f"User: {transcript}")

    async def on_assistant_transcript(self, transcript: str) -> None:
        print(f"Assistant: {transcript}")

agent = RealtimeAgent(
    instructions="...",
    listener=MyListener(),
)
await agent.run()

All methods are async no-ops by default — override only the ones you care about.


Available callbacks

Session lifecycle

Method When it fires
on_agent_session_connected() The WebSocket session is open and ready.
on_agent_stopped() The agent has fully shut down and run() is about to return.

Speaking state

Method When it fires
on_user_started_speaking() VAD detects that the user has started speaking.
on_user_stopped_speaking() VAD detects that the user has stopped speaking.
on_assistant_started_responding() The assistant begins streaming audio.
on_assistant_stopped_responding() The assistant finishes streaming audio.
on_agent_interrupted() The user interrupted the assistant mid-response.

Transcripts

Method When it fires
on_user_transcript(transcript) The user's turn is fully transcribed. Requires a transcription_model.
on_assistant_transcript(transcript) The assistant's response transcript is complete.

Errors

Method When it fires
on_agent_error(error) An error was received from the Realtime API or the agent internals.

Logging transcripts to the console

from rtvoice import AgentListener

class ConsolePrinter(AgentListener):
    async def on_user_transcript(self, transcript: str) -> None:
        print(f"\033[36mYou: {transcript}\033[0m")

    async def on_assistant_transcript(self, transcript: str) -> None:
        print(f"Jarvis: {transcript}")

Tracking speaking state for UI

Use speaking state callbacks to drive UI indicators (e.g. a mic activity light or a "thinking" spinner):

from rtvoice import AgentListener

class UIBridge(AgentListener):
    async def on_user_started_speaking(self) -> None:
        ui.set_mic_active(True)

    async def on_user_stopped_speaking(self) -> None:
        ui.set_mic_active(False)

    async def on_assistant_started_responding(self) -> None:
        ui.show_spinner(True)

    async def on_assistant_stopped_responding(self) -> None:
        ui.show_spinner(False)

    async def on_agent_interrupted(self) -> None:
        ui.show_spinner(False)

Handling errors

from rtvoice import AgentListener
from rtvoice.views import AgentError

class ErrorHandler(AgentListener):
    async def on_agent_error(self, error: AgentError) -> None:
        print(f"[{error.type}] {error.message}")
        # e.g. log to Sentry, display an error banner, etc.

AgentError has two fields:

  • type — OpenAI error type identifier (e.g. invalid_request_error)
  • message — Human-readable description

Reacting to session end

class SessionLogger(AgentListener):
    async def on_agent_session_connected(self) -> None:
        self._start = time.time()

    async def on_agent_stopped(self) -> None:
        duration = time.time() - self._start
        print(f"Session ended after {duration:.0f}s")

Full example

import asyncio
from rtvoice import RealtimeAgent, AgentListener
from rtvoice.views import AgentError

class VerboseListener(AgentListener):
    async def on_agent_session_connected(self) -> None:
        print("[connected]")

    async def on_user_started_speaking(self) -> None:
        print("[user speaking…]")

    async def on_user_transcript(self, transcript: str) -> None:
        print(f"You: {transcript}")

    async def on_assistant_started_responding(self) -> None:
        print("[assistant responding…]")

    async def on_assistant_transcript(self, transcript: str) -> None:
        print(f"Assistant: {transcript}")

    async def on_agent_interrupted(self) -> None:
        print("[interrupted]")

    async def on_agent_error(self, error: AgentError) -> None:
        print(f"Error: {error}")

    async def on_agent_stopped(self) -> None:
        print("[session ended]")


async def main():
    agent = RealtimeAgent(
        instructions="You are a concise voice assistant.",
        listener=VerboseListener(),
    )
    await agent.run()

asyncio.run(main())

API reference

See AgentListener and AgentError for full method signatures.