Skip to main content

Dynamic Agent Switcher

A Python package that allows you to dynamically switch between different AI models during agent execution. Perfect for handling rate limits, distributing API calls, and implementing custom switching logic.

Features

  • Flexible Switching Conditions: Switch models based on rate limits, tool call counts, response content, time limits, error counts, or custom functions
  • Multiple AI Providers: Support for OpenAI, Gemini, Groq, and other providers
  • Easy Integration: Drop-in replacement for existing pydantic_ai.Agent instances
  • Configurable Strategies: Round-robin, rate-limit-based, random, weighted, or fallback selection
  • Real-time Context Tracking: Monitor execution context and make informed switching decisions
  • Extensible: Create custom switching conditions for your specific needs

Installation

pip install dynamic_agent_switcher

Quick Start

Basic Usage

from dynamic_agent_switcher import (
    DynamicAgentWrapper, 
    ModelConfig, 
    SwitchStrategy,
    ConditionType
)

# Define your models
model_configs = [
    ModelConfig(
        name="openai_gpt4",
        provider="openai",
        model_name="gpt-4",
        api_key="your-openai-key",
        max_requests_per_minute=50
    ),
    ModelConfig(
        name="gemini_pro",
        provider="gemini",
        model_name="gemini-1.5-pro", 
        api_key="your-gemini-key",
        max_requests_per_minute=60
    )
]

# Create dynamic agent
agent = DynamicAgentWrapper(
    model_configs=model_configs,
    system_prompt="You are a helpful AI assistant.",
    strategy=SwitchStrategy.RATE_LIMIT_BASED
)

# Use like a regular agent
result = await agent.run("Generate a story about a robot.")

Custom Switching Conditions

# Switch after 3 tool calls
tool_call_condition = {
    "type": ConditionType.TOOL_CALL_COUNT.value,
    "name": "tool_call_limit",
    "parameters": {"max_calls": 3}
}

# Switch when the count_words tool reports > 500 words (preferred)
tool_word_count_condition = {
    "type": ConditionType.TOOL_RESPONSE.value,
    "name": "word_limit_via_tool",
    "parameters": {
        "tool_name": "count_words",             # optional: apply only to this tool
        "logic": "ANY",                         # ANY | ALL | NONE
        "response_conditions": [
            {"type": "greater_than", "path": "word_count", "value": 500}
        ]
    }
}

# Note: If you want to measure raw model output length instead of tool output,
# you can still use AI_RESPONSE_CONTENT. However, for generic, reusable logic,
# prefer TOOL_RESPONSE so it works with your explicit tool outputs.

# Switch after 2 minutes
time_condition = {
    "type": ConditionType.TIME_BASED.value,
    "name": "time_limit",
    "parameters": {"max_duration_seconds": 120}
}

agent = DynamicAgentWrapper(
    model_configs=model_configs,
    conditions=[tool_call_condition, tool_word_count_condition, time_condition]
)

Tool Response Based Switching

# Switch when a specific tool returns certain values
tool_response_condition = {
    "type": ConditionType.TOOL_RESPONSE.value,
    "name": "validation_failed",
    "parameters": {
        "tool_name": "validate_html",
        "response_conditions": [
            {"type": "contains", "value": "invalid"},
            {"type": "equals", "value": False}
        ]
    }
}

Custom Function Conditions

def custom_switch_logic(context):
    """Custom logic to determine when to switch models."""
    error_count = context.get("error_count", 0)
    current_model = context.get("current_model")
    
    # Switch if we've had 2 errors with the same model
    if error_count >= 2:
        return True
    
    # Switch if current model is OpenAI and it's peak hours
    if current_model == "openai_gpt4" and is_peak_hours():
        return True
    
    return False

custom_condition = {
    "type": ConditionType.CUSTOM_FUNCTION.value,
    "name": "custom_logic",
    "parameters": {
        "function": custom_switch_logic,
        "reason": "Custom business logic"
    }
}

Combination Conditions

# Switch if ANY of these conditions are met
combination_condition = {
    "type": ConditionType.COMBINATION.value,
    "name": "complex_logic",
    "operator": "OR",  # AND, OR, XOR
    "parameters": {
        "conditions": [
            {
                "type": ConditionType.RATE_LIMIT.value,
                "name": "rate_limit"
            },
            {
                "type": ConditionType.TOOL_CALL_COUNT.value,
                "name": "too_many_tools",
                "parameters": {"max_calls": 10}
            },
            {
                "type": ConditionType.TIME_BASED.value,
                "name": "timeout",
                "parameters": {"max_duration_seconds": 600}
            }
        ]
    }
}

Integration with Existing Code

Replace Existing Agents

from dynamic_agent_switcher import replace_agent_with_dynamic

# Your existing agent
original_agent = Agent(
    openai_model,
    system_prompt="...",
    tools=[count_words, validate_html]
)

# Replace with dynamic version
dynamic_agent = replace_agent_with_dynamic(
    original_agent=original_agent,
    model_configs=model_configs,
    conditions=conditions
)

# Use exactly the same way
result = await dynamic_agent.run(prompt)

Available Condition Types

Condition Type Description Parameters
RATE_LIMIT Switch when rate limit errors occur None
TOOL_CALL_COUNT Switch after N tool calls max_calls: int
TOOL_RESPONSE Switch based on tool response tool_name: str, response_conditions: List
AI_RESPONSE_STATUS Switch based on AI response status status_codes: List, error_patterns: List
AI_RESPONSE_CONTENT Switch based on response content content_conditions: List
TIME_BASED Switch after time limit max_duration_seconds: int
ERROR_COUNT Switch after N errors max_errors: int
CUSTOM_FUNCTION Switch based on custom function function: Callable, reason: str
COMBINATION Combine multiple conditions conditions: List, operator: str

Content Conditions

For AI_RESPONSE_CONTENT and TOOL_RESPONSE conditions, you can use:

  • contains: Check if response contains text
  • equals: Check if response equals value
  • regex: Check if response matches regex pattern
  • greater_than: Check if numeric value is greater
  • less_than: Check if numeric value is less
  • length_greater_than: Check if string length is greater
  • length_less_than: Check if string length is less
  • word_count_greater_than: Check if word count is greater
  • word_count_less_than: Check if word count is less

Monitoring and Debugging

# Get current status
status = agent.get_status()
print(f"Current model: {status['current_model']}")
print(f"Available models: {status['available_models']}")
print(f"Active conditions: {status['conditions']}")
print(f"Execution context: {status['execution_context']}")

# Update context manually
agent.update_context(
    tool_call_count=5,
    last_tool_response={"word_count": 750}
)

# Reset context
agent.reset_context()

# Add/remove conditions dynamically
agent.add_condition(new_condition)
agent.remove_condition("condition_name")

Advanced Usage

Custom Model Selection Strategy

def custom_model_selector(available_models, context):
    """Custom logic for model selection."""
    if context.get("task_type") == "creative":
        return "gemini_pro"  # Better for creative tasks
    elif context.get("task_type") == "analytical":
        return "openai_gpt4"  # Better for analysis
    else:
        return random.choice(available_models)

# Use with custom strategy
agent = DynamicAgentWrapper(
    model_configs=model_configs,
    strategy=custom_model_selector
)

Context-Aware Switching

# Update context based on your application logic
agent.update_context(
    task_type="creative",
    user_preference="fast",
    current_topic="artificial_intelligence"
)

# Your custom condition can use this context
def context_aware_condition(context):
    if context.get("task_type") == "creative" and context.get("current_model") == "openai_gpt4":
        return True  # Switch to Gemini for creative tasks
    return False

Examples

See usage_examples.py for comprehensive examples including:

  • Basic usage with rate limit handling
  • Tool call count based switching
  • Response content based switching
  • Time-based switching
  • Custom function conditions
  • Combination conditions
  • Tool response based switching
  • Monitoring and debugging
  • Integration with existing code
  • Advanced context-aware switching

License

MIT License - see LICENSE file for details.

Author

Sumit Paul - sumit.18.paul@gmail.com

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Release files for dynamic-agent-switcher 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dynamic-agent-switcher 0.1.1
File Size Uploaded
dynamic_agent_switcher-0.1.1.tar.gz 21.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dynamic-agent-switcher 0.1.1
File Interpreter ABI Platform
dynamic_agent_switcher-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 39.6 kB

Release files / dynamic_agent_switcher-0.1.1.tar.gz

Download URL dynamic_agent_switcher-0.1.1.tar.gz
Size 21.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d918fc76cc1f8d14537fe35dc079b8419cfa476bf75ff7e438b36690e941d777
BLAKE2b-256 checksum
How to use checksums
e419f48864179d05e443461b23dcff0a05329d1d7c6a710184657b7d627a7880
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.9.6

Release files / dynamic_agent_switcher-0.1.1-py3-none-any.whl

Download URL dynamic_agent_switcher-0.1.1-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1921e3b3e231b2133fe895fe68eada86b3f1641bf8acce6014d3d2bc2cdeeb24
BLAKE2b-256 checksum
How to use checksums
50eaf7584683db5216891f1cf68999b5e5970e6d954212b976ba4802bdd0bd33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page