Event Reference
VoiceRun uses an event-driven architecture. Your agent receives input events and yields output events to control the conversation.
Event Lifecycle#
- Event handler is invoked once per input event
- Event handler can yield zero or more output events
- 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.loggerinstead of yieldingLogEventdirectly. 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":
| Key | Type | Description |
|---|---|---|
toPhoneNumber | string | Destination phone number in E.164 format. Required. |
fromPhoneNumber | string | Caller ID. Defaults to the environment's assigned number. |
timeout | int | Call setup timeout in seconds (default: 60). |
timeLimit | int | Maximum call duration in seconds. |
statusCallbackUrl | string | Webhook URL for call state changes. |
statusCallbackMethod | string | HTTP method for the status callback (GET or POST). |
byoc | string | Bring-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"}
