Contexts and Steps Guide 🔗 ↑ TOC

Table of Contents 🔗 ↑ TOC

Overview 🔗 ↑ TOC

The Contexts and Steps system provides a structured alternative to traditional Prompt Object Model (POM) prompts in SignalWire AI agents. Instead of defining a single prompt, you create workflows with explicit steps, navigation rules, and completion criteria.

Key Benefits 🔗 ↑ TOC

When to Use Contexts vs Traditional Prompts 🔗 ↑ TOC

Use Contexts and Steps when:

Use Traditional Prompts when:

Core Concepts 🔗 ↑ TOC

Contexts 🔗 ↑ TOC

A Context represents a distinct conversation state or workflow. Think of contexts as different "modes" your agent can operate in:

Steps 🔗 ↑ TOC

A Step is a specific stage within a context. Each step defines:

The system provides fine-grained control over conversation flow:

Getting Started 🔗 ↑ TOC

Basic Single-Context Workflow 🔗 ↑ TOC

from signalwire_agents import AgentBase

class OnboardingAgent(AgentBase):
    def __init__(self):
        super().__init__(name="Onboarding Assistant", route="/onboarding")

        # Define contexts (replaces traditional prompt setup)
        contexts = self.define_contexts()

        # Single context must be named "default"
        workflow = contexts.create_context("default")

        # Step 1: Welcome
        workflow.create_step("welcome") \
            .set_text("Welcome to our service! Let's get you set up. What's your name?") \
            .set_step_criteria("User has provided their name") \
            .set_valid_steps(["collect_email"])

        # Step 2: Collect Email
        workflow.create_step("collect_email") \
            .set_text("Thanks! Now I need your email address to create your account.") \
            .set_step_criteria("Valid email address has been provided") \
            .set_valid_steps(["confirm_details"])

        # Step 3: Confirmation
        workflow.create_step("confirm_details") \
            .set_text("Perfect! Let me confirm your details before we proceed.") \
            .set_step_criteria("User has confirmed their information") \
            .set_valid_steps(["complete"])

        # Step 4: Completion
        workflow.create_step("complete") \
            .set_text("All set! Your account has been created successfully.")
            # No valid_steps = end of workflow

agent = OnboardingAgent()
agent.run()

if __name__ == "__main__":
    main()

Multi-Context Workflow 🔗 ↑ TOC

class CustomerServiceAgent(AgentBase):
    def __init__(self):
        super().__init__(name="Customer Service", route="/service")

        # Add skills for enhanced capabilities
        self.add_skill("datetime")
        self.add_skill("web_search", {
            "api_key": "your-api-key",
            "search_engine_id": "your-engine-id"
        })

        contexts = self.define_contexts()

        # Main triage context
        triage = contexts.create_context("triage")
        triage.create_step("greeting") \
            .add_section("Role", "You are a customer service representative") \
            .add_section("Goal", "Understand the customer's need and route appropriately") \
            .add_bullets([
                "Be friendly and professional",
                "Ask clarifying questions",
                "Determine the type of assistance needed"
            ]) \
            .set_step_criteria("Customer's need has been identified") \
            .set_valid_contexts(["technical", "billing", "general"])

        # Technical support context
        tech = contexts.create_context("technical")
        tech.create_step("technical_help") \
            .add_section("Role", "You are a technical support specialist") \
            .add_section("Instructions", "Help diagnose and resolve technical issues") \
            .set_functions(["web_search", "datetime"]) \
            .set_step_criteria("Issue is resolved or escalated") \
            .set_valid_contexts(["triage"])

        # Billing context (restricted functions for security)
        billing = contexts.create_context("billing")
        billing.create_step("billing_help") \
            .set_text("I'll help with your billing question. For security, please provide your account verification.") \
            .set_functions("none") \
            .set_step_criteria("Billing issue is addressed") \
            .set_valid_contexts(["triage"])

        # General inquiries context
        general = contexts.create_context("general")
        general.create_step("general_help") \
            .set_text("I'm here to help with general questions. What can I assist you with?") \
            .set_functions(["web_search", "datetime"]) \
            .set_step_criteria("Question has been answered") \
            .set_valid_contexts(["triage"])

agent = CustomerServiceAgent()
agent.run()

if __name__ == "__main__":
    main()

API Reference 🔗 ↑ TOC

ContextBuilder 🔗 ↑ TOC

The main entry point for defining contexts and steps.

# Get the builder
contexts = self.define_contexts()

# Create contexts
context = contexts.create_context(name: str) -> Context

Context 🔗 ↑ TOC

Represents a conversation context or workflow state.

class Context:
    def create_step(self, name: str) -> Step
        """Create a new step in this context"""

    def set_valid_contexts(self, contexts: List[str]) -> Context
        """Set which contexts can be accessed from this context"""

Methods 🔗 ↑ TOC

Step 🔗 ↑ TOC

Represents a single step within a context workflow.

class Step:
    # Content definition (choose one approach)
    def set_text(self, text: str) -> Step
        """Set direct text prompt (mutually exclusive with POM sections)"""

    def add_section(self, title: str, body: str = "") -> Step
        """Add a POM-style section (mutually exclusive with set_text)"""

    def add_bullets(self, bullets: List[str], numbered: bool = False) -> Step
        """Add bullets to the current or most recent section"""

    # Flow control
    def set_step_criteria(self, criteria: str) -> Step
        """Define completion criteria for this step"""

    def set_valid_steps(self, steps: List[str]) -> Step
        """Set which steps can be accessed next in same context"""

    def set_valid_contexts(self, contexts: List[str]) -> Step
        """Set which contexts can be accessed from this step"""

    # Function restrictions
    def set_functions(self, functions: Union[List[str], str]) -> Step
        """Restrict available functions ('none' or list of function names)"""

Content Methods 🔗 ↑ TOC

Option 1: Direct Text

step.set_text("Direct prompt text for the AI")

Option 2: POM-Style Sections

step.add_section("Role", "You are a helpful assistant") \
    .add_section("Instructions", "Help users with their questions") \
    .add_bullets(["Be friendly", "Ask clarifying questions"])

Note: You cannot mix set_text() with add_section() in the same step.

# Control step progression within context
step.set_valid_steps(["step1", "step2"])  # Can go to step1 or step2
step.set_valid_steps([])                   # Cannot progress (dead end)
# No set_valid_steps() call = implicit "next" step

# Control context switching
step.set_valid_contexts(["context1", "context2"])  # Can switch contexts
step.set_valid_contexts([])                         # Trapped in current context
# No set_valid_contexts() call = inherit from context level

Function Restriction Methods 🔗 ↑ TOC

# Allow specific functions only
step.set_functions(["datetime", "math"])

# Block all functions
step.set_functions("none")

# No restriction (default - all agent functions available)
# step.set_functions()  # Don't call this method

Step Navigation Rules 🔗 ↑ TOC

The set_valid_steps() method controls movement within a context:

# Explicit step list - can only go to these steps
step.set_valid_steps(["review", "edit", "cancel"])

# Empty list - dead end, cannot progress
step.set_valid_steps([])

# Not called - implicit "next" step progression
# (will go to the next step defined in the context)

Context Navigation Rules 🔗 ↑ TOC

The set_valid_contexts() method controls switching between contexts:

# Can switch to these contexts
step.set_valid_contexts(["billing", "technical", "general"])

# Trapped in current context
step.set_valid_contexts([])

# Not called - inherit from context-level settings

Context-level navigation settings are inherited by steps:

# Set at context level
context.set_valid_contexts(["main", "help"])

# All steps in this context can access main and help contexts
# unless overridden at step level
step.set_valid_contexts(["main"])  # Override - only main allowed

Complete Navigation Example 🔗 ↑ TOC

contexts = self.define_contexts()

# Main context
main = contexts.create_context("main")
main.set_valid_contexts(["help", "settings"])  # Context-level setting

main.create_step("welcome") \
    .set_text("Welcome! How can I help you?") \
    .set_valid_steps(["menu"])  # Must go to menu
    # Inherits context-level valid_contexts

main.create_step("menu") \
    .set_text("Choose an option: 1) Help 2) Settings 3) Continue") \
    .set_valid_contexts(["help", "settings", "main"])  # Override context setting
    # No valid_steps = this is a branching point

# Help context  
help_ctx = contexts.create_context("help")
help_ctx.create_step("help_info") \
    .set_text("Here's how to use the system...") \
    .set_valid_contexts(["main"])  # Can return to main

# Settings context
settings = contexts.create_context("settings")
settings.create_step("settings_menu") \
    .set_text("Choose a setting to modify...") \
    .set_valid_contexts(["main"])  # Can return to main

Function Restrictions 🔗 ↑ TOC

Control which AI tools/functions are available in each step for enhanced security and user experience.

Function Restriction Levels 🔗 ↑ TOC

# No restrictions (default) - all agent functions available
step  # Don't call set_functions()

# Allow specific functions only
step.set_functions(["datetime", "math", "web_search"])

# Block all functions
step.set_functions("none")

Security-Focused Example 🔗 ↑ TOC

class SecureBankingAgent(AgentBase):
    def __init__(self):
        super().__init__(name="Banking Assistant", route="/banking")

        # Add potentially sensitive functions
        self.add_skill("web_search", {"api_key": "key", "search_engine_id": "id"})
        self.add_skill("datetime")

        contexts = self.define_contexts()

        # Public context - full access
        public = contexts.create_context("public")
        public.create_step("welcome") \
            .set_text("Welcome to banking support. Are you an existing customer?") \
            .set_functions(["datetime", "web_search"])  # Safe functions only \
            .set_valid_contexts(["authenticated", "public"])

        # Authenticated context - restricted for security
        auth = contexts.create_context("authenticated")
        auth.create_step("account_access") \
            .set_text("I can help with your account. What do you need assistance with?") \
            .set_functions("none")  # No external functions for account data \
            .set_valid_contexts(["public"])  # Can log out

Function Access Patterns 🔗 ↑ TOC

# Progressive function access based on trust level
contexts = self.define_contexts()

# Low trust - limited functions
public = contexts.create_context("public")
public.create_step("initial_contact") \
    .set_functions(["datetime"])  # Only safe functions

# Medium trust - more functions  
verified = contexts.create_context("verified")
verified.create_step("verified_user") \
    .set_functions(["datetime", "web_search"])  # Add search capability

# High trust - full access
authenticated = contexts.create_context("authenticated")
authenticated.create_step("full_access") \
    # No set_functions() call = all functions available

Real-World Examples 🔗 ↑ TOC

Example 1: Technical Support Troubleshooting 🔗 ↑ TOC

class TechnicalSupportAgent(AgentBase):
    def __init__(self):
        super().__init__(name="Tech Support", route="/tech-support")

        # Add diagnostic tools
        self.add_skill("web_search", {"api_key": "key", "search_engine_id": "id"})
        self.add_skill("datetime")

        contexts = self.define_contexts()

        # Initial triage
        triage = contexts.create_context("triage")
        triage.create_step("problem_identification") \
            .add_section("Role", "You are a technical support specialist") \
            .add_section("Goal", "Identify the type of technical issue") \
            .add_bullets([
                "Ask about the specific problem",
                "Determine the severity level",
                "Classify the issue type"
            ]) \
            .set_step_criteria("Issue type and severity determined") \
            .set_valid_contexts(["hardware", "software", "network"])

        # Hardware troubleshooting
        hardware = contexts.create_context("hardware")
        hardware.create_step("hardware_diagnosis") \
            .add_section("Role", "Hardware troubleshooting specialist") \
            .add_section("Instructions", "Guide user through hardware diagnostics") \
            .set_functions(["web_search"])  # Can search for hardware info \
            .set_step_criteria("Hardware issue diagnosed") \
            .set_valid_steps(["hardware_solution"])

        hardware.create_step("hardware_solution") \
            .set_text("Based on the diagnosis, here's how to resolve the hardware issue...") \
            .set_step_criteria("Solution provided and tested") \
            .set_valid_contexts(["triage"])  # Can start over if needed

        # Software troubleshooting
        software = contexts.create_context("software")
        software.create_step("software_diagnosis") \
            .add_section("Role", "Software troubleshooting specialist") \
            .add_section("Instructions", "Diagnose software-related issues") \
            .set_functions(["web_search", "datetime"])  # Can check for updates \
            .set_step_criteria("Software issue identified") \
            .set_valid_steps(["software_fix", "escalation"])

        software.create_step("software_fix") \
            .set_text("Let's try these software troubleshooting steps...") \
            .set_step_criteria("Fix attempted and result confirmed") \
            .set_valid_steps(["escalation", "resolution"])

        software.create_step("escalation") \
            .set_text("I'll escalate this to our specialist team.") \
            .set_functions("none")  # No tools needed for escalation \
            .set_step_criteria("Escalation ticket created")

        software.create_step("resolution") \
            .set_text("Great! The issue has been resolved.") \
            .set_step_criteria("Customer confirms resolution") \
            .set_valid_contexts(["triage"])

        # Network troubleshooting
        network = contexts.create_context("network")
        network.create_step("network_diagnosis") \
            .add_section("Role", "Network connectivity specialist") \
            .add_section("Instructions", "Diagnose network and connectivity issues") \
            .set_functions(["web_search", "datetime"])  # Check service status \
            .set_step_criteria("Network issue diagnosed") \
            .set_valid_steps(["network_fix"])

        network.create_step("network_fix") \
            .set_text("Let's resolve your connectivity issue with these steps...") \
            .set_step_criteria("Network connectivity restored") \
            .set_valid_contexts(["triage"])

agent = TechnicalSupportAgent()
agent.run()

if __name__ == "__main__":
    main()

Example 2: Multi-Step Application Process 🔗 ↑ TOC

class LoanApplicationAgent(AgentBase):
    def __init__(self):
        super().__init__(name="Loan Application", route="/loan-app")

        # Add verification tools
        self.add_skill("datetime")  # For date validation

        contexts = self.define_contexts()

        # Single workflow context
        application = contexts.create_context("default")

        # Step 1: Introduction and eligibility
        application.create_step("introduction") \
            .add_section("Role", "You are a loan application assistant") \
            .add_section("Goal", "Guide customers through the loan application process") \
            .add_bullets([
                "Explain the process clearly",
                "Ensure all required information is collected",
                "Maintain professional and helpful tone"
            ]) \
            .set_step_criteria("Customer understands process and wants to continue") \
            .set_valid_steps(["personal_info"])

        # Step 2: Personal information
        application.create_step("personal_info") \
            .add_section("Instructions", "Collect personal information") \
            .add_bullets([
                "Full legal name",
                "Date of birth",
                "Social Security Number",
                "Phone number and email"
            ]) \
            .set_functions(["datetime"])  # Can validate dates \
            .set_step_criteria("All personal information collected and verified") \
            .set_valid_steps(["employment_info", "personal_info"])  # Can review/edit

        # Step 3: Employment information  
        application.create_step("employment_info") \
            .set_text("Now I need information about your employment and income.") \
            .set_step_criteria("Employment and income information complete") \
            .set_valid_steps(["financial_info", "personal_info"])  # Can go back

        # Step 4: Financial information
        application.create_step("financial_info") \
            .set_text("Let's review your financial situation including assets and debts.") \
            .set_step_criteria("Financial information complete") \
            .set_valid_steps(["review", "employment_info"])  # Can go back

        # Step 5: Review all information
        application.create_step("review") \
            .add_section("Instructions", "Review all collected information") \
            .add_bullets([
                "Confirm personal details",
                "Verify employment information", 
                "Review financial data",
                "Ensure accuracy before submission"
            ]) \
            .set_step_criteria("Customer has reviewed and confirmed all information") \
            .set_valid_steps(["submit", "personal_info", "employment_info", "financial_info"])

        # Step 6: Submission
        application.create_step("submit") \
            .set_text("Thank you! Your loan application has been submitted successfully. You'll receive a decision within 2-3 business days.") \
            .set_functions("none")  # No tools needed for final message \
            .set_step_criteria("Application submitted and confirmation provided")
            # No valid_steps = end of process

agent = LoanApplicationAgent()
agent.run()

if __name__ == "__main__":
    main()

Example 3: E-commerce Customer Service 🔗 ↑ TOC

class EcommerceServiceAgent(AgentBase):
    def __init__(self):
        super().__init__(name="E-commerce Support", route="/ecommerce")

        # Add tools for order management
        self.add_skill("web_search", {"api_key": "key", "search_engine_id": "id"})
        self.add_skill("datetime")

        contexts = self.define_contexts()

        # Main service menu
        main = contexts.create_context("main")
        main.create_step("service_menu") \
            .add_section("Role", "You are an e-commerce customer service representative") \
            .add_section("Goal", "Help customers with their orders and questions") \
            .add_bullets([
                "Identify the type of assistance needed",
                "Route to the appropriate service area",
                "Maintain friendly and professional tone"
            ]) \
            .set_step_criteria("Customer's need has been identified") \
            .set_valid_contexts(["orders", "returns", "products", "account"])

        # Order management context
        orders = contexts.create_context("orders")
        orders.create_step("order_assistance") \
            .add_section("Role", "Order management specialist") \
            .add_section("Instructions", "Help with order status, modifications, and tracking") \
            .set_functions(["datetime"])  # Can check delivery dates \
            .set_step_criteria("Order issue resolved or escalated") \
            .set_valid_contexts(["main"])

        # Returns and refunds context
        returns = contexts.create_context("returns")
        returns.create_step("return_process") \
            .add_section("Role", "Returns and refunds specialist") \
            .add_section("Instructions", "Guide customers through return process") \
            .add_bullets([
                "Verify return eligibility",
                "Explain return policy", 
                "Provide return instructions",
                "Process refund if applicable"
            ]) \
            .set_functions("none")  # Sensitive financial operations \
            .set_step_criteria("Return request processed") \
            .set_valid_contexts(["main"])

        # Product information context
        products = contexts.create_context("products")
        products.create_step("product_help") \
            .add_section("Role", "Product information specialist") \
            .add_section("Instructions", "Help customers with product questions") \
            .set_functions(["web_search"])  # Can search for product info \
            .set_step_criteria("Product question answered") \
            .set_valid_contexts(["main"])

        # Account management context
        account = contexts.create_context("account")
        account.create_step("account_help") \
            .set_text("I can help with account-related questions. Please verify your identity first.") \
            .set_functions("none")  # Security-sensitive context \
            .set_step_criteria("Account issue resolved") \
            .set_valid_contexts(["main"])

agent = EcommerceServiceAgent()
agent.run()

if __name__ == "__main__":
    main()

Best Practices 🔗 ↑ TOC

1. Clear Step Naming 🔗 ↑ TOC

Use descriptive step names that indicate purpose:

# Good
.create_step("collect_shipping_address")
.create_step("verify_payment_method")
.create_step("confirm_order_details")

# Avoid
.create_step("step1")
.create_step("next")
.create_step("continue")

2. Meaningful Completion Criteria 🔗 ↑ TOC

Define clear, testable completion criteria:

# Good - specific and measurable
.set_step_criteria("User has provided valid email address and confirmed subscription preferences")
.set_step_criteria("All required fields completed and payment method verified")

# Avoid - vague or subjective
.set_step_criteria("User is ready")
.set_step_criteria("Everything is good")

3. Logical Navigation Flow 🔗 ↑ TOC

Design intuitive navigation that matches user expectations:

# Allow users to go back and review
.set_valid_steps(["review_info", "edit_details", "confirm_submission"])

# Provide escape routes
.set_valid_contexts(["main_menu", "help"])

# Consider dead ends carefully
.set_valid_steps([])  # Only if this is truly the end

4. Progressive Function Access 🔗 ↑ TOC

Restrict functions based on security and context needs:

# Public areas - limited functions
public_step.set_functions(["datetime", "web_search"])

# Authenticated areas - more functions allowed
auth_step.set_functions(["datetime", "web_search", "user_profile"])

# Sensitive operations - minimal functions
billing_step.set_functions("none")

5. Context Organization 🔗 ↑ TOC

Organize contexts by functional area or user journey:

# By functional area
contexts = ["triage", "technical_support", "billing", "account_management"]

# By user journey stage  
contexts = ["onboarding", "verification", "configuration", "completion"]

# By security level
contexts = ["public", "authenticated", "admin"]

6. Error Handling and Recovery 🔗 ↑ TOC

Provide recovery paths for common issues:

# Allow users to retry failed steps
.set_valid_steps(["retry_payment", "choose_different_method", "contact_support"])

# Provide help context access
.set_valid_contexts(["help", "main"])

# Include validation steps
verification_step.create_step("validation") \
    .set_step_criteria("Data validation passed") \
    .set_valid_steps(["proceed", "edit_data"])

7. Content Strategy 🔗 ↑ TOC

Choose the right content approach for each step:

# Use set_text() for simple, direct instructions
step.set_text("Please provide your email address")

# Use POM sections for complex, structured content
step.add_section("Role", "You are a technical specialist") \
    .add_section("Context", "Customer is experiencing network issues") \
    .add_section("Instructions", "Follow diagnostic protocol") \
    .add_bullets(["Check connectivity", "Test speed", "Verify settings"])

Troubleshooting 🔗 ↑ TOC

Common Issues 🔗 ↑ TOC

1. "Single context must be named 'default'" 🔗 ↑ TOC

Error: When using a single context with a name other than "default"

# Wrong
context = contexts.create_context("main")  # Error!

# Correct
context = contexts.create_context("default")

2. "Cannot mix set_text with add_section" 🔗 ↑ TOC

Error: Using both direct text and POM sections in the same step

# Wrong
step.set_text("Welcome!") \
    .add_section("Role", "Assistant")  # Error!

# Correct - choose one approach
step.set_text("Welcome! I'm your assistant.")
# OR
step.add_section("Role", "Assistant") \
    .add_section("Message", "Welcome!")

3. Navigation Issues 🔗 ↑ TOC

Problem: Users getting stuck or unable to navigate

# Check your navigation rules
step.set_valid_steps([])  # Dead end - is this intended?
step.set_valid_contexts([])  # Trapped in context - is this intended?

# Add appropriate navigation
step.set_valid_steps(["next_step", "previous_step"])
step.set_valid_contexts(["main", "help"])

4. Function Access Problems 🔗 ↑ TOC

Problem: Functions not available when expected

# Check function restrictions
step.set_functions("none")  # All functions blocked
step.set_functions(["datetime"])  # Only datetime allowed

# Verify function names match your agent's functions
self.add_skill("web_search")  # Function name is "web_search"
step.set_functions(["web_search"])  # Must match exactly

Debugging Tips 🔗 ↑ TOC

1. Trace Navigation Flow 🔗 ↑ TOC

Add logging to understand flow:

def create_step_with_logging(self, name):
    step = context.create_step(name)
    print(f"Created step: {name}")
    return step

2. Validate Navigation Rules 🔗 ↑ TOC

Check that all referenced steps/contexts exist:

# Ensure referenced steps exist
.set_valid_steps(["review", "edit"])  # Both "review" and "edit" steps must exist

# Ensure referenced contexts exist  
.set_valid_contexts(["main", "help"])  # Both "main" and "help" contexts must exist

3. Test Function Restrictions 🔗 ↑ TOC

Verify functions are properly restricted:

# Test with all functions
# step  # No set_functions() call

# Test with restrictions
step.set_functions(["datetime"])

# Test with no functions
step.set_functions("none")

Migration from POM 🔗 ↑ TOC

Converting Traditional Prompts 🔗 ↑ TOC

Before (Traditional POM):

class TraditionalAgent(AgentBase):
    def __init__(self):
        super().__init__(name="assistant", route="/assistant")

        self.prompt_add_section("Role", "You are a helpful assistant")
        self.prompt_add_section("Instructions", "Help users with questions")
        self.prompt_add_section("Guidelines", bullets=[
            "Be friendly",
            "Ask clarifying questions",
            "Provide accurate information"
        ])

After (Contexts and Steps):

class ContextsAgent(AgentBase):
    def __init__(self):
        super().__init__(name="assistant", route="/assistant")

        contexts = self.define_contexts()
        main = contexts.create_context("default")

        main.create_step("assistance") \
            .add_section("Role", "You are a helpful assistant") \
            .add_section("Instructions", "Help users with questions") \
            .add_section("Guidelines", bullets=[
                "Be friendly",
                "Ask clarifying questions", 
                "Provide accurate information"
            ]) \
            .set_step_criteria("User's question has been answered")

Hybrid Approach 🔗 ↑ TOC

You can use both traditional prompts and contexts in the same agent:

class HybridAgent(AgentBase):
    def __init__(self):
        super().__init__(name="hybrid", route="/hybrid")

        # Traditional prompt sections (from skills, global settings, etc.)
        # These will coexist with contexts

        # Define contexts for structured workflows
        contexts = self.define_contexts()
        workflow = contexts.create_context("default")

        workflow.create_step("structured_process") \
            .set_text("Following the structured workflow...") \
            .set_step_criteria("Workflow complete")

Migration Strategy 🔗 ↑ TOC

  1. Start Simple: Convert one workflow at a time
  2. Preserve Existing: Keep traditional prompts for simple interactions
  3. Add Structure: Use contexts for complex, multi-step processes
  4. Test Thoroughly: Verify navigation and function access work as expected
  5. Iterate: Refine step criteria and navigation based on testing

Conclusion 🔗 ↑ TOC

The Contexts and Steps system provides powerful workflow control for building sophisticated AI agents. By combining structured navigation, function restrictions, and clear completion criteria, you can create predictable, user-friendly agent experiences that guide users through complex processes while maintaining security and control.

Start with simple single-context workflows and gradually build more complex multi-context systems as your requirements grow. The system is designed to be flexible and scalable, supporting both simple linear workflows and complex branching conversation trees.

Context Inheritance 🔗 ↑ TOC

Contexts can inherit from other contexts to create hierarchical structures:

from signalwire_agents import AgentBase
from signalwire_agents.core.context import Context

class CustomerServiceAgent(AgentBase):
    def __init__(self):
        super().__init__(name="customer-service", route="/support")

        # Base context for all customer interactions
        base_context = Context(
            name="customer_base",
            description="Base context for all customer interactions",
            instructions=[
                "Always be polite and professional",
                "Verify customer identity before accessing account information",
                "Document all interactions in the customer record"
            ]
        )

        # Billing context inherits from base
        billing_context = Context(
            name="billing_support",
            description="Handle billing inquiries and payment issues",
            parent=base_context,  # Inherits from base_context
            instructions=[
                "Check payment history before suggesting solutions",
                "Offer payment plan options for overdue accounts",
                "Escalate disputes over $500 to billing manager"
            ]
        )

        # Technical support context also inherits from base
        tech_context = Context(
            name="technical_support", 
            description="Provide technical assistance and troubleshooting",
            parent=base_context,  # Also inherits from base_context
            instructions=[
                "Start with basic troubleshooting steps",
                "Document error messages and symptoms",
                "Create support tickets for unresolved issues"
            ]
        )

        self.add_context(base_context)
        self.add_context(billing_context)
        self.add_context(tech_context)

def main():
    agent = CustomerServiceAgent()
    agent.run()

if __name__ == "__main__":
    main()

Dynamic Context Switching 🔗 ↑ TOC

Contexts can be switched dynamically during conversations based on user input or business logic:

from signalwire_agents import AgentBase
from signalwire_agents.core.context import Context
from signalwire_agents.core.function_result import SwaigFunctionResult

class AdaptiveAgent(AgentBase):
    def __init__(self):
        super().__init__(name="adaptive", route="/adaptive")

        # Define multiple contexts
        self.setup_contexts()

        # Start with general context
        self.set_active_context("general")

    def setup_contexts(self):
        general = Context(
            name="general",
            description="General conversation and routing",
            instructions=[
                "Determine what the user needs help with",
                "Route to appropriate specialized context",
                "Be helpful and friendly"
            ]
        )

        sales = Context(
            name="sales",
            description="Sales and product information",
            instructions=[
                "Focus on product benefits and features",
                "Understand customer needs and budget",
                "Provide pricing and availability information"
            ]
        )

        support = Context(
            name="support", 
            description="Technical support and troubleshooting",
            instructions=[
                "Diagnose technical issues systematically",
                "Provide step-by-step solutions",
                "Escalate complex problems to specialists"
            ]
        )

        self.add_context(general)
        self.add_context(sales)
        self.add_context(support)

    @AgentBase.tool(
        name="switch_to_sales",
        description="Switch to sales context for product inquiries",
        parameters={}
    )
    def switch_to_sales(self, args, raw_data):
        self.set_active_context("sales")
        return SwaigFunctionResult("Switching to sales mode. How can I help you with our products?")

    @AgentBase.tool(
        name="switch_to_support", 
        description="Switch to technical support context",
        parameters={}
    )
    def switch_to_support(self, args, raw_data):
        self.set_active_context("support")
        return SwaigFunctionResult("Switching to technical support. What issue are you experiencing?")

def main():
    agent = AdaptiveAgent()
    agent.run()

if __name__ == "__main__":
    main()

Context-Aware Function Behavior 🔗 ↑ TOC

Functions can behave differently based on the active context:

```python from signalwire_agents import AgentBase from signalwire_agents.core.context import Context from signalwire_agents.core.function_result import SwaigFunctionResult

class ContextAwareAgent(AgentBase): def init(self): super().init(name="context-aware", route="/context")

    # Setup contexts
    self.setup_contexts()
    self.set_active_context("customer")

def setup_contexts(self):
    customer = Context(
        name="customer",
        description="Customer-facing interactions",
        instructions=["Be friendly and helpful", "Use simple language"]
    )

    internal = Context(
        name="internal", 
        description="Internal staff interactions",
        instructions=["Be direct and technical", "Include detailed information"]
    )

    self.add_context(customer)
    self.add_context(internal)

@AgentBase.tool(
    name="get_account_info",
    description="Get account information",
    parameters={
        "account_id": {
            "type": "string",
            "description": "Account identifier"
        }
    }
)
def get_account_info(self, args, raw_data):
    account_id = args.get("account_id")

    # Get the current context
    current_context = self.get_active_context()

    if current_context.name == "customer":
        # Customer-friendly response
        return SwaigFunctionResult(
            f"Your account {account_id} is in good standing. "
            "Your next billing date is March 15th."
        )
    elif current_context.name == "internal":
        # Detailed internal response
        return SwaigFunctionResult(
            f"Account {account_id}: Status=ACTIVE, Balance=$125.50, "
            "Last_Payment=2024-02-15, Next_Bill=2024-03-15, "
            "Plan=Premium, Usage=85% of limit"
        )
    else:
        return SwaigFunctionResult("Account information retrieved.")

def main(): agent = ContextAwareAgent() agent.run()

if name == "main": main()