By Complexity

View as Markdown

Examples by Complexity

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

Beginner Examples

Hello World Agent

The simplest possible agent:

1#!/usr/bin/env python3
2## hello_world_agent.py - Simplest possible agent
3from signalwire_agents import AgentBase
4
5agent = AgentBase(name="hello", route="/hello")
6agent.prompt_add_section("Role", "Say hello and have a friendly conversation.")
7agent.add_language("English", "en-US", "rime.spore")
8
9if __name__ == "__main__":
10 agent.run()

FAQ Agent

Agent that answers questions from a knowledge base:

1#!/usr/bin/env python3
2## faq_agent.py - Agent with knowledge base
3from signalwire_agents import AgentBase
4
5agent = AgentBase(name="faq", route="/faq")
6agent.prompt_add_section("Role", "Answer questions about our company.")
7agent.prompt_add_section("Information", """
8Our hours are Monday to Friday, 9 AM to 5 PM.
9We are located at 123 Main Street.
10Contact us at support@example.com.
11""")
12agent.add_language("English", "en-US", "rime.spore")
13
14if __name__ == "__main__":
15 agent.run()

Greeting Agent

Agent with a custom greeting:

1#!/usr/bin/env python3
2## greeting_agent.py - Agent with custom greeting
3from signalwire_agents import AgentBase
4
5agent = AgentBase(name="greeter", route="/greeter")
6agent.prompt_add_section("Role", "You are a friendly receptionist.")
7agent.prompt_add_section("Greeting", """
8Always start by saying: "Thank you for calling Acme Corporation. How may I help you today?"
9""")
10agent.add_language("English", "en-US", "rime.spore")
11
12if __name__ == "__main__":
13 agent.run()

Intermediate Examples

Account Lookup Agent

Agent with database lookup:

1#!/usr/bin/env python3
2## account_lookup_agent.py - Agent with database lookup
3from signalwire_agents import AgentBase
4from signalwire_agents.core.function_result import SwaigFunctionResult
5
6## Simulated database
7ACCOUNTS = {
8 "12345": {"name": "John Doe", "balance": 150.00, "status": "active"},
9 "67890": {"name": "Jane Smith", "balance": 500.00, "status": "active"},
10}
11
12agent = AgentBase(name="accounts", route="/accounts")
13agent.prompt_add_section("Role", "You help customers check their account status.")
14agent.prompt_add_section("Guidelines", """
15- Always verify the account ID before providing information
16- Be helpful and professional
17- Never share information about other accounts
18""")
19agent.add_language("English", "en-US", "rime.spore")
20
21@agent.tool(description="Look up account information by ID")
22def lookup_account(account_id: str) -> SwaigFunctionResult:
23 account = ACCOUNTS.get(account_id)
24 if account:
25 return SwaigFunctionResult(
26 f"Account for {account['name']}: Status is {account['status']}, "
27 f"balance is ${account['balance']:.2f}"
28 )
29 return SwaigFunctionResult("Account not found. Please check the ID and try again.")
30
31if __name__ == "__main__":
32 agent.run()

Appointment Scheduler

Agent that books appointments with confirmation:

1#!/usr/bin/env python3
2## appointment_scheduler_agent.py - Agent that books appointments
3from signalwire_agents import AgentBase
4from signalwire_agents.core.function_result import SwaigFunctionResult
5from datetime import datetime
6
7appointments = []
8
9agent = AgentBase(name="scheduler", route="/scheduler")
10agent.prompt_add_section("Role", "You help customers schedule appointments.")
11agent.prompt_add_section("Guidelines", """
12- Collect customer name, date, and preferred time
13- Confirm all details before booking
14- Send SMS confirmation when booking is complete
15""")
16agent.add_language("English", "en-US", "rime.spore")
17
18@agent.tool(description="Check if a time slot is available")
19def check_availability(date: str, time: str) -> SwaigFunctionResult:
20 # Check against existing appointments
21 for apt in appointments:
22 if apt["date"] == date and apt["time"] == time:
23 return SwaigFunctionResult(f"Sorry, {date} at {time} is not available.")
24 return SwaigFunctionResult(f"{date} at {time} is available.")
25
26@agent.tool(description="Book an appointment")
27def book_appointment(
28 name: str,
29 phone: str,
30 date: str,
31 time: str
32) -> SwaigFunctionResult:
33 appointments.append({
34 "name": name,
35 "phone": phone,
36 "date": date,
37 "time": time,
38 "booked_at": datetime.now().isoformat()
39 })
40 return (
41 SwaigFunctionResult(f"Appointment booked for {name} on {date} at {time}.")
42 .send_sms(
43 to_number=phone,
44 from_number="+15559876543",
45 body=f"Your appointment is confirmed for {date} at {time}."
46 )
47 )
48
49if __name__ == "__main__":
50 agent.run()

Department Router

Agent that routes calls to the right department:

1#!/usr/bin/env python3
2## department_router_agent.py - Agent that routes calls
3from signalwire_agents import AgentBase
4from signalwire_agents.core.function_result import SwaigFunctionResult
5
6DEPARTMENTS = {
7 "sales": "+15551001001",
8 "support": "+15551001002",
9 "billing": "+15551001003",
10 "hr": "+15551001004"
11}
12
13agent = AgentBase(name="router", route="/router")
14agent.prompt_add_section("Role", "You are a receptionist routing calls.")
15agent.prompt_add_section("Departments", """
16Available departments:
17
18- Sales: Product inquiries, pricing, quotes
19- Support: Technical help, troubleshooting
20- Billing: Payments, invoices, refunds
21- HR: Employment, benefits, careers
22""")
23agent.add_language("English", "en-US", "rime.spore")
24
25@agent.tool(description="Transfer to a specific department")
26def transfer_to_department(department: str) -> SwaigFunctionResult:
27 dept_lower = department.lower()
28 if dept_lower in DEPARTMENTS:
29 return (
30 SwaigFunctionResult(f"Transferring you to {department} now.")
31 .connect(DEPARTMENTS[dept_lower], final=True)
32 )
33 return SwaigFunctionResult(
34 f"I don't have a {department} department. "
35 "Available departments are: sales, support, billing, and HR."
36 )
37
38if __name__ == "__main__":
39 agent.run()

Advanced Examples

Multi-Skill Agent

Agent combining multiple skills:

1#!/usr/bin/env python3
2## multi_skill_agent.py - Agent with multiple skills
3from signalwire_agents import AgentBase
4from signalwire_agents.core.function_result import SwaigFunctionResult
5
6agent = AgentBase(name="assistant", route="/assistant")
7agent.prompt_add_section("Role", "You are a comprehensive assistant.")
8agent.prompt_add_section("Capabilities", """
9You can:
10
11- Tell the current time and date
12- Search our knowledge base
13- Look up weather information
14- Transfer to support if needed
15""")
16agent.add_language("English", "en-US", "rime.spore")
17
18## Add built-in skills
19agent.add_skill("datetime")
20agent.add_skill("native_vector_search", {
21 "index_path": "./knowledge.swsearch",
22 "tool_name": "search_kb"
23})
24
25## Custom function
26@agent.tool(description="Transfer to human support")
27def transfer_support() -> SwaigFunctionResult:
28 return (
29 SwaigFunctionResult("Connecting you to a support representative.")
30 .connect("+15551234567", final=True)
31 )
32
33if __name__ == "__main__":
34 agent.run()

Order Processing Agent

Complete order management system:

1#!/usr/bin/env python3
2## order_processing_agent.py - Complete order management system
3from signalwire_agents import AgentBase
4from signalwire_agents.core.function_result import SwaigFunctionResult
5from datetime import datetime
6import uuid
7
8## Simulated databases
9orders = {}
10products = {
11 "widget": {"price": 29.99, "stock": 100},
12 "gadget": {"price": 49.99, "stock": 50},
13 "device": {"price": 99.99, "stock": 25}
14}
15
16agent = AgentBase(name="orders", route="/orders")
17agent.prompt_add_section("Role", "You help customers with orders.")
18agent.prompt_add_section("Products", """
19Available products:
20
21- Widget: $29.99
22- Gadget: $49.99
23- Device: $99.99
24""")
25agent.prompt_add_section("Guidelines", """
26- Verify product availability before placing orders
27- Collect customer name and phone for orders
28- Confirm order details before finalizing
29- Provide order ID for tracking
30""")
31agent.add_language("English", "en-US", "rime.spore")
32agent.set_global_data({"current_order": None})
33
34@agent.tool(description="Check product availability")
35def check_product(product: str) -> SwaigFunctionResult:
36 prod = products.get(product.lower())
37 if prod:
38 return SwaigFunctionResult(
39 f"{product.title()}: ${prod['price']}, {prod['stock']} in stock."
40 )
41 return SwaigFunctionResult(f"Product '{product}' not found.")
42
43@agent.tool(description="Place an order")
44def place_order(
45 product: str,
46 quantity: int,
47 customer_name: str,
48 customer_phone: str
49) -> SwaigFunctionResult:
50 prod = products.get(product.lower())
51 if not prod:
52 return SwaigFunctionResult(f"Product '{product}' not found.")
53
54 if prod["stock"] < quantity:
55 return SwaigFunctionResult(f"Insufficient stock. Only {prod['stock']} available.")
56
57 order_id = str(uuid.uuid4())[:8].upper()
58 total = prod["price"] * quantity
59
60 orders[order_id] = {
61 "product": product,
62 "quantity": quantity,
63 "total": total,
64 "customer": customer_name,
65 "phone": customer_phone,
66 "status": "confirmed",
67 "created": datetime.now().isoformat()
68 }
69
70 prod["stock"] -= quantity
71
72 return (
73 SwaigFunctionResult(
74 f"Order {order_id} confirmed! {quantity}x {product} for ${total:.2f}."
75 )
76 .update_global_data({"last_order_id": order_id})
77 .send_sms(
78 to_number=customer_phone,
79 from_number="+15559876543",
80 body=f"Order {order_id} confirmed: {quantity}x {product}, ${total:.2f}"
81 )
82 )
83
84@agent.tool(description="Check order status")
85def order_status(order_id: str) -> SwaigFunctionResult:
86 order = orders.get(order_id.upper())
87 if order:
88 return SwaigFunctionResult(
89 f"Order {order_id}: {order['quantity']}x {order['product']}, "
90 f"${order['total']:.2f}, Status: {order['status']}"
91 )
92 return SwaigFunctionResult(f"Order {order_id} not found.")
93
94if __name__ == "__main__":
95 agent.run()

Multi-Agent Server

Server hosting multiple specialized agents:

1#!/usr/bin/env python3
2## multi_agent_server.py - Server hosting multiple agents
3from signalwire_agents import AgentBase, AgentServer
4from signalwire_agents.core.function_result import SwaigFunctionResult
5
6
7class SalesAgent(AgentBase):
8 def __init__(self):
9 super().__init__(name="sales", route="/sales")
10 self.prompt_add_section("Role", "You are a sales specialist.")
11 self.add_language("English", "en-US", "rime.spore")
12
13 @AgentBase.tool(description="Get product pricing")
14 def get_pricing(self, product: str) -> SwaigFunctionResult:
15 return SwaigFunctionResult(f"Pricing for {product}: Starting at $99.")
16
17
18class SupportAgent(AgentBase):
19 def __init__(self):
20 super().__init__(name="support", route="/support")
21 self.prompt_add_section("Role", "You are a support specialist.")
22 self.add_language("English", "en-US", "rime.spore")
23 self.add_skill("native_vector_search", {
24 "index_path": "./support_docs.swsearch"
25 })
26
27 @AgentBase.tool(description="Create support ticket")
28 def create_ticket(self, issue: str) -> SwaigFunctionResult:
29 return SwaigFunctionResult(f"Ticket created for: {issue}")
30
31
32class RouterAgent(AgentBase):
33 def __init__(self):
34 super().__init__(name="router", route="/")
35 self.prompt_add_section("Role", "Route callers to the right agent.")
36 self.add_language("English", "en-US", "rime.spore")
37
38 @AgentBase.tool(description="Transfer to sales")
39 def transfer_sales(self) -> SwaigFunctionResult:
40 return SwaigFunctionResult("Transferring to sales.").connect(
41 "https://agent.example.com/sales", final=True
42 )
43
44 @AgentBase.tool(description="Transfer to support")
45 def transfer_support(self) -> SwaigFunctionResult:
46 return SwaigFunctionResult("Transferring to support.").connect(
47 "https://agent.example.com/support", final=True
48 )
49
50
51if __name__ == "__main__":
52 server = AgentServer(host="0.0.0.0", port=8080)
53 server.register(RouterAgent())
54 server.register(SalesAgent())
55 server.register(SupportAgent())
56 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.
Code-Driven Approach

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:

1#!/usr/bin/env python3
2## code_driven_order_agent.py - Code-driven LLM architecture example
3from signalwire_agents import AgentBase
4from signalwire_agents.core.function_result import SwaigFunctionResult
5
6## Menu data lives in code, not prompts
7MENU = {
8 "tacos": {
9 "T001": {"name": "Beef Taco", "price": 3.49},
10 "T002": {"name": "Chicken Taco", "price": 3.49},
11 "T003": {"name": "Fish Taco", "price": 4.29},
12 },
13 "sides": {
14 "S001": {"name": "Chips & Salsa", "price": 2.99},
15 "S002": {"name": "Guacamole", "price": 3.49},
16 },
17 "drinks": {
18 "D001": {"name": "Soda", "price": 1.99},
19 "D002": {"name": "Iced Tea", "price": 1.99},
20 },
21 "combos": {
22 "C001": {"name": "Taco Combo", "price": 9.99,
23 "includes": ["taco", "chips", "drink"], "savings": 1.97},
24 }
25}
26
27## Aliases handle natural speech variations
28MENU_ALIASES = {
29 "D001": ["soda", "coke", "pop", "soft drink"],
30 "S001": ["chips", "chips and salsa", "nachos"],
31}
32
33TAX_RATE = 0.10
34MAX_ITEMS_PER_ADD = 10
35MAX_ORDER_VALUE = 500.00
36
37
38class OrderAgent(AgentBase):
39 def __init__(self):
40 super().__init__(name="order-agent", route="/order")
41 self.add_language("English", "en-US", "rime.spore")
42
43 # Minimal prompt - personality only, not rules
44 self.prompt_add_section("Role",
45 "You are a friendly drive-thru order taker. "
46 "Keep responses brief and natural."
47 )
48
49 # State machine controls conversation flow
50 self._setup_contexts()
51
52 # Initialize order state
53 self.set_global_data({
54 "order_state": {
55 "items": [],
56 "subtotal": 0.00,
57 "tax": 0.00,
58 "total": 0.00,
59 "item_count": 0
60 }
61 })
62
63 def _setup_contexts(self):
64 """Define state machine for conversation flow."""
65 contexts = self.define_contexts()
66 ctx = contexts.add_context("default")
67
68 # Greeting state - limited actions
69 ctx.add_step("greeting") \
70 .add_section("Task", "Welcome the customer and take their order.") \
71 .set_functions(["add_item"]) \
72 .set_valid_steps(["taking_order"])
73
74 # Order state - full ordering capabilities
75 ctx.add_step("taking_order") \
76 .add_section("Task", "Continue taking the order.") \
77 .add_bullets("Info", [
78 "Current total: $${global_data.order_state.total}",
79 "Items: ${global_data.order_state.item_count}"
80 ]) \
81 .set_functions(["add_item", "remove_item", "finalize_order"]) \
82 .set_valid_steps(["confirming"])
83
84 # Confirmation state
85 ctx.add_step("confirming") \
86 .add_section("Task", "Confirm the order with the customer.") \
87 .set_functions(["confirm_order", "add_item", "remove_item"]) \
88 .set_valid_steps(["complete"])
89
90 def _find_menu_item(self, item_name):
91 """Find item by name or alias - code handles fuzzy matching."""
92 item_lower = item_name.lower().strip()
93
94 # Check exact matches first
95 for category, items in MENU.items():
96 for sku, data in items.items():
97 if item_lower == data["name"].lower():
98 return sku, data, category
99
100 # Check aliases
101 for sku, aliases in MENU_ALIASES.items():
102 if item_lower in [a.lower() for a in aliases]:
103 for category, items in MENU.items():
104 if sku in items:
105 return sku, items[sku], category
106
107 return None, None, None
108
109 def _calculate_totals(self, items):
110 """Code does all math - LLM never calculates."""
111 subtotal = sum(item["price"] * item["quantity"] for item in items)
112 tax = round(subtotal * TAX_RATE, 2)
113 total = round(subtotal + tax, 2)
114 return subtotal, tax, total
115
116 def _check_combo_opportunity(self, items):
117 """Code detects upsells - no prompt rules needed."""
118 item_names = [i["name"].lower() for i in items]
119 has_taco = any("taco" in n for n in item_names)
120 has_chips = any("chip" in n for n in item_names)
121 has_drink = any(n in ["soda", "iced tea"] for n in item_names)
122
123 # Check if already has combo
124 if any("combo" in n for n in item_names):
125 return None
126
127 if has_taco and has_chips and has_drink:
128 return "Great news! I can upgrade you to a Taco Combo and save you $1.97!"
129 return None
130
131 @AgentBase.tool(
132 name="add_item",
133 description="Add an item to the order",
134 parameters={
135 "type": "object",
136 "properties": {
137 "item_name": {"type": "string", "description": "Name of the menu item"},
138 "quantity": {"type": "integer", "description": "How many (default 1)",
139 "minimum": 1, "maximum": 10}
140 },
141 "required": ["item_name"]
142 }
143 )
144 def add_item(self, args, raw_data):
145 """Add item - code enforces all limits and rules."""
146 item_name = args.get("item_name", "")
147 quantity = args.get("quantity", 1)
148
149 # Code enforces limits (LLM doesn't need to know)
150 if quantity > MAX_ITEMS_PER_ADD:
151 quantity = MAX_ITEMS_PER_ADD
152
153 # Get order state
154 global_data = raw_data.get("global_data", {})
155 order_state = global_data.get("order_state", {
156 "items": [], "subtotal": 0, "tax": 0, "total": 0, "item_count": 0
157 })
158
159 # Find the item (code handles fuzzy matching)
160 sku, item_data, category = self._find_menu_item(item_name)
161 if not item_data:
162 return SwaigFunctionResult(
163 f"I couldn't find '{item_name}' on the menu. "
164 "We have tacos, chips, guacamole, and drinks."
165 )
166
167 # Check order value limit
168 potential = order_state["subtotal"] + (item_data["price"] * quantity)
169 if potential > MAX_ORDER_VALUE:
170 return SwaigFunctionResult(
171 f"That would exceed our ${MAX_ORDER_VALUE:.2f} order limit."
172 )
173
174 # Add to order
175 order_state["items"].append({
176 "sku": sku,
177 "name": item_data["name"],
178 "quantity": quantity,
179 "price": item_data["price"]
180 })
181 order_state["item_count"] += quantity
182
183 # Code calculates totals (LLM never does math)
184 subtotal, tax, total = self._calculate_totals(order_state["items"])
185 order_state["subtotal"] = subtotal
186 order_state["tax"] = tax
187 order_state["total"] = total
188
189 # Build response that guides LLM behavior
190 response = f"Added {quantity}x {item_data['name']} (${item_data['price']:.2f} each)."
191
192 # Check for upsell (code decides, not LLM)
193 combo_suggestion = self._check_combo_opportunity(order_state["items"])
194 if combo_suggestion:
195 response += f"\n\n{combo_suggestion}"
196
197 # Update state and transition
198 global_data["order_state"] = order_state
199
200 result = SwaigFunctionResult(response)
201 result.update_global_data(global_data)
202 result.swml_change_step("taking_order")
203
204 # Push UI update (frontend stays in sync without LLM)
205 result.swml_user_event({
206 "type": "item_added",
207 "item": {"name": item_data["name"], "quantity": quantity,
208 "price": item_data["price"]},
209 "total": total
210 })
211
212 return result
213
214 @AgentBase.tool(
215 name="remove_item",
216 description="Remove an item from the order",
217 parameters={
218 "type": "object",
219 "properties": {
220 "item_name": {"type": "string", "description": "Item to remove"},
221 "quantity": {"type": "integer", "description": "How many (-1 for all)"}
222 },
223 "required": ["item_name"]
224 }
225 )
226 def remove_item(self, args, raw_data):
227 """Remove item - code handles all edge cases."""
228 item_name = args.get("item_name", "").lower()
229 quantity = args.get("quantity", 1)
230
231 global_data = raw_data.get("global_data", {})
232 order_state = global_data.get("order_state", {"items": []})
233
234 # Find matching item in order
235 for i, item in enumerate(order_state["items"]):
236 if item_name in item["name"].lower():
237 if quantity == -1 or quantity >= item["quantity"]:
238 removed = order_state["items"].pop(i)
239 order_state["item_count"] -= removed["quantity"]
240 else:
241 item["quantity"] -= quantity
242 order_state["item_count"] -= quantity
243
244 # Recalculate
245 subtotal, tax, total = self._calculate_totals(order_state["items"])
246 order_state["subtotal"] = subtotal
247 order_state["tax"] = tax
248 order_state["total"] = total
249
250 global_data["order_state"] = order_state
251
252 result = SwaigFunctionResult(f"Removed {item_name} from your order.")
253 result.update_global_data(global_data)
254 return result
255
256 return SwaigFunctionResult(f"I don't see {item_name} in your order.")
257
258 @AgentBase.tool(
259 name="finalize_order",
260 description="Finalize and review the order",
261 parameters={"type": "object", "properties": {}}
262 )
263 def finalize_order(self, args, raw_data):
264 """Finalize - code builds the summary."""
265 global_data = raw_data.get("global_data", {})
266 order_state = global_data.get("order_state", {})
267
268 if not order_state.get("items"):
269 return SwaigFunctionResult("Your order is empty. What can I get you?")
270
271 # Code builds accurate summary (LLM just relays it)
272 items_text = ", ".join(
273 f"{i['quantity']}x {i['name']}" for i in order_state["items"]
274 )
275
276 result = SwaigFunctionResult(
277 f"Your order: {items_text}. "
278 f"Total is ${order_state['total']:.2f} including tax. "
279 "Does that look correct?"
280 )
281 result.swml_change_step("confirming")
282 return result
283
284 @AgentBase.tool(
285 name="confirm_order",
286 description="Confirm the order is complete",
287 parameters={"type": "object", "properties": {}}
288 )
289 def confirm_order(self, args, raw_data):
290 """Confirm - code handles completion."""
291 global_data = raw_data.get("global_data", {})
292 order_state = global_data.get("order_state", {})
293
294 # Generate order number
295 import random
296 order_num = random.randint(100, 999)
297
298 result = SwaigFunctionResult(
299 f"Order #{order_num} confirmed! "
300 f"Your total is ${order_state['total']:.2f}. "
301 "Please pull forward. Thank you!"
302 )
303 result.swml_change_step("complete")
304
305 # Final UI update
306 result.swml_user_event({
307 "type": "order_complete",
308 "order_number": order_num,
309 "total": order_state["total"]
310 })
311
312 return result
313
314
315if __name__ == "__main__":
316 agent = OrderAgent()
317 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