Skip to main content

Deployment

Summary: Deploy your agents as local servers, production services, or serverless functions. This chapter covers all deployment options from development to production.

What You'll Learn

This chapter covers deployment options:

  1. Local Development - Running agents during development
  2. Production - Deploying to production servers
  3. Serverless - AWS Lambda, Google Cloud Functions, Azure Functions
  4. Docker & Kubernetes - Container-based deployment
  5. CGI Mode - Traditional web server deployment

Deployment Options Overview

EnvironmentOptions
Developmentagent.run() on localhost, ngrok for public testing, auto-reload on changes
ProductionUvicorn with workers, HTTPS with certificates, load balancing, health monitoring
ServerlessAWS Lambda, Google Cloud Functions, Azure Functions, auto-scaling, pay per invocation
ContainerDocker, Kubernetes, auto-scaling, rolling updates, service mesh
TraditionalCGI mode, Apache/nginx integration, shared hosting compatible

Environment Detection

The SDK automatically detects your deployment environment:

Environment VariableDetected Mode
GATEWAY_INTERFACECGI mode
AWS_LAMBDA_FUNCTION_NAMEAWS Lambda
LAMBDA_TASK_ROOTAWS Lambda
FUNCTION_TARGETGoogle Cloud Functions
K_SERVICEGoogle Cloud Functions
GOOGLE_CLOUD_PROJECTGoogle Cloud Functions
AZURE_FUNCTIONS_ENVIRONMENTAzure Functions
FUNCTIONS_WORKER_RUNTIMEAzure Functions
(none of above)Server mode (default)

Chapter Contents

SectionDescription
Local DevelopmentDevelopment server and testing
ProductionProduction server deployment
ServerlessLambda, Cloud Functions, Azure
Docker & KubernetesContainer deployment
CGI ModeTraditional CGI deployment

Quick Start

from signalwire_agents import AgentBase

class MyAgent(AgentBase):
def __init__(self):
super().__init__(name="my-agent")
self.add_language("English", "en-US", "rime.spore")
self.prompt_add_section("Role", "You are a helpful assistant.")

if __name__ == "__main__":
agent = MyAgent()
agent.run() # Automatically detects environment

The run() method automatically:

  • Detects serverless environments (Lambda, Cloud Functions, Azure)
  • Starts a development server on localhost for local development
  • Handles CGI mode when deployed to traditional web servers

Starting the Development Server

The simplest way to run your agent locally:

from signalwire_agents import AgentBase


class MyAgent(AgentBase):
def __init__(self):
super().__init__(name="my-agent")
self.add_language("English", "en-US", "rime.spore")
self.prompt_add_section("Role", "You are a helpful assistant.")


if __name__ == "__main__":
agent = MyAgent()
agent.run() # Starts on http://localhost:3000

Server Configuration

Custom Host and Port

agent.run(host="0.0.0.0", port=8080)

Using serve() Directly

For more control, use serve() instead of run():

# Development server
agent.serve(host="127.0.0.1", port=3000)

# Listen on all interfaces
agent.serve(host="0.0.0.0", port=3000)

Development Endpoints

EndpointMethodPurpose
/GET/POSTSWML document
/swaigPOSTSWAIG function calls
/post_promptPOSTPost-prompt handling
/debugGET/POSTDebug information
/healthGETHealth check (AgentServer only)

Testing Your Agent

View SWML Output

# Get the SWML document
curl http://localhost:3000/

# Pretty print with jq
curl http://localhost:3000/ | jq .

Using swaig-test CLI

# List available functions
swaig-test my_agent.py --list-tools

# Test a specific function
swaig-test my_agent.py --exec get_weather --city "Seattle"

# Dump SWML output
swaig-test my_agent.py --dump-swml

Exposing Local Server

SignalWire needs to reach your agent via a public URL. Use ngrok or similar:

Connection Flow: SignalWire Cloud → ngrok tunnel → localhost:3000

Steps:

  1. Start your agent: python my_agent.py
  2. Start ngrok: ngrok http 3000
  3. Use ngrok URL in SignalWire: https://abc123.ngrok.io

Using ngrok

# Start your agent
python my_agent.py

# In another terminal, start ngrok
ngrok http 3000

ngrok provides a public URL like https://abc123.ngrok.io that forwards to your local server.

Using localtunnel

# Install
npm install -g localtunnel

# Start tunnel
lt --port 3000

Environment Variables for Development

# Disable authentication for local testing
export SWML_BASIC_AUTH_USER=""
export SWML_BASIC_AUTH_PASSWORD=""

# Or set custom credentials
export SWML_BASIC_AUTH_USER="dev"
export SWML_BASIC_AUTH_PASSWORD="test123"

# Override proxy URL if behind ngrok
export SWML_PROXY_URL_BASE="https://abc123.ngrok.io"

Proxy URL Configuration

When behind ngrok or another proxy, the SDK needs to know the public URL:

import os

# Option 1: Environment variable
os.environ['SWML_PROXY_URL_BASE'] = 'https://abc123.ngrok.io'

# Option 2: Auto-detection from X-Forwarded headers
# The SDK automatically detects proxy from request headers

Development Workflow

1. Code

Write/modify your agent code.

2. Test Locally

  • swaig-test my_agent.py --dump-swml
  • swaig-test my_agent.py --exec function_name --param value

3. Run Server

python my_agent.py

4. Expose Publicly

ngrok http 3000

5. Test with SignalWire

Point phone number to ngrok URL and make test call.

Debug Mode

Enable debug logging:

import logging
logging.basicConfig(level=logging.DEBUG)

agent = MyAgent()
agent.run()

Or via environment variable:

export SIGNALWIRE_LOG_MODE=default
python my_agent.py

Hot Reloading

For automatic reloading during development, use uvicorn directly:

# Install uvicorn with reload support
pip install uvicorn[standard]

# Run with auto-reload
uvicorn my_agent:agent._app --reload --host 0.0.0.0 --port 3000

Or create a development script:

# dev.py
from my_agent import MyAgent

agent = MyAgent()
app = agent._app # Expose the ASGI app for uvicorn

Then run:

uvicorn dev:app --reload --port 3000

Serving Static Files

Use AgentServer.serve_static_files() to serve static files alongside your agents. This is useful for web dashboards, documentation, or any static content:

from signalwire_agents import AgentServer
from pathlib import Path

# Create your agents
from my_agents import SupportAgent, SalesAgent

HOST = "0.0.0.0"
PORT = 3000

server = AgentServer(host=HOST, port=PORT)
server.register(SupportAgent(), "/support")
server.register(SalesAgent(), "/sales")

# Serve static files from web directory
web_dir = Path(__file__).parent / "web"
if web_dir.exists():
server.serve_static_files(str(web_dir))

server.run()

Directory Structure:

my_project/
├── server.py
├── my_agents.py
└── web/
├── index.html
├── styles.css
└── app.js

Key Points:

  • Use server.serve_static_files(directory) to serve static files
  • Agent routes always take priority over static files
  • Requests to / serve index.html from the static directory
  • Both /support and /support/ work correctly with agents

Route Priority:

RouteHandler
/supportSupportAgent
/salesSalesAgent
/healthAgentServer health check
/*Static files (fallback)

Common Development Issues

IssueSolution
Port already in useUse different port: agent.run(port=8080)
401 UnauthorizedCheck SWML_BASIC_AUTH_* env vars
Functions not foundVerify function registration
SWML URL wrongSet SWML_PROXY_URL_BASE for ngrok
Connection refusedEnsure agent is running on correct port
Static files not foundCheck web_dir.exists() and path is correct