Skip to main content

By Complexity

Examples by Complexity

Summary: Progressive examples from simple to advanced, helping you build increasingly sophisticated agents.

Beginner Examples

Hello World Agent

The simplest possible agent:

#!/usr/bin/env python3
## hello_world_agent.py - Simplest possible agent
from signalwire_agents import AgentBase

agent = AgentBase(name="hello", route="/hello")
agent.prompt_add_section("Role", "Say hello and have a friendly conversation.")
agent.add_language("English", "en-US", "rime.spore")

if __name__ == "__main__":
agent.run()

FAQ Agent

Agent that answers questions from a knowledge base:

#!/usr/bin/env python3
## faq_agent.py - Agent with knowledge base
from signalwire_agents import AgentBase

agent = AgentBase(name="faq", route="/faq")
agent.prompt_add_section("Role", "Answer questions about our company.")
agent.prompt_add_section("Information", """
Our hours are Monday to Friday, 9 AM to 5 PM.
We are located at 123 Main Street.
Contact us at support@example.com.
""")
agent.add_language("English", "en-US", "rime.spore")

if __name__ == "__main__":
agent.run()

Greeting Agent

Agent with a custom greeting:

#!/usr/bin/env python3
## greeting_agent.py - Agent with custom greeting
from signalwire_agents import AgentBase

agent = AgentBase(name="greeter", route="/greeter")
agent.prompt_add_section("Role", "You are a friendly receptionist.")
agent.prompt_add_section("Greeting", """
Always start by saying: "Thank you for calling Acme Corporation. How may I help you today?"
""")
agent.add_language("English", "en-US", "rime.spore")

if __name__ == "__main__":
agent.run()

Intermediate Examples

Account Lookup Agent

Agent with database lookup:

#!/usr/bin/env python3
## account_lookup_agent.py - Agent with database lookup
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult

## Simulated database
ACCOUNTS = {
"12345": {"name": "John Doe", "balance": 150.00, "status": "active"},
"67890": {"name": "Jane Smith", "balance": 500.00, "status": "active"},
}

agent = AgentBase(name="accounts", route="/accounts")
agent.prompt_add_section("Role", "You help customers check their account status.")
agent.prompt_add_section("Guidelines", """
- Always verify the account ID before providing information
- Be helpful and professional
- Never share information about other accounts
""")
agent.add_language("English", "en-US", "rime.spore")

@agent.tool(description="Look up account information by ID")
def lookup_account(account_id: str) -> SwaigFunctionResult:
account = ACCOUNTS.get(account_id)
if account:
return SwaigFunctionResult(
f"Account for {account['name']}: Status is {account['status']}, "
f"balance is ${account['balance']:.2f}"
)
return SwaigFunctionResult("Account not found. Please check the ID and try again.")

if __name__ == "__main__":
agent.run()

Appointment Scheduler

Agent that books appointments with confirmation:

#!/usr/bin/env python3
## appointment_scheduler_agent.py - Agent that books appointments
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult
from datetime import datetime

appointments = []

agent = AgentBase(name="scheduler", route="/scheduler")
agent.prompt_add_section("Role", "You help customers schedule appointments.")
agent.prompt_add_section("Guidelines", """
- Collect customer name, date, and preferred time
- Confirm all details before booking
- Send SMS confirmation when booking is complete
""")
agent.add_language("English", "en-US", "rime.spore")

@agent.tool(description="Check if a time slot is available")
def check_availability(date: str, time: str) -> SwaigFunctionResult:
# Check against existing appointments
for apt in appointments:
if apt["date"] == date and apt["time"] == time:
return SwaigFunctionResult(f"Sorry, {date} at {time} is not available.")
return SwaigFunctionResult(f"{date} at {time} is available.")

@agent.tool(description="Book an appointment")
def book_appointment(
name: str,
phone: str,
date: str,
time: str
) -> SwaigFunctionResult:
appointments.append({
"name": name,
"phone": phone,
"date": date,
"time": time,
"booked_at": datetime.now().isoformat()
})
return (
SwaigFunctionResult(f"Appointment booked for {name} on {date} at {time}.")
.send_sms(
to_number=phone,
from_number="+15559876543",
body=f"Your appointment is confirmed for {date} at {time}."
)
)

if __name__ == "__main__":
agent.run()

Department Router

Agent that routes calls to the right department:

#!/usr/bin/env python3
## department_router_agent.py - Agent that routes calls
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult

DEPARTMENTS = {
"sales": "+15551001001",
"support": "+15551001002",
"billing": "+15551001003",
"hr": "+15551001004"
}

agent = AgentBase(name="router", route="/router")
agent.prompt_add_section("Role", "You are a receptionist routing calls.")
agent.prompt_add_section("Departments", """
Available departments:

- Sales: Product inquiries, pricing, quotes
- Support: Technical help, troubleshooting
- Billing: Payments, invoices, refunds
- HR: Employment, benefits, careers
""")
agent.add_language("English", "en-US", "rime.spore")

@agent.tool(description="Transfer to a specific department")
def transfer_to_department(department: str) -> SwaigFunctionResult:
dept_lower = department.lower()
if dept_lower in DEPARTMENTS:
return (
SwaigFunctionResult(f"Transferring you to {department} now.")
.connect(DEPARTMENTS[dept_lower], final=True)
)
return SwaigFunctionResult(
f"I don't have a {department} department. "
"Available departments are: sales, support, billing, and HR."
)

if __name__ == "__main__":
agent.run()

Advanced Examples

Multi-Skill Agent

Agent combining multiple skills:

#!/usr/bin/env python3
## multi_skill_agent.py - Agent with multiple skills
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult

agent = AgentBase(name="assistant", route="/assistant")
agent.prompt_add_section("Role", "You are a comprehensive assistant.")
agent.prompt_add_section("Capabilities", """
You can:

- Tell the current time and date
- Search our knowledge base
- Look up weather information
- Transfer to support if needed
""")
agent.add_language("English", "en-US", "rime.spore")

## Add built-in skills
agent.add_skill("datetime")
agent.add_skill("native_vector_search", {
"index_path": "./knowledge.swsearch",
"tool_name": "search_kb"
})

## Custom function
@agent.tool(description="Transfer to human support")
def transfer_support() -> SwaigFunctionResult:
return (
SwaigFunctionResult("Connecting you to a support representative.")
.connect("+15551234567", final=True)
)

if __name__ == "__main__":
agent.run()

Order Processing Agent

Complete order management system:

#!/usr/bin/env python3
## order_processing_agent.py - Complete order management system
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult
from datetime import datetime
import uuid

## Simulated databases
orders = {}
products = {
"widget": {"price": 29.99, "stock": 100},
"gadget": {"price": 49.99, "stock": 50},
"device": {"price": 99.99, "stock": 25}
}

agent = AgentBase(name="orders", route="/orders")
agent.prompt_add_section("Role", "You help customers with orders.")
agent.prompt_add_section("Products", """
Available products:

- Widget: $29.99
- Gadget: $49.99
- Device: $99.99
""")
agent.prompt_add_section("Guidelines", """
- Verify product availability before placing orders
- Collect customer name and phone for orders
- Confirm order details before finalizing
- Provide order ID for tracking
""")
agent.add_language("English", "en-US", "rime.spore")
agent.set_global_data({"current_order": None})

@agent.tool(description="Check product availability")
def check_product(product: str) -> SwaigFunctionResult:
prod = products.get(product.lower())
if prod:
return SwaigFunctionResult(
f"{product.title()}: ${prod['price']}, {prod['stock']} in stock."
)
return SwaigFunctionResult(f"Product '{product}' not found.")

@agent.tool(description="Place an order")
def place_order(
product: str,
quantity: int,
customer_name: str,
customer_phone: str
) -> SwaigFunctionResult:
prod = products.get(product.lower())
if not prod:
return SwaigFunctionResult(f"Product '{product}' not found.")

if prod["stock"] < quantity:
return SwaigFunctionResult(f"Insufficient stock. Only {prod['stock']} available.")

order_id = str(uuid.uuid4())[:8].upper()
total = prod["price"] * quantity

orders[order_id] = {
"product": product,
"quantity": quantity,
"total": total,
"customer": customer_name,
"phone": customer_phone,
"status": "confirmed",
"created": datetime.now().isoformat()
}

prod["stock"] -= quantity

return (
SwaigFunctionResult(
f"Order {order_id} confirmed! {quantity}x {product} for ${total:.2f}."
)
.update_global_data({"last_order_id": order_id})
.send_sms(
to_number=customer_phone,
from_number="+15559876543",
body=f"Order {order_id} confirmed: {quantity}x {product}, ${total:.2f}"
)
)

@agent.tool(description="Check order status")
def order_status(order_id: str) -> SwaigFunctionResult:
order = orders.get(order_id.upper())
if order:
return SwaigFunctionResult(
f"Order {order_id}: {order['quantity']}x {order['product']}, "
f"${order['total']:.2f}, Status: {order['status']}"
)
return SwaigFunctionResult(f"Order {order_id} not found.")

if __name__ == "__main__":
agent.run()

Multi-Agent Server

Server hosting multiple specialized agents:

#!/usr/bin/env python3
## multi_agent_server.py - Server hosting multiple agents
from signalwire_agents import AgentBase, AgentServer
from signalwire_agents.core.function_result import SwaigFunctionResult


class SalesAgent(AgentBase):
def __init__(self):
super().__init__(name="sales", route="/sales")
self.prompt_add_section("Role", "You are a sales specialist.")
self.add_language("English", "en-US", "rime.spore")

@AgentBase.tool(description="Get product pricing")
def get_pricing(self, product: str) -> SwaigFunctionResult:
return SwaigFunctionResult(f"Pricing for {product}: Starting at $99.")


class SupportAgent(AgentBase):
def __init__(self):
super().__init__(name="support", route="/support")
self.prompt_add_section("Role", "You are a support specialist.")
self.add_language("English", "en-US", "rime.spore")
self.add_skill("native_vector_search", {
"index_path": "./support_docs.swsearch"
})

@AgentBase.tool(description="Create support ticket")
def create_ticket(self, issue: str) -> SwaigFunctionResult:
return SwaigFunctionResult(f"Ticket created for: {issue}")


class RouterAgent(AgentBase):
def __init__(self):
super().__init__(name="router", route="/")
self.prompt_add_section("Role", "Route callers to the right agent.")
self.add_language("English", "en-US", "rime.spore")

@AgentBase.tool(description="Transfer to sales")
def transfer_sales(self) -> SwaigFunctionResult:
return SwaigFunctionResult("Transferring to sales.").connect(
"https://agent.example.com/sales", final=True
)

@AgentBase.tool(description="Transfer to support")
def transfer_support(self) -> SwaigFunctionResult:
return SwaigFunctionResult("Transferring to support.").connect(
"https://agent.example.com/support", final=True
)


if __name__ == "__main__":
server = AgentServer(host="0.0.0.0", port=8080)
server.register(RouterAgent())
server.register(SalesAgent())
server.register(SupportAgent())
server.run()

Expert Examples

Code-Driven LLM Architecture

The most robust agents use code-driven architecture where business logic lives in SWAIG functions, not prompts. The LLM becomes a natural language translator while code handles all validation, state, and business rules.

┌─────────────────────────────────────────────────────────────┐
│ Code-Driven Approach │
│ │
│ User ──► LLM ──► SWAIG Function ──► Response to LLM │
│ │ │
│ ▼ │
│ Code enforces: │
│ • Business rules │
│ • State management │
│ • Calculations │
│ • Validation │
│ • UI updates │
│ │
│ Advantage: LLM only translates intent, code does the rest │
└─────────────────────────────────────────────────────────────┘

Core principles:

Traditional ApproachCode-Driven Approach
Rules in promptsRules in functions
LLM does mathCode does math
LLM tracks stateGlobal data tracks state
Hope LLM follows rulesCode enforces rules

Order-Taking Agent (Code-Driven)

Complete example demonstrating code-driven patterns:

#!/usr/bin/env python3
## code_driven_order_agent.py - Code-driven LLM architecture example
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult

## Menu data lives in code, not prompts
MENU = {
"tacos": {
"T001": {"name": "Beef Taco", "price": 3.49},
"T002": {"name": "Chicken Taco", "price": 3.49},
"T003": {"name": "Fish Taco", "price": 4.29},
},
"sides": {
"S001": {"name": "Chips & Salsa", "price": 2.99},
"S002": {"name": "Guacamole", "price": 3.49},
},
"drinks": {
"D001": {"name": "Soda", "price": 1.99},
"D002": {"name": "Iced Tea", "price": 1.99},
},
"combos": {
"C001": {"name": "Taco Combo", "price": 9.99,
"includes": ["taco", "chips", "drink"], "savings": 1.97},
}
}

## Aliases handle natural speech variations
MENU_ALIASES = {
"D001": ["soda", "coke", "pop", "soft drink"],
"S001": ["chips", "chips and salsa", "nachos"],
}

TAX_RATE = 0.10
MAX_ITEMS_PER_ADD = 10
MAX_ORDER_VALUE = 500.00


class OrderAgent(AgentBase):
def __init__(self):
super().__init__(name="order-agent", route="/order")
self.add_language("English", "en-US", "rime.spore")

# Minimal prompt - personality only, not rules
self.prompt_add_section("Role",
"You are a friendly drive-thru order taker. "
"Keep responses brief and natural."
)

# State machine controls conversation flow
self._setup_contexts()

# Initialize order state
self.set_global_data({
"order_state": {
"items": [],
"subtotal": 0.00,
"tax": 0.00,
"total": 0.00,
"item_count": 0
}
})

def _setup_contexts(self):
"""Define state machine for conversation flow."""
contexts = self.define_contexts()
ctx = contexts.add_context("default")

# Greeting state - limited actions
ctx.add_step("greeting") \
.add_section("Task", "Welcome the customer and take their order.") \
.set_functions(["add_item"]) \
.set_valid_steps(["taking_order"])

# Order state - full ordering capabilities
ctx.add_step("taking_order") \
.add_section("Task", "Continue taking the order.") \
.add_bullets("Info", [
"Current total: $${global_data.order_state.total}",
"Items: ${global_data.order_state.item_count}"
]) \
.set_functions(["add_item", "remove_item", "finalize_order"]) \
.set_valid_steps(["confirming"])

# Confirmation state
ctx.add_step("confirming") \
.add_section("Task", "Confirm the order with the customer.") \
.set_functions(["confirm_order", "add_item", "remove_item"]) \
.set_valid_steps(["complete"])

def _find_menu_item(self, item_name):
"""Find item by name or alias - code handles fuzzy matching."""
item_lower = item_name.lower().strip()

# Check exact matches first
for category, items in MENU.items():
for sku, data in items.items():
if item_lower == data["name"].lower():
return sku, data, category

# Check aliases
for sku, aliases in MENU_ALIASES.items():
if item_lower in [a.lower() for a in aliases]:
for category, items in MENU.items():
if sku in items:
return sku, items[sku], category

return None, None, None

def _calculate_totals(self, items):
"""Code does all math - LLM never calculates."""
subtotal = sum(item["price"] * item["quantity"] for item in items)
tax = round(subtotal * TAX_RATE, 2)
total = round(subtotal + tax, 2)
return subtotal, tax, total

def _check_combo_opportunity(self, items):
"""Code detects upsells - no prompt rules needed."""
item_names = [i["name"].lower() for i in items]
has_taco = any("taco" in n for n in item_names)
has_chips = any("chip" in n for n in item_names)
has_drink = any(n in ["soda", "iced tea"] for n in item_names)

# Check if already has combo
if any("combo" in n for n in item_names):
return None

if has_taco and has_chips and has_drink:
return "Great news! I can upgrade you to a Taco Combo and save you $1.97!"
return None

@AgentBase.tool(
name="add_item",
description="Add an item to the order",
parameters={
"type": "object",
"properties": {
"item_name": {"type": "string", "description": "Name of the menu item"},
"quantity": {"type": "integer", "description": "How many (default 1)",
"minimum": 1, "maximum": 10}
},
"required": ["item_name"]
}
)
def add_item(self, args, raw_data):
"""Add item - code enforces all limits and rules."""
item_name = args.get("item_name", "")
quantity = args.get("quantity", 1)

# Code enforces limits (LLM doesn't need to know)
if quantity > MAX_ITEMS_PER_ADD:
quantity = MAX_ITEMS_PER_ADD

# Get order state
global_data = raw_data.get("global_data", {})
order_state = global_data.get("order_state", {
"items": [], "subtotal": 0, "tax": 0, "total": 0, "item_count": 0
})

# Find the item (code handles fuzzy matching)
sku, item_data, category = self._find_menu_item(item_name)
if not item_data:
return SwaigFunctionResult(
f"I couldn't find '{item_name}' on the menu. "
"We have tacos, chips, guacamole, and drinks."
)

# Check order value limit
potential = order_state["subtotal"] + (item_data["price"] * quantity)
if potential > MAX_ORDER_VALUE:
return SwaigFunctionResult(
f"That would exceed our ${MAX_ORDER_VALUE:.2f} order limit."
)

# Add to order
order_state["items"].append({
"sku": sku,
"name": item_data["name"],
"quantity": quantity,
"price": item_data["price"]
})
order_state["item_count"] += quantity

# Code calculates totals (LLM never does math)
subtotal, tax, total = self._calculate_totals(order_state["items"])
order_state["subtotal"] = subtotal
order_state["tax"] = tax
order_state["total"] = total

# Build response that guides LLM behavior
response = f"Added {quantity}x {item_data['name']} (${item_data['price']:.2f} each)."

# Check for upsell (code decides, not LLM)
combo_suggestion = self._check_combo_opportunity(order_state["items"])
if combo_suggestion:
response += f"\n\n{combo_suggestion}"

# Update state and transition
global_data["order_state"] = order_state

result = SwaigFunctionResult(response)
result.update_global_data(global_data)
result.swml_change_step("taking_order")

# Push UI update (frontend stays in sync without LLM)
result.swml_user_event({
"type": "item_added",
"item": {"name": item_data["name"], "quantity": quantity,
"price": item_data["price"]},
"total": total
})

return result

@AgentBase.tool(
name="remove_item",
description="Remove an item from the order",
parameters={
"type": "object",
"properties": {
"item_name": {"type": "string", "description": "Item to remove"},
"quantity": {"type": "integer", "description": "How many (-1 for all)"}
},
"required": ["item_name"]
}
)
def remove_item(self, args, raw_data):
"""Remove item - code handles all edge cases."""
item_name = args.get("item_name", "").lower()
quantity = args.get("quantity", 1)

global_data = raw_data.get("global_data", {})
order_state = global_data.get("order_state", {"items": []})

# Find matching item in order
for i, item in enumerate(order_state["items"]):
if item_name in item["name"].lower():
if quantity == -1 or quantity >= item["quantity"]:
removed = order_state["items"].pop(i)
order_state["item_count"] -= removed["quantity"]
else:
item["quantity"] -= quantity
order_state["item_count"] -= quantity

# Recalculate
subtotal, tax, total = self._calculate_totals(order_state["items"])
order_state["subtotal"] = subtotal
order_state["tax"] = tax
order_state["total"] = total

global_data["order_state"] = order_state

result = SwaigFunctionResult(f"Removed {item_name} from your order.")
result.update_global_data(global_data)
return result

return SwaigFunctionResult(f"I don't see {item_name} in your order.")

@AgentBase.tool(
name="finalize_order",
description="Finalize and review the order",
parameters={"type": "object", "properties": {}}
)
def finalize_order(self, args, raw_data):
"""Finalize - code builds the summary."""
global_data = raw_data.get("global_data", {})
order_state = global_data.get("order_state", {})

if not order_state.get("items"):
return SwaigFunctionResult("Your order is empty. What can I get you?")

# Code builds accurate summary (LLM just relays it)
items_text = ", ".join(
f"{i['quantity']}x {i['name']}" for i in order_state["items"]
)

result = SwaigFunctionResult(
f"Your order: {items_text}. "
f"Total is ${order_state['total']:.2f} including tax. "
"Does that look correct?"
)
result.swml_change_step("confirming")
return result

@AgentBase.tool(
name="confirm_order",
description="Confirm the order is complete",
parameters={"type": "object", "properties": {}}
)
def confirm_order(self, args, raw_data):
"""Confirm - code handles completion."""
global_data = raw_data.get("global_data", {})
order_state = global_data.get("order_state", {})

# Generate order number
import random
order_num = random.randint(100, 999)

result = SwaigFunctionResult(
f"Order #{order_num} confirmed! "
f"Your total is ${order_state['total']:.2f}. "
"Please pull forward. Thank you!"
)
result.swml_change_step("complete")

# Final UI update
result.swml_user_event({
"type": "order_complete",
"order_number": order_num,
"total": order_state["total"]
})

return result


if __name__ == "__main__":
agent = OrderAgent()
agent.run()

Key patterns demonstrated:

  1. Response-guided behavior: Functions return text that guides LLM responses. The combo upsell suggestion appears in the response, so the LLM naturally offers it.

  2. Code-enforced limits: MAX_ITEMS_PER_ADD and MAX_ORDER_VALUE are enforced in code. The LLM cannot bypass them.

  3. State machine control: set_functions() restricts what the LLM can do in each state. Impossible actions are literally unavailable.

  4. Dynamic prompt injection: ${global_data.order_state.total} injects current state into prompts without LLM tracking.

  5. UI synchronization: swml_user_event() pushes updates to frontends in real-time.

  6. Fuzzy input handling: _find_menu_item() handles variations like "coke" → "Soda" without prompt rules.

Complexity Progression

Beginner

  1. Create basic agent with prompt
  2. Add language configuration
  3. Test with swaig-test

Intermediate

  1. Add SWAIG functions
  2. Use global data for state
  3. Add skills
  4. Implement call transfers

Advanced

  1. Use DataMap for API integration
  2. Implement context workflows
  3. Build multi-agent systems
  4. Deploy to production

Expert

  1. Code-driven LLM architecture
  2. State machine conversation control
  3. Response-guided LLM behavior
  4. Real-time UI synchronization