Files
mims-harvard__tooluniverse/examples/global_fallback_example.py
2026-07-29 18:46:56 -04:00

289 lines
11 KiB
Python

#!/usr/bin/env python3
"""
Test script to verify global fallback functionality in AgenticTool.
Tests the system-wide default fallback chain.
"""
import os
import json
from tooluniverse.agentic_tool import AgenticTool
def test_default_global_fallback():
"""Test: Tool uses default global fallback chain when no explicit fallback is configured."""
print("=== Test 1: Default Global Fallback Chain ===\n")
# Remove Gemini API key to force fallback
original_gemini_key = os.environ.get("GEMINI_API_KEY")
if "GEMINI_API_KEY" in os.environ:
del os.environ["GEMINI_API_KEY"]
try:
# Create tool with only primary API (no explicit fallback)
tool = AgenticTool(
{
"name": "gemini_with_global_fallback",
"api_type": "GEMINI",
"model_id": "gemini-3.6-flash",
# No fallback_api_type configured - should use global fallback
"prompt": "You are a helpful assistant. Answer: {question}",
"input_arguments": ["question"],
}
)
print(f"Tool available: {tool.is_available()}")
print(f"Current API: {tool._current_api_type}")
print(f"Current model: {tool._current_model_id}")
print(f"Original config: {tool._api_type} with {tool._model_id}")
print(f"Global fallback enabled: {tool._use_global_fallback}")
print(f"Global fallback chain: {tool._global_fallback_chain}")
if tool.is_available():
result = tool.run({"question": "What is 2+2?"})
if result.get("success"):
print(f"✅ Tool worked with global fallback: {result['result']}")
else:
print(f"❌ Tool failed: {result['error']}")
else:
print(f"❌ Tool not available: {tool._initialization_error}")
finally:
# Restore Gemini key
if original_gemini_key:
os.environ["GEMINI_API_KEY"] = original_gemini_key
def test_custom_global_fallback():
"""Test: Tool uses custom global fallback chain from environment variable."""
print("\n=== Test 2: Custom Global Fallback Chain ===\n")
# Set custom global fallback chain
custom_chain = [
{"api_type": "GEMINI", "model_id": "gemini-3.6-flash"},
{"api_type": "CHATGPT", "model_id": "gpt-4o-mini-0718"},
]
os.environ["AGENTIC_TOOL_FALLBACK_CHAIN"] = json.dumps(custom_chain)
# Remove Azure OpenAI API key to force fallback
original_azure_key = os.environ.get("AZURE_OPENAI_API_KEY")
if "AZURE_OPENAI_API_KEY" in os.environ:
del os.environ["AZURE_OPENAI_API_KEY"]
try:
# Create tool with ChatGPT as primary
tool = AgenticTool(
{
"name": "chatgpt_with_custom_global_fallback",
"api_type": "CHATGPT",
"model_id": "gpt-4o-1120",
"prompt": "You are a helpful assistant. Answer: {question}",
"input_arguments": ["question"],
}
)
print(f"Tool available: {tool.is_available()}")
print(f"Current API: {tool._current_api_type}")
print(f"Current model: {tool._current_model_id}")
print(f"Original config: {tool._api_type} with {tool._model_id}")
print(f"Custom global fallback chain: {tool._global_fallback_chain}")
if tool.is_available():
result = tool.run({"question": "What is 2+2?"})
if result.get("success"):
print(f"✅ Tool worked with custom global fallback: {result['result']}")
else:
print(f"❌ Tool failed: {result['error']}")
else:
print(f"❌ Tool not available: {tool._initialization_error}")
finally:
# Restore Azure key and remove custom chain
if original_azure_key:
os.environ["AZURE_OPENAI_API_KEY"] = original_azure_key
if "AGENTIC_TOOL_FALLBACK_CHAIN" in os.environ:
del os.environ["AGENTIC_TOOL_FALLBACK_CHAIN"]
def test_disable_global_fallback():
"""Test: Tool can disable global fallback."""
print("\n=== Test 3: Disable Global Fallback ===\n")
# Remove Azure OpenAI API key
original_azure_key = os.environ.get("AZURE_OPENAI_API_KEY")
if "AZURE_OPENAI_API_KEY" in os.environ:
del os.environ["AZURE_OPENAI_API_KEY"]
try:
# Create tool with global fallback disabled
tool = AgenticTool(
{
"name": "no_global_fallback",
"api_type": "CHATGPT",
"model_id": "gpt-4o-1120",
"use_global_fallback": False, # Disable global fallback
"prompt": "You are a helpful assistant. Answer: {question}",
"input_arguments": ["question"],
}
)
print(f"Tool available: {tool.is_available()}")
print(f"Current API: {tool._current_api_type}")
print(f"Current model: {tool._current_model_id}")
print(f"Global fallback enabled: {tool._use_global_fallback}")
if tool.is_available():
result = tool.run({"question": "What is 2+2?"})
print(f"Unexpected success: {result}")
else:
print(
f"✅ Tool correctly failed without global fallback: {tool._initialization_error}"
)
finally:
# Restore Azure key
if original_azure_key:
os.environ["AZURE_OPENAI_API_KEY"] = original_azure_key
def test_explicit_fallback_priority():
"""Test: Explicit fallback takes priority over global fallback."""
print("\n=== Test 4: Explicit Fallback Priority ===\n")
# Remove Gemini API key
original_gemini_key = os.environ.get("GEMINI_API_KEY")
if "GEMINI_API_KEY" in os.environ:
del os.environ["GEMINI_API_KEY"]
try:
# Create tool with both explicit and global fallback
tool = AgenticTool(
{
"name": "explicit_vs_global_fallback",
"api_type": "GEMINI",
"model_id": "gemini-3.6-flash",
"fallback_api_type": "CHATGPT", # Explicit fallback
"fallback_model_id": "gpt-4o-mini-0718", # Different from global default
"prompt": "You are a helpful assistant. Answer: {question}",
"input_arguments": ["question"],
}
)
print(f"Tool available: {tool.is_available()}")
print(f"Current API: {tool._current_api_type}")
print(f"Current model: {tool._current_model_id}")
print(
f"Explicit fallback: {tool._fallback_api_type} ({tool._fallback_model_id})"
)
print(f"Global fallback chain: {tool._global_fallback_chain}")
if tool.is_available():
result = tool.run({"question": "What is 2+2?"})
if result.get("success"):
print(f"✅ Tool worked with explicit fallback: {result['result']}")
# Check if it used explicit fallback (gpt-4o-mini-0718) instead of global default (gpt-4o-1120)
if tool._current_model_id == "gpt-4o-mini-0718":
print("✅ Used explicit fallback as expected")
else:
print(
f"⚠️ Used {tool._current_model_id} instead of explicit fallback"
)
else:
print(f"❌ Tool failed: {result['error']}")
else:
print(f"❌ Tool not available: {tool._initialization_error}")
finally:
# Restore Gemini key
if original_gemini_key:
os.environ["GEMINI_API_KEY"] = original_gemini_key
def test_multiple_tools_global_fallback():
"""Test: Multiple tools using global fallback."""
print("\n=== Test 5: Multiple Tools with Global Fallback ===\n")
# Remove Gemini API key to force fallback for Gemini tools
original_gemini_key = os.environ.get("GEMINI_API_KEY")
if "GEMINI_API_KEY" in os.environ:
del os.environ["GEMINI_API_KEY"]
try:
tools_config = [
{
"name": "gemini_tool_1",
"api_type": "GEMINI",
"model_id": "gemini-3.6-flash",
"prompt": "Gemini tool 1: {question}",
"input_arguments": ["question"],
},
{
"name": "gemini_tool_2",
"api_type": "GEMINI",
"model_id": "gemini-3.6-flash",
"prompt": "Gemini tool 2: {question}",
"input_arguments": ["question"],
},
{
"name": "chatgpt_tool",
"api_type": "CHATGPT",
"model_id": "gpt-4o-1120",
"prompt": "ChatGPT tool: {question}",
"input_arguments": ["question"],
},
]
tools = []
for config in tools_config:
tool = AgenticTool(config)
tools.append(tool)
status = "✅ Available" if tool.is_available() else "❌ Unavailable"
current_api = (
f"{tool._current_api_type} ({tool._current_model_id})"
if tool._current_api_type
else "None"
)
print(f"{config['name']}: {status} - Using: {current_api}")
print()
# Test all available tools
available_tools = [tool for tool in tools if tool.is_available()]
if available_tools:
print("=== Testing Available Tools ===")
for tool in available_tools:
result = tool.run({"question": "Hello!"})
if result.get("success"):
print(f"✅ {tool.name}: {result['result'][:50]}...")
else:
print(f"❌ {tool.name}: {result['error']}")
finally:
# Restore Gemini key
if original_gemini_key:
os.environ["GEMINI_API_KEY"] = original_gemini_key
if __name__ == "__main__":
test_default_global_fallback()
test_custom_global_fallback()
test_disable_global_fallback()
test_explicit_fallback_priority()
test_multiple_tools_global_fallback()
print("\n=== Summary ===")
print("✅ Global fallback chain works as default")
print("✅ Custom global fallback chain from environment variable")
print("✅ Global fallback can be disabled per tool")
print("✅ Explicit fallback takes priority over global fallback")
print("✅ Multiple tools can use global fallback independently")
print("\n=== Configuration Options ===")
print("• use_global_fallback: true/false (default: true)")
print("• AGENTIC_TOOL_FALLBACK_CHAIN: JSON array of {api_type, model_id}")
print("• Explicit fallback_api_type/fallback_model_id takes priority")