Skip to main content

Variable Handling

Claro prompts support variables that can be dynamically replaced with values. Learn how to extract, validate, and use variables.

Understanding Variables

Variables in prompts use double curly brace syntax:
Hello {{user_name}}! You have {{count}} unread messages.
Variables can include type hints and descriptions:
{{user_name:string}}
{{count:number // Number of unread messages}}
{{is_premium:boolean}}

Extracting Variables

Use the extract_variables() method to find all variables in a prompt:
from baytos.claro import BaytClient

client = BaytClient(api_key="your_api_key")
prompt = client.get_prompt("@workspace/template:v1")

# Extract all variables
variables = prompt.extract_variables()

for var in variables:
    print(f"Name: {var['name']}")
    if 'type' in var:
        print(f"Type: {var['type']}")
    if 'description' in var:
        print(f"Description: {var['description']}")
    print()

Variable Information

Each extracted variable contains:
{
    "name": "user_name",           # Variable name
    "type": "string",              # Type (optional)
    "description": "User's name"   # Description (optional)
}

Variable Types

Claro supports several variable types:

String Variables

# In prompt: Hello {{name:string}}!

variables = prompt.extract_variables()
# [{'name': 'name', 'type': 'string'}]

Number Variables

# In prompt: You have {{count:number}} items

variables = prompt.extract_variables()
# [{'name': 'count', 'type': 'number'}]

Boolean Variables

# In prompt: Premium: {{is_premium:boolean}}

variables = prompt.extract_variables()
# [{'name': 'is_premium', 'type': 'boolean'}]

Array Variables

# In prompt: Tags: {{tags:array}}

variables = prompt.extract_variables()
# [{'name': 'tags', 'type': 'array'}]

Object Variables

# In prompt: User: {{user:object}}

variables = prompt.extract_variables()
# [{'name': 'user', 'type': 'object'}]

Validating Variables

Validate variable values before using them:
prompt = client.get_prompt("@workspace/notification:v1")

# Values to validate
values = {
    'user_name': 'Alice',
    'count': 42,
    'is_premium': True
}

# Validate
errors = prompt.validate_variables(values)

if errors:
    print("Validation errors:")
    for field, message in errors.items():
        print(f"  {field}: {message}")
else:
    print("All variables valid!")

Validation Rules

The validator checks:
  1. Missing Variables - All required variables must be provided
  2. Unexpected Variables - No extra variables allowed
  3. Type Mismatches - Values must match declared types
# Missing variable
values = {'user_name': 'Alice'}  # Missing 'count'
errors = prompt.validate_variables(values)
# {'count': 'Missing required variable: count'}

# Type mismatch
values = {'user_name': 'Alice', 'count': 'not a number'}
errors = prompt.validate_variables(values)
# {'count': 'Expected number, got str'}

# Unexpected variable
values = {'user_name': 'Alice', 'count': 42, 'extra': 'value'}
errors = prompt.validate_variables(values)
# {'extra': 'Unexpected variable: extra'}

Using Prompts as Templates

Replace variables with actual values:
import re

def render_template(prompt_text: str, values: dict) -> str:
    """Replace {{variable}} placeholders with values"""
    def replace(match):
        var_name = match.group(1).split(':')[0].strip()
        return str(values.get(var_name, match.group(0)))

    pattern = r'\{\{([^}]+)\}\}'
    return re.sub(pattern, replace, prompt_text)

# Get prompt
prompt = client.get_prompt("@workspace/greeting:v1")

# Define values
values = {
    'user_name': 'Alice',
    'message_count': 5
}

# Render template
rendered = render_template(prompt.generator, values)
print(rendered)

Complete Example

#!/usr/bin/env python3
"""
Example: Extract, validate, and use variables
"""

import os
import re
from baytos.claro import BaytClient

def render_template(text: str, values: dict) -> str:
    """Replace {{variable}} or {{variable:type}} with values"""
    def replace(match):
        # Extract variable name (before : if type is specified)
        var_name = match.group(1).split(':')[0].strip()
        return str(values.get(var_name, match.group(0)))

    pattern = r'\{\{([^}]+)\}\}'
    return re.sub(pattern, replace, text)

def use_prompt_with_variables(package_name: str, values: dict):
    """Get prompt, validate variables, and render"""

    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))
    prompt = client.get_prompt(package_name)

    print(f"Prompt: {prompt.title}\n")

    # Extract variables
    variables = prompt.extract_variables()
    print(f"Found {len(variables)} variable(s):")
    for var in variables:
        type_info = f" ({var['type']})" if 'type' in var else ""
        desc_info = f" - {var['description']}" if 'description' in var else ""
        print(f"  - {var['name']}{type_info}{desc_info}")
    print()

    # Validate
    errors = prompt.validate_variables(values)
    if errors:
        print("Validation errors:")
        for field, message in errors.items():
            print(f"  {field}: {message}")
        return

    print("Variables validated successfully!\n")

    # Render
    rendered = render_template(prompt.generator, values)
    print("Rendered prompt:")
    print(rendered)

if __name__ == "__main__":
    # Example usage
    values = {
        'user_name': 'Alice',
        'product_name': 'Premium Subscription',
        'price': 29.99,
        'is_trial': False
    }

    use_prompt_with_variables("@workspace/sales-email:v1", values)

Type Safety with Python

For better type safety, use TypedDict:
from typing import TypedDict
from baytos.claro import BaytClient

class EmailVariables(TypedDict):
    user_name: str
    product_name: str
    price: float
    is_trial: bool

def send_email(values: EmailVariables):
    """Type-safe variable usage"""
    client = BaytClient(api_key="...")
    prompt = client.get_prompt("@workspace/sales-email:v1")

    # Validate
    errors = prompt.validate_variables(values)
    if errors:
        raise ValueError(f"Invalid variables: {errors}")

    # Use prompt...
    print(prompt.generator)

# Usage - IDE provides autocomplete and type checking
send_email({
    'user_name': 'Alice',
    'product_name': 'Premium',
    'price': 29.99,
    'is_trial': False
})

Dynamic Variable Discovery

Discover variables at runtime:
def get_required_variables(package_name: str) -> dict:
    """Get information about required variables"""
    client = BaytClient(api_key="...")
    prompt = client.get_prompt(package_name)

    variables = prompt.extract_variables()

    var_info = {}
    for var in variables:
        var_info[var['name']] = {
            'type': var.get('type', 'any'),
            'description': var.get('description', ''),
            'required': True
        }

    return var_info

# Usage
required = get_required_variables("@workspace/template:v1")

print("This prompt requires:")
for name, info in required.items():
    print(f"  {name}: {info['type']}")
    if info['description']:
        print(f"    {info['description']}")

Best Practices

Validate variables before using a prompt:
# ✅ Good: Validate first
errors = prompt.validate_variables(values)
if not errors:
    rendered = render_template(prompt.generator, values)

# ❌ Bad: Skip validation
rendered = render_template(prompt.generator, values)
Include type hints in your prompts for better validation:
✅ Good:
Hello {{name:string}}! You have {{count:number}} items.

❌ Less clear:
Hello {{name}}! You have {{count}} items.
Type hints enable automatic validation and better documentation.
Provide defaults for optional variables:
def render_safe(text: str, values: dict, defaults: dict = None) -> str:
    """Render with fallback defaults"""
    defaults = defaults or {}
    all_values = {**defaults, **values}

    def replace(match):
        var_name = match.group(1).split(':')[0].strip()
        return str(all_values.get(var_name, match.group(0)))

    pattern = r'\{\{([^}]+)\}\}'
    return re.sub(pattern, replace, text)

# Usage with defaults
rendered = render_safe(
    prompt.generator,
    {'user_name': 'Alice'},
    defaults={'greeting': 'Hello', 'message_count': 0}
)
Use descriptions to document variables:
✅ Good:
{{user_email:string // User's email address for notifications}}
{{retry_count:number // Number of retry attempts (max: 3)}}

❌ Less helpful:
{{user_email}}
{{retry_count}}

Advanced: Variable Extraction from All Fields

Extract variables from all prompt fields (generator, system, critique):
def extract_all_variables(prompt):
    """Extract variables from all prompt fields"""
    all_variables = {}

    # This is already done by extract_variables()
    # It searches generator, system, and critique fields
    variables = prompt.extract_variables()

    # Group by field
    for var in variables:
        name = var['name']
        if name not in all_variables:
            all_variables[name] = var

    return list(all_variables.values())

# Usage
prompt = client.get_prompt("@workspace/complex:v1")
variables = extract_all_variables(prompt)

print(f"Found {len(variables)} unique variable(s)")
for var in variables:
    print(f"  - {var['name']}")

Next Steps