SWAIG (SignalWire AI Gateway) is the platform's AI tool-calling system -- it connects the AI's decisions to actions like call transfers, SMS, recordings, and API calls, with native access to the media stack. This document provides a complete reference for all methods available in the SwaigFunctionResult class. These methods provide convenient abstractions for SWAIG actions, eliminating the need to manually construct action JSON objects.
Creates a new result object with optional response text and post-processing behavior.
result = SwaigFunctionResult("Hello, I'll help you with that")
result = SwaigFunctionResult("Processing request...", post_process=True)Sets or updates the response text that the AI will speak.
result.set_response("I've updated your information")Controls whether AI gets one more turn before executing actions.
result.set_post_process(True) # AI speaks response before executing actions
result.set_post_process(False) # Actions execute immediatelyExecute SWML content with flexible input support and optional transfer behavior.
# Raw SWML string
result.execute_swml('{"version":"1.0.0","sections":{"main":[{"say":"Hello"}]}}')
# SWML dictionary
swml_dict = {"version": "1.0.0", "sections": {"main": [{"say": "Hello"}]}}
result.execute_swml(swml_dict, transfer=True)
# SWML SDK object
from signalwire.swml import SWML
swml_doc = SWML()
swml_doc.add_application("main", "say", {"text": "Connecting now"})
result.execute_swml(swml_doc)result.connect("+15551234567", final=True) # Permanent transfer
result.connect("support@company.com", final=False, from_addr="+15559876543") # Temporary transfer[HELPER METHOD] - Send SMS message to PSTN phone number using SWML.
# Simple text message
result.send_sms(
to_number="+15551234567",
from_number="+15559876543",
body="Your order has been confirmed!"
)
# Media message with images
result.send_sms(
to_number="+15551234567",
from_number="+15559876543",
media=["https://example.com/receipt.jpg", "https://example.com/map.png"]
)
# Full featured message with tags and region
result.send_sms(
to_number="+15551234567",
from_number="+15559876543",
body="Order update with receipt attached",
media=["https://example.com/receipt.pdf"],
tags=["order", "confirmation", "customer"],
region="us"
)Parameters:
to_number(required): Phone number in E.164 format to send tofrom_number(required): Phone number in E.164 format to send frombody(optional): Message text (required if no media)media(optional): Array of URLs to send (required if no body)tags(optional): Array of tags for UI searchingregion(optional): Region to originate message from
Variables Set:
send_sms_result: "success" or "failed"
[HELPER METHOD] - Process payments using SWML pay action with extensive customization.
# Simple payment setup
result.pay(
payment_connector_url="https://api.example.com/accept-payment",
charge_amount="10.99",
description="Monthly subscription"
)
# Advanced payment with custom prompts
from signalwire.core.function_result import SwaigFunctionResult
# Create custom prompts
welcome_actions = [
SwaigFunctionResult.create_payment_action("Say", "Welcome to our payment system"),
SwaigFunctionResult.create_payment_action("Say", "Please enter your credit card number")
]
card_prompt = SwaigFunctionResult.create_payment_prompt("payment-card-number", welcome_actions)
error_actions = [
SwaigFunctionResult.create_payment_action("Say", "Invalid card number, please try again")
]
error_prompt = SwaigFunctionResult.create_payment_prompt(
"payment-card-number",
error_actions,
error_type="invalid-card-number timeout"
)
# Create payment parameters
params = [
SwaigFunctionResult.create_payment_parameter("customer_id", "12345"),
SwaigFunctionResult.create_payment_parameter("order_id", "ORD-789")
]
# Full payment configuration
result.pay(
payment_connector_url="https://api.example.com/accept-payment",
status_url="https://api.example.com/payment-status",
timeout=10,
max_attempts=3,
security_code=True,
postal_code=False,
token_type="one-time",
charge_amount="25.50",
currency="usd",
language="en-US",
voice="polly.Sally",
description="Premium service upgrade",
valid_card_types="visa mastercard amex",
parameters=params,
prompts=[card_prompt, error_prompt]
)Core Parameters:
payment_connector_url(required): URL to process payment requestsinput_method: "dtmf" or "voice" (default: "dtmf")payment_method: "credit-card" (default: "credit-card")timeout: Seconds to wait for input (default: 5)max_attempts: Number of retry attempts (default: 1)
Security & Validation:
security_code: Prompt for CVV (default: True)postal_code: Prompt for postal code or provide known code (default: True)min_postal_code_length: Minimum postal code digits (default: 0)valid_card_types: Space-separated card types (default: "visa mastercard amex")
Payment Configuration:
token_type: "one-time" or "reusable" (default: "reusable")charge_amount: Amount as decimal stringcurrency: Currency code (default: "usd")description: Payment description
Customization:
language: Prompt language (default: "en-US")voice: TTS voice (default: "woman")status_url: URL for status notificationsparameters: Additional name/value pairs for connectorprompts: Custom prompt configurations
Helper Methods for Payment Setup:
# Create payment action
action = SwaigFunctionResult.create_payment_action("Say", "Enter card number")
# Create payment prompt
prompt = SwaigFunctionResult.create_payment_prompt(
"payment-card-number",
[action],
error_type="invalid-card-number"
)
# Create payment parameter
param = SwaigFunctionResult.create_payment_parameter("customer_id", "12345")Variables Set:
pay_result: "success", "too-many-failed-attempts", "payment-connector-error", etc.pay_payment_results: JSON with payment details including tokens and card info
[HELPER METHOD] - Start background call recording using SWML.
Unlike foreground recording, the script continues executing while recording happens in the background.
# Simple background recording
result.record_call()
# Recording with custom settings
result.record_call(
control_id="support_call_001",
stereo=True,
format="mp3",
direction="both",
max_length=300 # 5 minutes max
)
# Recording with terminator and status webhook
result.record_call(
control_id="customer_voicemail",
format="wav",
direction="speak", # Only record customer voice
terminators="#", # Stop on '#' press
beep=True, # Play beep before recording
initial_timeout=4.0, # Wait 4 seconds for speech
end_silence_timeout=3.0, # Stop after 3 seconds of silence
status_url="https://api.example.com/recording-status"
)Core Parameters:
control_id(optional): Identifier for this recording (for use with stop_record_call)stereo: Record in stereo (default: False)format: "wav" or "mp3" (default: "wav")direction: "speak", "listen", or "both" (default: "both")
Control Options:
terminators: Digits that stop recording when pressedbeep: Play beep before recording (default: False)max_length: Maximum recording length in seconds
Timing Options:
input_sensitivity: Input sensitivity (default: 44.0)initial_timeout: Time to wait for speech start (default: 0.0)end_silence_timeout: Time to wait in silence before ending (default: 0.0)
Webhook Options:
status_url: URL to send recording status events to
Variables Set:
record_call_result: "success" or "failed"record_call_url: URL of recorded file (when recording completes)
[HELPER METHOD] - Stop an active background call recording using SWML.
# Stop the most recent recording
result.stop_record_call()
# Stop specific recording by ID
result.stop_record_call("support_call_001")
# Chain to stop recording and provide feedback
result.stop_record_call("customer_voicemail") \
.say("Thank you, your message has been recorded")Parameters:
control_id(optional): Identifier for recording to stop. If not provided, stops the most recent recording.
Variables Set:
stop_record_call_result: "success" or "failed"
[HELPER METHOD] - Join a RELAY room using SWML.
RELAY rooms enable multi-party communication and collaboration features.
# Join a conference room
result.join_room("support_team_room")
# Join customer meeting room
result.join_room("customer_meeting_001") \
.say("Welcome to the customer meeting room")
# Join room and set metadata
result.join_room("sales_conference") \
.set_metadata({"participant_role": "moderator", "join_time": "2024-01-01T12:00:00Z"})Parameters:
name(required): The name of the room to join
Variables Set:
join_room_result: "success" or "failed"
[HELPER METHOD] - Send SIP REFER for call transfer using SWML.
SIP REFER is used for call transfer in SIP environments, allowing one endpoint to request another to initiate a new connection.
# Basic SIP refer to transfer call
result.sip_refer("sip:support@company.com")
# Transfer to specific SIP address with domain
result.sip_refer("sip:agent123@pbx.company.com:5060")
# Chain with announcement
result.say("Transferring your call to our specialist") \
.sip_refer("sip:specialist@company.com")Parameters:
to_uri(required): The SIP URI to send the REFER to
Variables Set:
sip_refer_result: "success" or "failed"
[HELPER METHOD] - Join an ad-hoc audio conference with RELAY and CXML calls using SWML.
Provides extensive configuration options for conference call management and recording.
# Simple conference join
result.join_conference("my_conference")
# Basic conference with recording
result.join_conference(
name="daily_standup",
record="record-from-start",
max_participants=10
)
# Advanced conference with callbacks and coaching
result.join_conference(
name="customer_support_conf",
muted=False,
beep="onEnter",
start_on_enter=True,
end_on_exit=False,
max_participants=50,
record="record-from-start",
region="us-east",
trim="trim-silence",
status_callback="https://api.company.com/conference-events",
status_callback_event="start end join leave",
recording_status_callback="https://api.company.com/recording-events"
)
# Chain with other actions
result.say("Joining you to the team conference") \
.join_conference("team_meeting") \
.set_metadata({"meeting_type": "team_sync", "participant_role": "attendee"})Core Parameters:
name(required): Name of conference to joinmuted: Join muted (default: False)beep: Beep configuration - "true", "false", "onEnter", "onExit" (default: "true")start_on_enter: Conference starts when this participant enters (default: True)end_on_exit: Conference ends when this participant exits (default: False)
Capacity & Region:
max_participants: Maximum participants <= 250 (default: 250)region: Conference region for optimizationwait_url: SWML URL for custom hold music
Recording Options:
record: "do-not-record" or "record-from-start" (default: "do-not-record")trim: "trim-silence" or "do-not-trim" (default: "trim-silence")recording_status_callback: URL for recording status eventsrecording_status_callback_method: "GET" or "POST" (default: "POST")recording_status_callback_event: "in-progress completed absent" (default: "completed")
Status & Coaching:
coach: SWML Call ID or CXML CallSid for coaching featuresstatus_callback: URL for conference status eventsstatus_callback_method: "GET" or "POST" (default: "POST")status_callback_event: Events to report - "start end join leave mute hold modify speaker announcement"
Control Flow:
result: Switch on return_value (object {} or array [] for conditional logic)
Variables Set:
join_conference_result: "completed", "answered", "no-answer", "failed", or "canceled"return_value: Same asjoin_conference_result
[HELPER METHOD] - Start background call tap using SWML.
Media is streamed over Websocket or RTP to customer controlled URI for real-time monitoring and analysis.
# Simple WebSocket tap
result.tap("wss://example.com/tap")
# RTP tap with custom settings
result.tap(
uri="rtp://192.168.1.100:5004",
control_id="monitoring_tap_001",
direction="both",
codec="PCMA",
rtp_ptime=30
)
# Advanced tap with status callbacks
result.tap(
uri="wss://monitoring.company.com/audio-stream",
control_id="compliance_tap",
direction="speak", # Only what the party says
status_url="https://api.company.com/tap-status"
) \
.set_metadata({"tap_purpose": "compliance", "session_id": "sess_123"})Core Parameters:
uri(required): Destination of tap media stream- WebSocket:
ws://example.comorwss://example.com - RTP:
rtp://IP:port
- WebSocket:
control_id: Identifier for this tap to use with stop_tap (optional, auto-generated if not provided)
Audio Configuration:
direction: Audio direction to tap (default: "both")"speak": What party says"hear": What party hears"both": What party hears and says
codec: Codec for tap stream - "PCMU" or "PCMA" (default: "PCMU")rtp_ptime: RTP packetization time in milliseconds (default: 20)
Status & Monitoring:
status_url: URL for tap status change requests
Variables Set:
tap_uri: Destination URI of the newly started taptap_result: "success" or "failed"tap_control_id: Control ID of this taptap_rtp_src_addr: If RTP, source address of the tap streamtap_rtp_src_port: If RTP, source port of the tap streamtap_ptime: Packetization time of the tap streamtap_codec: Codec in the tap streamtap_rate: Sample rate in the tap stream
[HELPER METHOD] - Stop an active tap stream using SWML.
# Stop the most recent tap
result.stop_tap()
# Stop specific tap by ID
result.stop_tap("monitoring_tap_001")
# Chain to stop tap and provide feedback
result.stop_tap("compliance_tap") \
.say("Audio monitoring has been stopped") \
.update_global_data({"tap_active": False})Parameters:
control_id(optional): ID of the tap to stop. If not set, the last tap started will be stopped.
Variables Set:
stop_tap_result: "success" or "failed"
Terminate the call immediately.
result.hangup()Put call on hold with timeout (max 900 seconds).
result.hold(60) # Hold for 1 minute
result.hold(600) # Hold for 10 minutesControl how agent waits for user input with flexible parameters.
result.wait_for_user(True) # Wait indefinitely
result.wait_for_user(timeout=30) # Wait 30 seconds
result.wait_for_user(answer_first=True) # Special answer_first mode
result.wait_for_user(False) # Disable waitingStop agent execution completely.
result.stop()Make the agent speak specific text immediately.
result.say("Please hold while I look that up for you")Play audio file in background with attention control.
result.play_background_file("hold_music.wav") # AI tries to get attention
result.play_background_file("announcement.mp3", wait=True) # AI suppresses attentionStop currently playing background audio.
result.stop_background_file()Set silence timeout after speech detection for finalizing recognition.
result.set_end_of_speech_timeout(2000) # 2 seconds of silenceSet timeout since last speech event - better for noisy environments.
result.set_speech_event_timeout(3000) # 3 seconds since last speech event[IMPLEMENTED] - Update global agent data variables.
result.update_global_data({"user_name": "John", "step": 2})Remove global data variables by key(s).
result.remove_global_data("temporary_data") # Single key
result.remove_global_data(["step", "temp_value"]) # Multiple keysSet metadata scoped to current function's meta_data_token.
result.set_metadata({"session_id": "abc123", "user_tier": "premium"})Remove metadata from current function's scope.
result.remove_metadata("temp_session_data") # Single key
result.remove_metadata(["cache_key", "temp_flag"]) # Multiple keysEnable/disable specific SWAIG functions dynamically.
result.toggle_functions([
{"function": "transfer_call", "active": False},
{"function": "lookup_info", "active": True}
])Control whether functions can be called on speaker timeout.
result.enable_functions_on_timeout(True)
result.enable_functions_on_timeout(False)Send full data to LLM for this turn only, then use smaller replacement.
result.enable_extensive_data(True) # Send extensive data this turn
result.enable_extensive_data(False) # Use normal dataRemove or replace the tool_call + tool_result pair from the LLM's conversation history after the first send. This is useful when a function call is an implementation detail that would confuse the model if it remained visible in context.
When called with a string, the tool_call/tool_result pair is replaced with an assistant message containing that text. When called with True, the pair is removed entirely — the LLM will never see that the function was called.
# Remove entirely — LLM won't see this function was called
result = SwaigFunctionResult("Done.")
result.replace_in_history()
# Replace with a friendly assistant message instead of tool artifacts
result = SwaigFunctionResult("Profile saved.")
result.replace_in_history("I've saved your profile information.")
# Practical example: data collection function that shouldn't clutter history
@agent.tool(name="save_answer", description="Save the user's answer")
def save_answer(args, raw_data):
answer = args.get("answer")
result = SwaigFunctionResult(f"Answer recorded: {answer}")
result.replace_in_history() # Keep history clean
return resultWhen to use:
- Functions that are implementation details (saving data, logging, internal state changes)
- Functions called frequently that would bloat conversation history
- Situations where tool artifacts confuse the model's reasoning (especially with reasoning models at low effort settings)
Note: For structured data collection, consider using gather_info mode instead, which produces zero tool artifacts by design and doesn't require replace_in_history.
Update agent runtime settings with validation.
# AI model settings
result.update_settings({
"temperature": 0.7,
"max-tokens": 2048,
"frequency-penalty": -0.5
})
# Speech recognition settings
result.update_settings({
"confidence": 0.8,
"barge-confidence": 0.7
})Supported Settings:
frequency-penalty: Float (-2.0 to 2.0)presence-penalty: Float (-2.0 to 2.0)max-tokens: Integer (0 to 4096)top-p: Float (0.0 to 1.0)confidence: Float (0.0 to 1.0)barge-confidence: Float (0.0 to 1.0)temperature: Float (0.0 to 2.0, clamped to 1.5)
Change agent context/prompt during conversation.
# Simple context switch
result.switch_context("You are now a technical support agent")
# Advanced context switch
result.switch_context(
system_prompt="You are a billing specialist",
user_prompt="The user needs help with their invoice",
consolidate=True
)Queue simulated user input for testing or flow control.
result.simulate_user_input("Yes, I'd like to speak to billing")Add a single action manually (for custom actions not covered by helper methods).
result.add_action("custom_action", {"param": "value"})Add multiple actions at once.
result.add_actions([
{"say": "Hello"},
{"hold": 300}
])Convert result to dictionary format for JSON serialization.
result_dict = result.to_dict()
# Returns: {"response": "...", "action": [...], "post_process": true/false}All methods return self to enable fluent method chaining:
result = SwaigFunctionResult("Processing your request", post_process=True) \
.update_global_data({"status": "processing"}) \
.play_background_file("processing.wav", wait=True) \
.set_end_of_speech_timeout(2500)
# Complex chaining example
result = SwaigFunctionResult("Let me transfer you to billing") \
.set_metadata({"transfer_reason": "billing_inquiry"}) \
.update_global_data({"last_action": "transfer_to_billing"}) \
.connect("+15551234567", final=True)- [IMPLEMENTED]:
connect(),update_global_data(), and all methods listed above - [HELPER METHODS]:
send_sms(),pay(),record_call(),stop_record_call(),join_room(),sip_refer(),join_conference(),tap(),stop_tap()- Additional convenience methods that generate SWML - [UTILITY METHODS]:
create_payment_prompt(),create_payment_action(),create_payment_parameter() - [EXTENSIBLE]: Additional convenience methods for common SWML patterns
- Use post_process=True when you want the AI to speak before executing actions
- Chain methods for cleaner, more readable code
- Use specific methods instead of manual action construction when available
- Handle errors gracefully - methods may raise TypeError for invalid inputs
- Validate settings - update_settings() relies on server-side validation
The framework now includes 10 virtual helpers total:
- connect() - Call transfer/connect
- send_sms() - SMS messaging
- pay() - Payment processing
- record_call() - Start background recording
- stop_record_call() - Stop background recording
- join_room() - Join RELAY room
- sip_refer() - SIP REFER transfer
- join_conference() - Join audio conference with extensive options
- tap() - Start background call tap for monitoring
- stop_tap() - Stop background call tap
The post_data object is the JSON payload sent to SWAIG function handlers. Its structure differs between webhook functions and DataMap functions.
| Key | Type | Description |
|---|---|---|
app_name |
string | Name of the AI application |
function |
string | Name of the SWAIG function being called |
call_id |
string | Unique UUID of the current call session |
ai_session_id |
string | Unique UUID of the AI session |
caller_id_name |
string | Caller ID name (if available) |
caller_id_num |
string | Caller ID number (if available) |
channel_active |
boolean | Whether the channel is currently up |
channel_offhook |
boolean | Whether the channel is off-hook |
channel_ready |
boolean | Whether the AI session is ready |
argument |
object | Parsed function arguments |
argument_desc |
object | Function argument schema/description |
purpose |
string | Description of what the function does |
content_type |
string | Always "text/swaig" |
version |
string | SWAIG protocol version |
global_data |
object | Application-level global data (when set) |
conversation_id |
string | Conversation identifier (when tracking enabled) |
project_id |
string | SignalWire project ID |
space_id |
string | SignalWire space ID |
These keys are only present for traditional webhook SWAIG functions:
| Key | Type | Description | Present When |
|---|---|---|---|
meta_data_token |
string | Token for metadata access | Function has metadata token |
meta_data |
object | Function-level metadata | Function has metadata token |
SWMLVars |
object | SWML variables | swaig_post_swml_vars parameter set |
SWMLCall |
object | SWML call state | swaig_post_swml_vars parameter set |
call_log |
array | Processed conversation history | swaig_post_conversation is true |
raw_call_log |
array | Raw conversation history | swaig_post_conversation is true |
Metadata scoping: Functions sharing the same meta_data_token share access to the same metadata. If no token is specified, scope defaults to function name/URL.
Conversation history: call_log may shrink after conversation resets (consolidation), while raw_call_log preserves full history. Both include timing data (latency, utterance_latency, audio_latency).
| Key | Type | Description |
|---|---|---|
prompt_vars |
object | Template variables built from call context, SWML vars, and global_data |
args |
object | First parsed argument object for easy template access |
input |
object | Copy of entire post_data for variable expansion |
| Key | Source | Description |
|---|---|---|
call_direction |
Call direction | "inbound" or "outbound" |
caller_id_name |
Channel variable | Caller's name |
caller_id_number |
Channel variable | Caller's number |
local_date |
System time | Current date in local timezone |
local_time |
System time | Current time with timezone |
time_of_day |
Derived from hour | "morning", "afternoon", or "evening" |
supported_languages |
App config | Available languages |
default_language |
App config | Primary language |
All keys from global_data are also merged into prompt_vars, with global_data taking precedence.
| Parameter | Type | Default | Purpose |
|---|---|---|---|
swaig_allow_swml |
boolean | true | Allow functions to execute SWML actions |
swaig_allow_settings |
boolean | true | Allow functions to modify AI settings |
swaig_post_conversation |
boolean | false | Include conversation history in post_data |
swaig_set_global_data |
boolean | true | Allow functions to modify global_data |
swaig_post_swml_vars |
boolean/array | false | Include SWML variables in post_data |
DataMap processing supports template expansion with access to:
- Nested object access via dot notation:
${user.name} - Array access:
${items[0].value} - Encoding functions:
${enc:url:variable} - Built-in functions:
@{strftime %Y-%m-%d},@{expr 2+2}
- API Reference - Complete AgentBase and SwaigFunctionResult API reference
- Contexts Guide - Using
swml_change_context()andswml_change_step() - DataMap Guide - Using SwaigFunctionResult with DataMap outputs
- Agent Guide - General agent development guide
examples/simple_agent.py- Basic SWAIG function usageexamples/swaig_features_agent.py- Advanced SWAIG features with fillersexamples/record_call_example.py- Recording and tapping callsexamples/room_and_sip_example.py- Room joining and SIP transfer