Local Development

View as Markdown

Deployment

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

1from signalwire_agents import AgentBase
2
3class MyAgent(AgentBase):
4 def __init__(self):
5 super().__init__(name="my-agent")
6 self.add_language("English", "en-US", "rime.spore")
7 self.prompt_add_section("Role", "You are a helpful assistant.")
8
9if __name__ == "__main__":
10 agent = MyAgent()
11 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:

1from signalwire_agents import AgentBase
2
3
4class MyAgent(AgentBase):
5 def __init__(self):
6 super().__init__(name="my-agent")
7 self.add_language("English", "en-US", "rime.spore")
8 self.prompt_add_section("Role", "You are a helpful assistant.")
9
10
11if __name__ == "__main__":
12 agent = MyAgent()
13 agent.run() # Starts on http://localhost:3000

Server Configuration

Custom Host and Port

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

Using serve() Directly

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

1# Development server
2agent.serve(host="127.0.0.1", port=3000)
3
4# Listen on all interfaces
5agent.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:

1import os
2
3# Option 1: Environment variable
4os.environ['SWML_PROXY_URL_BASE'] = 'https://abc123.ngrok.io'
5
6# Option 2: Auto-detection from X-Forwarded headers
7# 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:

1import logging
2logging.basicConfig(level=logging.DEBUG)
3
4agent = MyAgent()
5agent.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:

1# dev.py
2from my_agent import MyAgent
3
4agent = MyAgent()
5app = 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:

1from signalwire_agents import AgentServer
2from pathlib import Path
3
4# Create your agents
5from my_agents import SupportAgent, SalesAgent
6
7HOST = "0.0.0.0"
8PORT = 3000
9
10server = AgentServer(host=HOST, port=PORT)
11server.register(SupportAgent(), "/support")
12server.register(SalesAgent(), "/sales")
13
14# Serve static files from web directory
15web_dir = Path(__file__).parent / "web"
16if web_dir.exists():
17 server.serve_static_files(str(web_dir))
18
19server.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