State Management and Persistence
Based automatically persists variables across conversation turns, allowing you to maintain context throughout a multi-turn conversation. Understanding how state works is essential for building stateful agents.
The state Dictionary
The state dictionary is the primary way to store and retrieve data that should persist across conversation turns. It’s automatically saved and restored between interactions.
Usage:
# Initialize state at the start of your flow
state = {}
# Store user information as you collect it
state["user_name"] = "John"
state["preferences"] = {"language": "en", "notifications": True}
state["order_items"] = []
# Add items to state throughout the conversation
state["order_items"].append({"item": "Taco", "quantity": 2})
# Access state later in the flow
total_items = len(state["order_items"])
say(f"You have {total_items} items in your cart.", exact=True)
Variable Persistence Example
Here’s a complete example showing how variables persist across conversation turns:
# First turn: Initialize and collect data
state = {}
say("Welcome! Let me help you place an order.")
loop:
response = talk("What would you like to order?", True)
until "user provides their order":
order = response.ask(
question="Extract the items the user wants to order",
example={"items": [{"name": "burger", "quantity": 1}]}
)
state["order"] = order
state["order_step"] = "collecting_details"
print(f"Order saved to state: {state['order']}")
# On subsequent turns, the state is automatically restored
# You can access state["order"] and continue from where you left off
Variables defined at the top level of your Based code (like state = {}) are automatically persisted across conversation turns. The session maintains the complete execution state, so your agent can pick up right where it left off.
Pre-populated State for Voice Calls
When your Based agent is deployed for voice, the state dictionary is automatically pre-populated with call metadata. This gives you immediate access to caller information without needing to ask for it.
Inbound Voice Calls
For inbound calls, state is pre-populated with Twilio call data:
# Example state for an inbound voice call
state = {
# Caller information
'From': '+14154650216',
'Caller': '+14154650216',
'CallerCity': 'SAN FRANCISCO',
'CallerState': 'CA',
'CallerZip': '94904',
'CallerCountry': 'US',
# Called number information
'To': '+14158738252',
'Called': '+14158738252',
'ToCity': 'POINT REYES STATION',
'ToState': 'CA',
'ToZip': '94956',
'ToCountry': 'US',
'CalledCity': 'POINT REYES STATION',
'CalledState': 'CA',
'CalledZip': '94956',
'CalledCountry': 'US',
# Call metadata
'Direction': 'inbound',
'CallStatus': 'ringing',
'CallSid': 'CAe64d540d7f8d465128c3e128d4cfb6d8',
'AccountSid': 'AC607f40827a8fce6eb9b4d9d67adbf425',
'ApiVersion': '2010-04-01',
'StirVerstat': 'TN-Validation-Passed-A',
# Brainbase metadata
'version': 'v2',
'deploymentId': 'deploy_a05e0b20-87ed-440b-9cd4-0427cc812c41',
'flowId': 'flow_86414fd8-f0b9-42d8-8fdf-e6d13daeec48',
'workerId': 'worker_5e864909-61c0-4785-8622-3af76cc58783',
'teamId': '581fdb69-309b-4e95-aa78-315d6a0ad0db',
'phoneNumber': '+14158738252'
}
You can use this data to personalize the conversation:
# Access caller information directly from state
caller_city = state.get('CallerCity', 'your area')
caller_number = state.get('From', '')
say(f"Thanks for calling from {caller_city}!", exact=True)
# Use caller ID for lookups
customer = lookup_customer_by_phone(caller_number)
if customer:
say(f"Welcome back, {customer['name']}!", exact=True)
Outbound Voice Calls
For outbound calls, state includes all the same call metadata plus an outbound_data field containing the data that triggered the call:
# Example state for an outbound voice call
state = {
# Standard call metadata (same as inbound)
'Direction': 'outbound',
'From': '+14158738252',
'To': '+14154650216',
'CallStatus': 'in-progress',
# ... other Twilio fields ...
# Custom data that triggered the call
'outbound_data': {
'first_name': 'John',
'last_name': 'Smith',
'appointment_date': '2024-03-15',
'appointment_time': '2:30 PM',
'doctor_name': 'Dr. Johnson'
# ... any other data you included when initiating the call
}
}
Use outbound_data to personalize outbound calls:
# Access the data that triggered this outbound call
data = state.get('outbound_data', {})
first_name = data.get('first_name', 'there')
appointment_date = data.get('appointment_date', '')
appointment_time = data.get('appointment_time', '')
say(f"Hi {first_name}, this is a reminder about your appointment on {appointment_date} at {appointment_time}.", exact=True)
The outbound_data field contains whatever data you pass when initiating the outbound call through the API or trigger. This allows you to include any context needed for the conversation, such as customer details, appointment information, order numbers, etc.