Event Reference

VoiceRun uses an event-driven architecture. Your agent receives input events and yields output events to control the conversation.

Event Lifecycle#

  1. Event handler is invoked once per input event
  2. Event handler can yield zero or more output events
  3. Each output event is processed in the order emitted

Input Events#

Input events are triggered by user actions or system events and passed to your agent's handler function.

StartEvent#

Emitted when a new voice agent session has started.

class StartEvent(Event): pass

Usage:

if isinstance(event, StartEvent): yield TextToSpeechEvent( text="Hello! How can I help you today?", voice="nova" )

TextEvent#

Emitted when the user speaks or types text.

class TextEvent(Event): data: { "source": str # Source of input: "speech" or "text" "text": str # The transcribed or typed text "language": str # Language code (optional, provided by STT) }

Usage:

if isinstance(event, TextEvent): user_message = event.data.get("text", "N/A") source = event.data.get("source") # "speech" or "text"

TimeoutEvent#

Emitted when the user does not speak for 5 seconds of silence. The timeout counter increments with each consecutive timeout and resets when the user speaks.

class TimeoutEvent(Event): data: { "count": int # Number of consecutive timeouts "ms_since_input": int # Milliseconds since last input }

Usage:

if isinstance(event, TimeoutEvent): count = event.data.get("count", 0) ms_since_input = event.data.get("ms_since_input", 0) if count >= 3: yield TextToSpeechEvent(text="Are you still there?", voice="nova") elif count == 1: yield TextToSpeechEvent(text="Take your time.", voice="nova")

DTMFEvent#

Emitted when DTMF tones (phone keypad input) are received.

class DTMFEvent(Event): data: { "digits": str # The DTMF digits pressed (e.g., "123#") }

Usage:

if isinstance(event, DTMFEvent): digits = event.data.get("digits") if digits == "1": yield TextToSpeechEvent(text="You pressed one.", voice="nova")

Output Events#

Output events are yielded by your agent to perform actions like speaking, playing audio, or transferring sessions.

TextToSpeechEvent#

Converts text to speech and plays it to the user.

class TextToSpeechEvent(Event): def __init__( self, text: str, # Text to speak voice: str | TextToSpeechIdentifier = "nova", # Voice name or identifier cache: bool = True, # Cache generated audio interruptible: bool | None = None, # Can user interrupt instructions: str = "", # Voice styling (OpenAI only) speed: float = 1.0, # Playback speed language: str = "en", # Language code stream: bool | None = None, # Enable streaming TTS model: str | None = None, # Override default provider model )

Usage:

# Basic usage yield TextToSpeechEvent( text="Hello, how can I help you?", voice="nova" ) # With voice styling (OpenAI only) yield TextToSpeechEvent( text="Welcome to our service!", voice="alloy", instructions="enthusiastic and professional", speed=1.25 ) # Non-interruptible announcement yield TextToSpeechEvent( text="Please do not interrupt this important message.", voice="nova", interruptible=False ) # Using TextToSpeechIdentifier for specific provider voice yield TextToSpeechEvent( text="G'day mate!", voice={"provider": "azure", "identifier": "en-AU-WilliamNeural"} ) # Override the default model for the provider yield TextToSpeechEvent( text="High-quality narration.", voice={"provider": "openai", "identifier": "marin"}, model="tts-1-hd" )

AudioEvent#

Plays audio from a URL.

class AudioEvent(Event): def __init__( self, path: str, # URL of the audio file interruptible: bool = True, # Can user interrupt loop: bool = False, # Loop the audio )

Usage:

# Play audio file yield AudioEvent(path="https://example.com/audio.mp3") # Play non-interruptible audio yield AudioEvent( path="https://example.com/important.mp3", interruptible=False ) # Loop background music yield AudioEvent( path="https://example.com/hold-music.mp3", loop=True )

SilenceEvent#

Plays silence for a specified duration.

class SilenceEvent(Event): def __init__( self, duration: int # Duration in milliseconds )

Usage:

# Pause for 2 seconds yield SilenceEvent(duration=2000)

StopEvent#

Ends the current voice agent session.

class StopEvent(Event): def __init__( self, closing_speech: str | None = None, # Optional goodbye message voice: str | TextToSpeechIdentifier | None = None, # Voice for closing speech speed: float = 1.0, # Playback speed language: str = "en", # Language code )

Usage:

# End session immediately yield StopEvent() # End session with closing message yield StopEvent( closing_speech="Thank you for calling. Goodbye!", voice="nova" )

LogEvent#

Logs a message to the system logs.

class LogEvent(Event): def __init__( self, message: str, # Message to log location: str | None = None # Optional source location )

Usage:

from primfunctions.logger import logger logger.info("User requested account balance")

Tip: Use primfunctions.logger instead of yielding LogEvent directly. The logger can be called from anywhere in your code — not just inside the handler.


TransferSessionEvent#

Transfers the session to another phone number or agent.

class TransferSessionEvent(Event): def __init__( self, *, phone_number: str | None = None, # Phone number to transfer to agent_id: str | None = None, # Agent ID to transfer to environment: str | None = None, # Target environment data: dict | None = None, # Context data to pass closing_speech: str | None = None, # Message before transfer voice: str | TextToSpeechIdentifier | None = None, # Voice for closing speech speed: float = 1.0, # Playback speed language: str = "en", # Language code )

Usage:

# Phone transfer (cold transfer) yield TransferSessionEvent(phone_number="+15555555555") # Phone transfer with context yield TransferSessionEvent( phone_number="+15555551234", closing_speech="I'm transferring you to a specialist.", voice="nova", data={"reason": "technical_support", "priority": "high"} ) # Web/API redirect to different agent yield TransferSessionEvent( agent_id="technical_support_agent", environment="production", data={"conversation_context": "payment_issue"} )

STTUpdateSettingsEvent#

Dynamically updates Speech-to-Text settings during a conversation. See Speech To Text for model-specific configuration options.

class STTUpdateSettingsEvent(Event): def __init__( self, language: str | None = None, # Language code (e.g., "en", "es", "multi") prompt: str | None = None, # Context prompt for accuracy endpointing: int | None = None, # End-of-speech detection sensitivity noise_reduction_type: str | None = None, # Audio processing type model: str | None = None, # STT model to use )

Usage:

# Switch to Spanish yield STTUpdateSettingsEvent(language="es") # Improve transcription with context yield STTUpdateSettingsEvent( prompt="Technical conversation about software development" ) # Optimize for phone audio yield STTUpdateSettingsEvent( noise_reduction_type="telephony", endpointing=2000 ) # Full configuration update yield STTUpdateSettingsEvent( language="es", model="nova-3", prompt="Conversación técnica en español.", endpointing=500, noise_reduction_type="near_field" )

StartRecordingEvent#

Starts recording the current call session.

class StartRecordingEvent(Event): def __init__( self, status_callback_url: str | None = None # Webhook for recording status )

Usage:

# Start recording yield StartRecordingEvent() # Start recording with webhook yield StartRecordingEvent( status_callback_url="https://your-app.com/webhooks/recording" )

StopRecordingEvent#

Stops the current call recording.

class StopRecordingEvent(Event): pass

Usage:

yield StopRecordingEvent()

InputAllowedEvent#

Enables or disables user input.

class InputAllowedEvent(Event): def __init__( self, allowed: bool # True to enable input, False to disable )

When allowed=False, user input is disabled until either InputAllowedEvent(allowed=True) is yielded or the handler completes.

Usage:

# Disable input during processing yield InputAllowedEvent(allowed=False) # ... do some processing ... # Re-enable input yield InputAllowedEvent(allowed=True)

UpdateAudioSettingsEvent#

Updates the session's background audio track. Use this to start, swap, or stop a looping background track (hold music, ambient noise, etc.) while the call continues.

class UpdateAudioSettingsEvent(Event): def __init__( self, background_track_url: str | None = None, # URL of the background track (None to stop) background_track_volume: float = 1.0, # Volume from 0.0 to 1.0 background_track_loop: bool = True, # Loop the track )

Usage:

# Start a background track yield UpdateAudioSettingsEvent( background_track_url="https://example.com/hold-music.mp3", background_track_volume=0.4 ) # Stop the background track yield UpdateAudioSettingsEvent(background_track_url=None)

ErrorEvent#

Signals that an error has occurred. Useful for surfacing failures from your handler to the platform for logging and observability.

class ErrorEvent(Event): def __init__( self, message: str # Description of the error )

Usage:

try: result = await call_external_api() except Exception as e: yield ErrorEvent(message=f"External API failed: {e}")

UpdateCallEvent#

Updates parameters on the active telephony call (for example, modifying TwiML on a Twilio call mid-session).

class UpdateCallEvent(Event): def __init__( self, data: dict # Provider-specific call update payload )

Usage:

yield UpdateCallEvent(data={"twiml": "<Response><Pause length='2'/></Response>"})

StartSessionEvent#

Starts a new agent session with the given agent and configuration. Used to launch a session programmatically — for example, kicking off an outbound call from another agent.

class StartSessionEvent(Event): def __init__( self, agent_id: str = "", # Target agent ID environment: str = "", # Target environment input_type: str = "", # "phone" or "mic" input_parameters: dict = {}, # Channel-specific parameters (see below) parameters: dict = {}, # Custom session context passed to the new session )

input_parameters for input_type="phone":

KeyTypeDescription
toPhoneNumberstringDestination phone number in E.164 format. Required.
fromPhoneNumberstringCaller ID. Defaults to the environment's assigned number.
timeoutintCall setup timeout in seconds (default: 60).
timeLimitintMaximum call duration in seconds.
statusCallbackUrlstringWebhook URL for call state changes.
statusCallbackMethodstringHTTP method for the status callback (GET or POST).
byocstringBring-your-own-carrier SIP trunk identifier.

For input_type="mic", input_parameters can be left empty ({}) — this mode is for local WebSocket/microphone sessions.

parameters is a free-form dict of string values forwarded to the new session as initial context (accessible via the agent's context).

Usage:

# Outbound phone call to a follow-up agent yield StartSessionEvent( agent_id="outbound_followup_agent", environment="production", input_type="phone", input_parameters={ "toPhoneNumber": "+15555550100", "fromPhoneNumber": "+15555550199", }, parameters={"customer_id": "cust_123"}, )

MergeSessionEvent#

Merges another session into the current session by session ID. Useful for joining a follow-up or supervisor session into the active conversation.

class MergeSessionEvent(Event): def __init__( self, session_id: str # ID of the session to merge with )

Usage:

yield MergeSessionEvent(session_id="session_abc123")

CustomEvent#

Creates a custom event for client-specific functionality.

class CustomEvent(Event): def __init__( self, name: str, # Custom event name data: dict = {} # Custom event data )

Usage:

yield CustomEvent( name="user_action", data={"action": "button_click", "button_id": "submit"} )

ExternalEvent#

Sends an event to another agent session.

class ExternalEvent(Event): def __init__( self, agent_id: str, # Target agent ID session_id: str, # Target session ID name: str, # Event name data: dict # Event data )

Usage:

yield ExternalEvent( agent_id="supervisor_agent", session_id="session_123", name="escalation", data={"reason": "customer_request", "priority": "high"} )

Enums#

TTSProvider#

Supported Text-to-Speech providers for use with TextToSpeechIdentifier.

class TTSProvider(str, Enum): AZURE = "azure" CARTESIA = "cartesia" CUSTOM = "custom" ELEVENLABS = "elevenlabs" FISH_AUDIO = "fish_audio" GOOGLE_CHIRP = "google_chirp" GRADIUM = "gradium" INWORLD = "inworld" MINIMAX = "minimax" OPENAI = "openai" PRIM_VOICES = "prim_voices" QWEN3 = "qwen3" XAI = "xai"

Types#

TextToSpeechIdentifier#

Voice specification with provider and identifier for direct provider access.

class TextToSpeechIdentifier(TypedDict): provider: TTSProvider # The TTS provider identifier: str # Voice identifier for that provider

Examples:

{"provider": "azure", "identifier": "en-AU-WilliamNeural"} {"provider": "cartesia", "identifier": "6f84f4b8-58a2-430c-8c79-688dad597532"} {"provider": "custom", "identifier": "my_voicerun_custom_voice"} {"provider": "elevenlabs", "identifier": "21m00Tcm4TlvDq8ikWAM"} {"provider": "fish_audio", "identifier": "d13f84b987ad4f22b56d2b47f4eb838e"} {"provider": "google_chirp", "identifier": "laomedeia"} {"provider": "gradium", "identifier": "YTpq7expH9539ERJ"} {"provider": "inworld", "identifier": "Alex"} {"provider": "minimax", "identifier": "English_Aussie_Bloke"} {"provider": "openai", "identifier": "marin"} {"provider": "prim_voices", "identifier": "lyric"} {"provider": "qwen3", "identifier": "Serena"} {"provider": "xai", "identifier": "eve"}
eventsapireference