| Duration | 1.5 hours |
| Day | 4 of 5 |
Learning Objectives
By the end of this module, students will be able to:
- Store and retrieve per-call state
- Use global data for shared information
- Implement session persistence patterns
- Pass state between function calls
Topics
1. State in Voice AI (15 min)
The Challenge
Each function call is stateless - how do you remember:
- Customer’s name from earlier
- Items they mentioned
- Progress through a workflow
State Types
| Type | Scope | Persistence |
|---|---|---|
| Global Data | All calls | Agent lifetime |
| Call Metadata | Single call | Call duration |
| Function State | Single function | Function execution |
2. Global Data (25 min)
Setting Global Data
agent.set_global_data({
"company": "TechCorp",
"hours": "9 AM to 5 PM",
"support_email": "help@techcorp.com"
})
Accessing in Functions
@agent.tool(description="Get company info")
def get_company_info(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
data = agent.get_global_data()
return SwaigFunctionResult(
f"We are {data['company']}, open {data['hours']}."
)
Dynamic Global Data
class MyAgent(AgentBase):
def __init__(self):
super().__init__(name="my-agent")
# Update based on time
from datetime import datetime
hour = datetime.now().hour
self.set_global_data({
"greeting": "Good morning" if hour < 12 else "Good afternoon",
"is_business_hours": 9 <= hour < 17
})
3. Call Metadata (25 min)
Setting Metadata
Use the set_meta_data action:
@agent.tool(description="Store customer name")
def store_name(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
name = args.get("name", "")
return (
SwaigFunctionResult(f"Nice to meet you, {name}!")
.update_global_data( {"customer_name": name})
)
Accessing Metadata
Metadata is passed in raw_data to subsequent functions:
@agent.tool(description="Personalized greeting")
def greet_customer(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
raw_data = raw_data or {}
global_data = raw_data.get("global_data", {})
name = global_data.get("customer_name", "there")
return SwaigFunctionResult(f"Hello again, {name}!")
Building Up State
@agent.tool(description="Add item to cart")
def add_to_cart(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
item = args.get("item", "")
raw_data = raw_data or {}
global_data = raw_data.get("global_data", {})
cart = global_data.get("cart", [])
cart.append(item)
return (
SwaigFunctionResult(f"Added {item}. You have {len(cart)} items.")
.update_global_data( {"cart": cart})
)
4. State Patterns (20 min)
Pattern: Customer Context
class ContextAwareAgent(AgentBase):
def __init__(self):
super().__init__(name="context-agent")
self._setup_functions()
def _setup_functions(self):
@self.tool(description="Identify the customer")
def identify_customer(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
phone = args.get("phone", "")
# Look up customer
customer = lookup_customer_by_phone(phone)
if customer:
return (
SwaigFunctionResult(
f"Hello {customer['name']}! How can I help?"
)
.update_global_data( {
"customer_id": customer["id"],
"customer_name": customer["name"],
"customer_tier": customer["tier"]
})
)
return SwaigFunctionResult("I don't recognize this number.")
@self.tool(description="Get customer's orders")
def get_orders(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
raw_data = raw_data or {}
global_data = raw_data.get("global_data", {})
customer_id = global_data.get("customer_id")
if not customer_id:
return SwaigFunctionResult(
"I need to identify you first. What's your phone number?"
)
orders = fetch_orders(customer_id)
return SwaigFunctionResult(f"You have {len(orders)} orders.")
Pattern: Workflow Progress
@self.tool(description="Move to next step")
def next_step(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
raw_data = raw_data or {}
global_data = raw_data.get("global_data", {})
current_step = global_data.get("workflow_step", 0)
next_step_num = current_step + 1
steps = ["name", "email", "phone", "confirm"]
if next_step_num >= len(steps):
return SwaigFunctionResult("All information collected!")
return (
SwaigFunctionResult(f"Now let's get your {steps[next_step_num]}.")
.update_global_data( {"workflow_step": next_step_num})
)
5. Best Practices (15 min)
Keep State Minimal
# Good - essential data only
.update_global_data( {
"customer_id": "12345",
"verified": True
})
# Bad - too much data
.update_global_data( {
"entire_customer_record": {...huge object...}
})
Initialize State Early
@self.tool(description="Start conversation")
def start_call(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
return (
SwaigFunctionResult("Welcome! How can I help?")
.update_global_data( {
"call_start": datetime.now().isoformat(),
"items_discussed": [],
"actions_taken": []
})
)
State Cleanup
@self.tool(description="End call")
def end_call(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
raw_data = raw_data or {}
global_data = raw_data.get("global_data", {})
# Log state for analytics
log_call_summary({
"duration": calculate_duration(global_data.get("call_start")),
"items": global_data.get("items_discussed"),
"actions": global_data.get("actions_taken")
})
return SwaigFunctionResult("Thank you for calling!")
Key Takeaways
- Global data for constants - Company info, settings
- Metadata for call state - Customer ID, progress
- set_meta_data action - Store state during call
- raw_data contains metadata - Access in functions
- Keep state minimal - Only essential data
Preparation for Lab 2.6
- Think about what state your agent needs
- Identify what should be global vs per-call
- Plan state flow through conversation
Lab Preview
In Lab 2.6, you will:
- Implement customer identification with state
- Build a shopping cart with metadata
- Track workflow progress
- Test state across function calls