Variable Substitution

Dynamic variable substitution with double-brace placeholders and dot-notation

Variable substitution enables dynamic content replacement using {{variable}} placeholders that resolve at runtime, supporting both flat variables and dot-notation for nested data structures.

python
from praisonaiagents import Agent

agent = Agent(name="Daily Agent", instructions="Answer using today's date when asked.")
agent.start("Summarise the top AI news for {{today}}")

The user includes placeholders in the prompt; the agent resolves variables before answering.

Diagram
graph LR
    subgraph "Variable Resolution"
        A[📝 {{user.name}}] --> B[🔍 Look up]
        B --> C[📊 variables["user"]["name"]]
        C --> D[✅ "Alice"]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class A input
    class B,C process
    class D output

How It Works

Diagram
VariableSubstitutionAgentUserVariableSubstitutionAgentUserRequestProcessResultResponse

Quick Start

  1. Dynamic placeholders in prompts

    Built-in providers such as {{today}}, {{now}}, and {{uuid}} resolve when the agent runs:

    python
    from praisonaiagents import Agent
    
    agent = Agent(name="Daily Agent", instructions="Answer concisely.")
    agent.start("What is today's date? Reply with {{today}} only.")
  2. Dot notation for nested data

    Pass a variables dict when substituting text in workflows or templates:

    python
    from praisonaiagents.utils.variables import substitute_variables
    
    text = substitute_variables(
        "Welcome {{user.name}}! Your role is {{user.role}}",
        {"user": {"name": "Alice", "role": "admin", "settings": {"theme": "dark"}}},
    )
    # "Welcome Alice! Your role is admin"
  3. Graceful fallback for missing keys

    Missing segments stay as literal placeholders — no error is raised:

    python
    from praisonaiagents.utils.variables import substitute_variables
    
    text = substitute_variables(
        "Process {{data.value}} or use {{fallback}} if missing",
        {"data": {"other": "something"}, "fallback": "default"},
    )
    # "Process {{data.value}} or use default if missing"

How It Works

Diagram
Variable SubstitutionAgentUserVariable SubstitutionAgentUserRequestProcess requestResultResponse
Diagram
graph TB
    A[📝 Input Text] --> B{🔍 Has {{var}}?}
    B -->|No| C[✅ Return as-is]
    B -->|Yes| D{📊 Dotted name?}
    D -->|No| E[🔍 Provider Registry]
    D -->|Yes| F[🗂️ Dict Traversal]
    E --> G{✅ Found?}
    F --> G
    G -->|Yes| H[🔄 Replace]
    G -->|No| I[📝 Keep Original]
    H --> J[✅ Result]
    I --> J

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class A input
    class B,D,E,F,G process
    class C,H,I,J output
Resolution OrderDescription
1. Provider RegistryDynamic providers (for non-dotted names only)
2. Dict TraversalNavigate nested dicts using dot notation
3. Graceful FallbackKeep original {{...}} if not found

Configuration Options

PatternTypeDescription
{{name}}strFlat variable name – checks providers then static variables
{{obj.prop}}strDot notation – traverses nested dicts only
{{missing}}strMissing variables remain as literal text (graceful fallback)

Traversal Rules:

  • Only dict objects are traversed (not lists, objects, or attributes)
  • Provider registry is consulted only for non-dotted names
  • Missing segments result in graceful fallback (no errors)

Common Patterns

Pattern 1: User configuration

python
from praisonaiagents.utils.variables import substitute_variables

instructions = substitute_variables(
    "Hello {{user.name}}! Theme: {{user.settings.theme}}",
    {
        "user": {
            "name": "Bob",
            "settings": {"theme": "light", "notifications": True},
        }
    },
)

Pattern 2: API Endpoint Templates

python
variables = {
    "api": {
        "base_url": "https://api.example.com",
        "version": "v1",
        "endpoints": {
            "users": "/users",
            "posts": "/posts"
        }
    }
}

template = "{{api.base_url}}/{{api.version}}{{api.endpoints.users}}"
# Resolves to: "https://api.example.com/v1/users"

Pattern 3: Multi-Level Data Access

python
variables = {
    "company": {
        "departments": {
            "engineering": {
                "team_lead": "Charlie",
                "budget": 100000
            }
        }
    }
}

instruction = "Contact {{company.departments.engineering.team_lead}}"
# Resolves to: "Contact Charlie"

Best Practices

Use Descriptive Variable Names

Choose clear, descriptive names that make templates self-documenting.

python
# Good
variables = {
    "user": {"name": "Alice", "role": "admin"},
    "project": {"name": "Dashboard", "deadline": "2024-01-15"}
}

# Avoid
variables = {
    "u": {"n": "Alice", "r": "admin"},
    "p": {"n": "Dashboard", "d": "2024-01-15"}
}
Structure Data Hierarchically

Organize related data into logical groupings for cleaner templates.

python
# Organized structure
variables = {
    "user": {
        "profile": {"name": "Bob", "email": "bob@example.com"},
        "preferences": {"theme": "dark", "language": "en"}
    },
    "system": {
        "version": "1.2.0",
        "environment": "production"
    }
}
Handle Missing Data Gracefully

Design templates that degrade gracefully when optional data is missing.

python
# Template with fallback
template = "Welcome {{user.name}}! {{user.title}} is optional."

# Works with partial data
variables = {"user": {"name": "Carol"}}
# Result: "Welcome Carol! {{user.title}} is optional."
Avoid Deep Nesting

Keep dot-notation paths reasonably short for maintainability.

python
# Reasonable depth
{{config.database.host}}

# Too deep - consider flattening
{{app.modules.auth.providers.oauth.google.client_id}}

Related