Skip to content

Graph Configuration

The configuration object (config) is a Python dictionary that controls various aspects of graph execution in PyAgenity. It serves as the control panel for how your agent graph behaves during runtime, affecting everything from execution limits to state persistence and authentication.

Core Configuration Fields

Required Fields

thread_id: str

Purpose: Unique identifier for the conversation or execution session.

Usage: Essential for state persistence and resuming interrupted executions.

config = {"thread_id": "user-session-123"}

Notes: - Required when using checkpointers (state persistence) - Must be unique per conversation/session - Used to group related messages and state snapshots - Can be any string format: UUIDs, user IDs, session names, etc.


Optional Fields (with defaults)

user_id: str

Default: "test-user-id" (auto-generated if not provided)

Purpose: Identifies the user or system making the request.

Usage: Used for multi-tenant systems, authentication, and data isolation.

config = {
    "thread_id": "session-456", 
    "user_id": "john.doe@example.com"
}

Notes: - Critical for production deployments with multiple users - Used by checkpointers for data segregation - Required by some store implementations (Mem0, Qdrant) - Can be username, email, UUID, or any unique identifier

recursion_limit: int

Default: 25

Purpose: Maximum number of execution steps before the graph stops automatically.

Usage: Prevents infinite loops and runaway executions.

config = {
    "thread_id": "demo-thread",
    "recursion_limit": 50  # Allow up to 50 steps
}

Notes: - Each node execution counts as one step - Helps control resource usage and execution time - Particularly important for conditional routing scenarios - Set higher for complex workflows, lower for simple ones

is_stream: bool

Default: False (auto-set by execution method)

Purpose: Indicates whether this is a streaming execution.

Usage: Automatically set by framework, rarely configured manually.

# Usually auto-set by the framework
for chunk in app.stream(input_data, config={"thread_id": "stream-1"}):
    print(chunk.content)

Notes: - Automatically set to True when using stream() or astream() - Affects how events are published and responses are formatted - Influences internal execution flow and optimization

run_id: str

Default: Auto-generated UUID

Purpose: Unique identifier for this specific graph execution.

Usage: Useful for tracing, logging, and debugging individual runs.

config = {
    "thread_id": "session-123",
    "run_id": "exec-2024-001"  # Custom run identifier
}

Notes: - Auto-generated if not provided - Different from thread_id - multiple runs can share the same thread - Useful for audit trails and execution tracking

timestamp: str

Default: Current ISO timestamp (auto-generated)

Purpose: Records when the graph execution started.

Usage: For auditing, logging, and temporal analysis.

config = {
    "thread_id": "session-789",
    "timestamp": "2024-01-15T10:30:00Z"  # Custom timestamp
}

Notes: - Auto-generated in ISO format if not provided - Used by publishers and logging systems - Helps with execution tracking and debugging


Extended Configuration Options

State Management

state_class: type

Default: AgentState

Purpose: Specifies custom state class for specialized workflows.

Usage: For applications requiring custom state fields.

from pyagenity.state import AgentState

class CustomState(AgentState):
    user_data: dict = Field(default_factory=dict)
    custom_field: str = "default"

config = {
    "thread_id": "custom-session",
    "state_class": CustomState
}

Store Integration

collection: str (Qdrant Store)

Purpose: Specifies which collection to use for vector storage.

Usage: For organizing memories by domain or use case.

config = {
    "thread_id": "session-123",
    "user_id": "user-456",
    "collection": "customer_support_memories"
}

app_id: str (Mem0 Store)

Purpose: Application identifier for Mem0 memory service.

Usage: For multi-application deployments using Mem0.

config = {
    "thread_id": "session-123", 
    "user_id": "user-456",
    "app_id": "customer-service-bot"
}

Thread Management

thread_name: str

Purpose: Human-readable name for the conversation thread.

Usage: Improves thread organization and user experience.

config = {
    "thread_id": "thread-123",
    "thread_name": "Customer Support - Billing Issue",
    "user_id": "customer-456"
}

meta: dict / thread_meta: dict

Purpose: Additional metadata for the execution or thread.

Usage: Store custom data alongside execution context.

config = {
    "thread_id": "session-123",
    "meta": {
        "customer_tier": "premium",
        "support_level": 2,
        "region": "us-west"
    }
}


Configuration Examples

Basic Usage

# Minimal configuration
config = {"thread_id": "simple-chat"}

# With user identification
config = {
    "thread_id": "user-session-789",
    "user_id": "alice@company.com"
}

Production Configuration

config = {
    "thread_id": f"support-{ticket_id}",
    "user_id": user.email,
    "thread_name": f"Support Ticket #{ticket_id}",
    "recursion_limit": 30,
    "meta": {
        "ticket_id": ticket_id,
        "priority": "high", 
        "department": "technical_support",
        "created_at": datetime.now().isoformat()
    }
}

Multi-Store Configuration

# For applications using memory stores
config = {
    "thread_id": f"chat-{session_id}",
    "user_id": user.id,
    "collection": "user_preferences",  # Qdrant
    "app_id": "personal-assistant",    # Mem0
    "recursion_limit": 20
}

Streaming Configuration

# Streaming execution (is_stream auto-set)
config = {
    "thread_id": "live-chat-123",
    "user_id": "customer-456",
    "recursion_limit": 15  # Lower limit for responsiveness
}

# Use with streaming
for chunk in app.stream(input_data, config=config):
    print(chunk.content)

Integration Patterns

With Authentication Systems

When deployed using PyAgenity CLI or similar deployment systems, the authentication system can populate the config with user information:

# Authentication system provides user context
def create_config_from_auth(request, thread_id):
    user = authenticate_request(request)
    return {
        "thread_id": thread_id,
        "user_id": user.id,
        "user_name": user.name,
        "meta": {
            "roles": user.roles,
            "permissions": user.permissions,
            "session_start": datetime.now().isoformat()
        }
    }

Environment-Based Configuration

import os

def create_production_config(thread_id: str, user_id: str) -> dict:
    return {
        "thread_id": thread_id,
        "user_id": user_id,
        "recursion_limit": int(os.getenv("MAX_RECURSION_LIMIT", "25")),
        "app_id": os.getenv("APP_ID", "default-app"),
        "meta": {
            "environment": os.getenv("ENVIRONMENT", "production"),
            "version": os.getenv("APP_VERSION", "1.0.0")
        }
    }

Best Practices

1. Always Provide thread_id

# ❌ Bad - Missing thread_id for stateful apps
config = {"user_id": "user-123"}

# ✅ Good - Always include thread_id
config = {
    "thread_id": "session-456",
    "user_id": "user-123"  
}

2. Use Meaningful Identifiers

# ❌ Bad - Non-descriptive IDs
config = {"thread_id": "abc123"}

# ✅ Good - Descriptive, traceable IDs
config = {
    "thread_id": f"support-ticket-{ticket_number}",
    "user_id": user.email
}

3. Set Appropriate Limits

# ❌ Bad - Too high, potential runaway
config = {"recursion_limit": 1000}

# ❌ Bad - Too low, premature termination  
config = {"recursion_limit": 5}

# ✅ Good - Reasonable limit for use case
config = {
    "recursion_limit": 25,  # Default, good for most cases
    "thread_id": "session-123"
}

4. Include Relevant Metadata

# ✅ Good - Rich metadata for debugging/analytics
config = {
    "thread_id": session_id,
    "user_id": user_id,
    "meta": {
        "feature_flags": get_user_features(user_id),
        "client_version": request.headers.get("X-Client-Version"),
        "request_id": request.id
    }
}

Security Considerations

  • Never include sensitive data (passwords, API keys) in config
  • Validate user_id to prevent unauthorized access to other users' data
  • Sanitize thread_id to prevent path traversal or injection attacks
  • Use proper authentication before accepting user-provided config values
# ✅ Good - Validated configuration
def create_safe_config(authenticated_user, thread_id):
    # Validate inputs
    if not authenticated_user.is_active:
        raise ValueError("User not active")

    safe_thread_id = sanitize_thread_id(thread_id)

    return {
        "thread_id": safe_thread_id,
        "user_id": authenticated_user.id,  # Trusted source
        "recursion_limit": min(50, authenticated_user.max_recursion_limit)
    }