Skip to main content

SWAIG Functions

SWAIG functions allow the AI agent to perform actions and access external systems. There are two types of SWAIG functions you can define:

Local Webhook Functions (Standard)

These are the traditional SWAIG functions that are handled locally by your agent:

from signalwire_agents.core.function_result import SwaigFunctionResult

@AgentBase.tool(
name="get_weather",
description="Get the current weather for a location",
parameters={
"location": {
"type": "string",
"description": "The city or location to get weather for"
}
},
secure=True # Optional, defaults to True
)
def get_weather(self, args, raw_data):
# Extract the location parameter
location = args.get("location", "Unknown location")

# Here you would typically call a weather API
# For this example, we'll return mock data
weather_data = f"It's sunny and 72°F in {location}."

# Return a SwaigFunctionResult
return SwaigFunctionResult(weather_data)

External Webhook Functions

External webhook functions allow you to delegate function execution to external services instead of handling them locally. This is useful when you want to:

  • Use existing web services or APIs directly
  • Distribute function processing across multiple servers
  • Integrate with third-party systems that provide their own endpoints

To create an external webhook function, add a webhook_url parameter to the decorator:

@AgentBase.tool(
name="get_weather_external",
description="Get weather from external service",
parameters={
"location": {
"type": "string",
"description": "The city or location to get weather for"
}
},
webhook_url="https://your-service.com/weather-endpoint"
)
def get_weather_external(self, args, raw_data):
# This function will never be called locally when webhook_url is provided
# The external service at webhook_url will receive the function call instead
return SwaigFunctionResult("This should not be reached for external webhooks")

How External Webhooks Work

When you specify a webhook_url:

  1. Function Registration: The function is registered with your agent as usual
  2. SWML Generation: The generated SWML includes the external webhook URL instead of your local endpoint
  3. SignalWire Processing: When the AI calls the function, SignalWire makes an HTTP POST request directly to your external URL
  4. Payload Format: The external service receives a JSON payload with the function call data:
{
"function": "get_weather_external",
"argument": {
"parsed": [{"location": "New York"}],
"raw": "{\"location\": \"New York\"}"
},
"call_id": "abc123-def456-ghi789",
"call": { /* call information */ },
"vars": { /* call variables */ }
}
  1. Response Handling: Your external service should return a JSON response that SignalWire will process.

Mixing Local and External Functions

You can mix both types of functions in the same agent:

class HybridAgent(AgentBase):
def __init__(self):
super().__init__(name="hybrid-agent", route="/hybrid")

# Local function - handled by this agent
@AgentBase.tool(
name="get_help",
description="Get help information",
parameters={}
)
def get_help(self, args, raw_data):
return SwaigFunctionResult("I can help you with weather and news!")

# External function - handled by external service
@AgentBase.tool(
name="get_weather",
description="Get current weather",
parameters={
"location": {"type": "string", "description": "City name"}
},
webhook_url="https://weather-service.com/api/weather"
)
def get_weather_external(self, args, raw_data):
# This won't be called for external webhooks
pass

# Another external function - different service
@AgentBase.tool(
name="get_news",
description="Get latest news",
parameters={
"topic": {"type": "string", "description": "News topic"}
},
webhook_url="https://news-service.com/api/news"
)
def get_news_external(self, args, raw_data):
# This won't be called for external webhooks
pass

Testing External Webhooks

You can test external webhook functions using the CLI tool:

# Test local function
swaig-test examples/my_agent.py --exec get_help

# Test external webhook function
swaig-test examples/my_agent.py --verbose --exec get_weather --location "New York"

# List all functions with their types
swaig-test examples/my_agent.py --list-tools

The CLI tool will automatically detect external webhook functions and make HTTP requests to the external services, simulating what SignalWire does in production.

Function Parameters

The parameters for a SWAIG function are defined using JSON Schema:

parameters={
"parameter_name": {
"type": "string", # Can be string, number, integer, boolean, array, object
"description": "Description of the parameter",
# Optional attributes:
"enum": ["option1", "option2"], # For enumerated values
"minimum": 0, # For numeric types
"maximum": 100, # For numeric types
"pattern": "^[A-Z]+$" # For string validation
}
}

Function Results

To return results from a SWAIG function, use the SwaigFunctionResult class:

# Basic result with just text
return SwaigFunctionResult("Here's the result")

# Result with a single action
return SwaigFunctionResult("Here's the result with an action")
.add_action("say", "I found the information you requested.")

# Result with multiple actions using add_actions
return SwaigFunctionResult("Multiple actions example")
.add_actions([
{"playback_bg": {"file": "https://example.com/music.mp3"}},
{"set_global_data": {"key": "value"}}
])

# Alternative way to add multiple actions sequentially
return (
SwaigFunctionResult("Sequential actions example")
.add_action("say", "I found the information you requested.")
.add_action("playback_bg", {"file": "https://example.com/music.mp3"})
)

In the examples above:

  • add_action(name, data) adds a single action with the given name and data
  • add_actions(actions) adds multiple actions at once from a list of action objects

Native Functions

The agent can use SignalWire's built-in functions:

# Enable native functions
self.set_native_functions([
"check_time",
"wait_seconds"
])

Function Includes

You can include functions from remote sources:

# Include remote functions
self.add_function_include(
url="https://api.example.com/functions",
functions=["get_weather", "get_news"],
meta_data={"session_id": "unique-session-123"} # Use for session tracking, NOT credentials
)

SWAIG Function Security

The SDK implements an automated security mechanism for SWAIG functions to ensure that only authorized calls can be made to your functions. This is important because SWAIG functions often provide access to sensitive operations or data.

Token-Based Security

By default, all SWAIG functions are marked as secure=True, which enables token-based security:

@agent.tool(
name="get_account_details",
description="Get customer account details",
parameters={"account_id": {"type": "string"}},
secure=True # This is the default, can be omitted
)
def get_account_details(self, args, raw_data):
# Implementation

When a function is marked as secure:

  1. The SDK automatically generates a secure token for each function when rendering the SWML document
  2. The token is added to the function's URL as a query parameter: ?token=X2FiY2RlZmcuZ2V0X3RpbWUuMTcxOTMxNDI1...
  3. When the function is called, the token is validated before executing the function

These security tokens have important properties:

  • Completely stateless: The system doesn't need to store tokens or track sessions
  • Self-contained: Each token contains all information needed for validation
  • Function-specific: A token for one function can't be used for another
  • Session-bound: Tokens are tied to a specific call/session ID
  • Time-limited: Tokens expire after a configurable duration (default: 60 minutes)
  • Cryptographically signed: Tokens can't be tampered with or forged

This stateless design provides several benefits:

  • Server resilience: Tokens remain valid even if the server restarts
  • No memory consumption: No need to track sessions or store tokens in memory
  • High scalability: Multiple servers can validate tokens without shared state
  • Load balancing: Requests can be distributed across multiple servers freely

The token system secures both SWAIG functions and post-prompt endpoints:

  • SWAIG function calls for interactive AI capabilities
  • Post-prompt requests for receiving conversation summaries

You can disable token security for specific functions when appropriate:

@agent.tool(
name="get_public_information",
description="Get public information that doesn't require security",
parameters={},
secure=False # Disable token security for this function
)
def get_public_information(self, args, raw_data):
# Implementation

Token Expiration

The default token expiration is 60 minutes (3600 seconds), but you can configure this when initializing your agent:

agent = MyAgent(
name="my_agent",
token_expiry_secs=1800 # Set token expiration to 30 minutes
)

The expiration timer resets each time a function is successfully called, so as long as there is activity at least once within the expiration period, the tokens will remain valid throughout the entire conversation.

Custom Token Validation

You can override the default token validation by implementing your own validate_tool_token method in your custom agent class.