Phase 8: Additional provider integrations (Anthropic, Google) and enhanced documentation
This commit is contained in:
1 parent
c44a4ae92a
commit
c54f2a33c8
2 files changed
+413
-5
No files matched your search
+362
-1
@@ -548,12 +548,337 @@ class OpenRouterProviderTools(BaseProviderTools):
|
||||
return output
|
||||
|
||||
|
||||
class AnthropicProviderTools(BaseProviderTools):
|
||||
"""Anthropic provider tools implementation"""
|
||||
|
||||
def __init__(self, api_key: str, **kwargs):
|
||||
"""
|
||||
Initialize Anthropic tools
|
||||
|
||||
Args:
|
||||
api_key: Anthropic API key
|
||||
**kwargs: Additional configuration
|
||||
"""
|
||||
super().__init__("anthropic", api_key=api_key, **kwargs)
|
||||
self.api_key = api_key
|
||||
self.api_url = "https://api.anthropic.com/v1"
|
||||
|
||||
def _make_request(self, endpoint: str, method: str = "GET", data: Optional[Dict] = None) -> Dict[str, Any]:
|
||||
"""Make a request to the Anthropic API"""
|
||||
try:
|
||||
url = f"{self.api_url}/{endpoint}"
|
||||
headers = {
|
||||
"x-api-key": self.api_key,
|
||||
"Content-Type": "application/json",
|
||||
"anthropic-version": "2023-06-01"
|
||||
}
|
||||
|
||||
if method.upper() == "GET":
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
elif method.upper() == "POST":
|
||||
response = requests.post(url, headers=headers, json=data, timeout=30)
|
||||
else:
|
||||
return {"success": False, "error": f"Unsupported method: {method}"}
|
||||
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
return {"success": True, "data": response.json()}
|
||||
except json.JSONDecodeError:
|
||||
return {"success": True, "data": response.text}
|
||||
else:
|
||||
return {"success": False, "error": f"HTTP {response.status_code}: {response.text}"}
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return {"success": False, "error": "Request timed out"}
|
||||
except requests.exceptions.ConnectionError:
|
||||
return {"success": False, "error": "Connection failed to Anthropic API"}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
def list_models(self) -> str:
|
||||
"""List available Anthropic models"""
|
||||
# Anthropic doesn't have a public models endpoint
|
||||
# Return known models
|
||||
output = "Available Anthropic Models:\n"
|
||||
output += "=" * 50 + "\n"
|
||||
output += "• claude-3-5-sonnet-20241022\n"
|
||||
output += "• claude-3-opus-20240229\n"
|
||||
output += "• claude-3-sonnet-20240229\n"
|
||||
output += "• claude-3-haiku-20240307\n"
|
||||
output += "• claude-2.1\n"
|
||||
output += "• claude-2.0\n"
|
||||
output += "• claude-instant-1.2\n"
|
||||
return output
|
||||
|
||||
def get_model_info(self, model_name: str) -> str:
|
||||
"""Get detailed information about a specific model"""
|
||||
# Anthropic doesn't have a public model info endpoint
|
||||
# Return basic information
|
||||
output = f"Model Information: {model_name}\n"
|
||||
output += "=" * 50 + "\n"
|
||||
|
||||
if "claude-3-5-sonnet" in model_name:
|
||||
output += "Description: Most intelligent model\n"
|
||||
output += "Context Window: 200K tokens\n"
|
||||
output += "Best for: Complex tasks, analysis, coding\n"
|
||||
elif "claude-3-opus" in model_name:
|
||||
output += "Description: Most powerful model\n"
|
||||
output += "Context Window: 200K tokens\n"
|
||||
output += "Best for: Maximum intelligence\n"
|
||||
elif "claude-3-sonnet" in model_name:
|
||||
output += "Description: Balanced performance\n"
|
||||
output += "Context Window: 200K tokens\n"
|
||||
output += "Best for: Balance of intelligence and speed\n"
|
||||
elif "claude-3-haiku" in model_name:
|
||||
output += "Description: Fastest model\n"
|
||||
output += "Context Window: 200K tokens\n"
|
||||
output += "Best for: Quick responses, simple tasks\n"
|
||||
else:
|
||||
output += "Description: Claude model\n"
|
||||
output += "Context Window: Varies\n"
|
||||
|
||||
return output
|
||||
|
||||
def test_connection(self) -> str:
|
||||
"""Test connection to Anthropic"""
|
||||
try:
|
||||
# Try to make a simple request
|
||||
headers = {
|
||||
"x-api-key": self.api_key,
|
||||
"Content-Type": "application/json",
|
||||
"anthropic-version": "2023-06-01"
|
||||
}
|
||||
|
||||
# Test with a minimal completion request
|
||||
data = {
|
||||
"model": "claude-3-haiku-20240307",
|
||||
"max_tokens": 10,
|
||||
"messages": [{"role": "user", "content": "Hi"}]
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/messages",
|
||||
headers=headers,
|
||||
json=data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
return "✅ Anthropic API connection successful."
|
||||
else:
|
||||
return f"❌ Anthropic API connection failed: HTTP {response.status_code}"
|
||||
except Exception as e:
|
||||
return f"❌ Error connecting to Anthropic: {str(e)}"
|
||||
|
||||
def get_default_model(self) -> str:
|
||||
"""Get the default model for Anthropic"""
|
||||
return "Default model: claude-3-5-sonnet-20241022 (recommended for most tasks)"
|
||||
|
||||
def set_default_model(self, model_name: str) -> str:
|
||||
"""Set the default model for Anthropic"""
|
||||
# Anthropic doesn't have a built-in default model concept
|
||||
# Just verify the model name is valid
|
||||
known_models = [
|
||||
"claude-3-5-sonnet-20241022",
|
||||
"claude-3-opus-20240229",
|
||||
"claude-3-sonnet-20240229",
|
||||
"claude-3-haiku-20240307",
|
||||
"claude-2.1",
|
||||
"claude-2.0",
|
||||
"claude-instant-1.2"
|
||||
]
|
||||
|
||||
if model_name in known_models:
|
||||
return f"✅ Model '{model_name}' is a valid Anthropic model."
|
||||
else:
|
||||
return f"⚠️ Model '{model_name}' may not be a valid Anthropic model."
|
||||
|
||||
def get_provider_info(self) -> str:
|
||||
"""Get information about Anthropic configuration"""
|
||||
output = "Anthropic Provider Configuration:\n"
|
||||
output += "=" * 50 + "\n"
|
||||
output += f"API URL: {self.api_url}\n"
|
||||
output += f"API Key: {'Set' if self.api_key else 'Not set'}\n"
|
||||
|
||||
# Test connection
|
||||
try:
|
||||
headers = {
|
||||
"x-api-key": self.api_key,
|
||||
"Content-Type": "application/json",
|
||||
"anthropic-version": "2023-06-01"
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/messages",
|
||||
headers=headers,
|
||||
json={"model": "claude-3-haiku-20240307", "max_tokens": 1, "messages": [{"role": "user", "content": "test"}]},
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
output += "Status: ✅ Connected\n"
|
||||
else:
|
||||
output += f"Status: ❌ Connection failed (HTTP {response.status_code})\n"
|
||||
except:
|
||||
output += "Status: ❌ Not connected\n"
|
||||
|
||||
return output
|
||||
|
||||
|
||||
class GoogleProviderTools(BaseProviderTools):
|
||||
"""Google provider tools implementation"""
|
||||
|
||||
def __init__(self, api_key: str, **kwargs):
|
||||
"""
|
||||
Initialize Google tools
|
||||
|
||||
Args:
|
||||
api_key: Google API key
|
||||
**kwargs: Additional configuration
|
||||
"""
|
||||
super().__init__("google", api_key=api_key, **kwargs)
|
||||
self.api_key = api_key
|
||||
self.api_url = "https://generativelanguage.googleapis.com/v1beta"
|
||||
|
||||
def _make_request(self, endpoint: str, method: str = "GET", data: Optional[Dict] = None) -> Dict[str, Any]:
|
||||
"""Make a request to the Google API"""
|
||||
try:
|
||||
url = f"{self.api_url}/{endpoint}?key={self.api_key}"
|
||||
headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
if method.upper() == "GET":
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
elif method.upper() == "POST":
|
||||
response = requests.post(url, headers=headers, json=data, timeout=30)
|
||||
else:
|
||||
return {"success": False, "error": f"Unsupported method: {method}"}
|
||||
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
return {"success": True, "data": response.json()}
|
||||
except json.JSONDecodeError:
|
||||
return {"success": True, "data": response.text}
|
||||
else:
|
||||
return {"success": False, "error": f"HTTP {response.status_code}: {response.text}"}
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return {"success": False, "error": "Request timed out"}
|
||||
except requests.exceptions.ConnectionError:
|
||||
return {"success": False, "error": "Connection failed to Google API"}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
def list_models(self) -> str:
|
||||
"""List available Google models"""
|
||||
result = self._make_request("models")
|
||||
|
||||
if not result["success"]:
|
||||
return f"Error listing models: {result['error']}"
|
||||
|
||||
models = result["data"].get("models", [])
|
||||
if not models:
|
||||
return "No models found on Google."
|
||||
|
||||
output = "Available Google Models:\n"
|
||||
output += "=" * 50 + "\n"
|
||||
|
||||
for model in models:
|
||||
name = model.get("name", "")
|
||||
display_name = model.get("displayName", "")
|
||||
description = model.get("description", "")
|
||||
|
||||
if name:
|
||||
output += f"• {name}\n"
|
||||
if display_name:
|
||||
output += f" Display Name: {display_name}\n"
|
||||
if description:
|
||||
output += f" Description: {description[:100]}...\n"
|
||||
output += "\n"
|
||||
|
||||
return output
|
||||
|
||||
def get_model_info(self, model_name: str) -> str:
|
||||
"""Get detailed information about a specific model"""
|
||||
# Extract model name from full path if needed
|
||||
if "/" in model_name:
|
||||
model_name = model_name.split("/")[-1]
|
||||
|
||||
result = self._make_request(f"models/{model_name}")
|
||||
|
||||
if not result["success"]:
|
||||
return f"Error getting model info: {result['error']}"
|
||||
|
||||
model_info = result["data"]
|
||||
|
||||
output = f"Model Information: {model_name}\n"
|
||||
output += "=" * 50 + "\n"
|
||||
output += f"Name: {model_info.get('name', 'Unknown')}\n"
|
||||
output += f"Display Name: {model_info.get('displayName', 'Unknown')}\n"
|
||||
output += f"Description: {model_info.get('description', 'Unknown')}\n"
|
||||
|
||||
if "inputTokenLimit" in model_info:
|
||||
output += f"Input Token Limit: {model_info['inputTokenLimit']}\n"
|
||||
|
||||
if "outputTokenLimit" in model_info:
|
||||
output += f"Output Token Limit: {model_info['outputTokenLimit']}\n"
|
||||
|
||||
return output
|
||||
|
||||
def test_connection(self) -> str:
|
||||
"""Test connection to Google"""
|
||||
try:
|
||||
# Try to list models as a connection test
|
||||
result = self._make_request("models")
|
||||
if result["success"]:
|
||||
return "✅ Google API connection successful."
|
||||
else:
|
||||
return f"❌ Google API connection failed: {result['error']}"
|
||||
except Exception as e:
|
||||
return f"❌ Error connecting to Google: {str(e)}"
|
||||
|
||||
def get_default_model(self) -> str:
|
||||
"""Get the default model for Google"""
|
||||
return "Default model: gemini-1.5-pro (recommended for most tasks)"
|
||||
|
||||
def set_default_model(self, model_name: str) -> str:
|
||||
"""Set the default model for Google"""
|
||||
# Google doesn't have a built-in default model concept
|
||||
# Just verify the model exists
|
||||
result = self._make_request(f"models/{model_name}")
|
||||
|
||||
if result["success"]:
|
||||
return f"✅ Model '{model_name}' exists and can be used as default."
|
||||
else:
|
||||
return f"❌ Model '{model_name}' not found on Google."
|
||||
|
||||
def get_provider_info(self) -> str:
|
||||
"""Get information about Google configuration"""
|
||||
output = "Google Provider Configuration:\n"
|
||||
output += "=" * 50 + "\n"
|
||||
output += f"API URL: {self.api_url}\n"
|
||||
output += f"API Key: {'Set' if self.api_key else 'Not set'}\n"
|
||||
|
||||
# Test connection
|
||||
try:
|
||||
result = self._make_request("models")
|
||||
if result["success"]:
|
||||
output += "Status: ✅ Connected\n"
|
||||
else:
|
||||
output += f"Status: ❌ Connection failed\n"
|
||||
except:
|
||||
output += "Status: ❌ Not connected\n"
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def get_provider_tools(provider: str, **kwargs) -> List[Tool]:
|
||||
"""
|
||||
Get tools for a specific provider
|
||||
|
||||
Args:
|
||||
provider: Provider name ("ollama", "openai", "openrouter")
|
||||
provider: Provider name ("ollama", "openai", "openrouter", "anthropic", "google")
|
||||
**kwargs: Provider-specific configuration
|
||||
|
||||
Returns:
|
||||
@@ -583,6 +908,22 @@ def get_provider_tools(provider: str, **kwargs) -> List[Tool]:
|
||||
tools = OpenRouterProviderTools(api_key=api_key, base_url=base_url)
|
||||
return tools.get_tools()
|
||||
|
||||
elif provider == "anthropic":
|
||||
api_key = kwargs.get("api_key", os.getenv("ANTHROPIC_API_KEY"))
|
||||
if not api_key:
|
||||
print("Warning: Anthropic API key not provided")
|
||||
return []
|
||||
tools = AnthropicProviderTools(api_key=api_key)
|
||||
return tools.get_tools()
|
||||
|
||||
elif provider == "google":
|
||||
api_key = kwargs.get("api_key", os.getenv("GOOGLE_API_KEY"))
|
||||
if not api_key:
|
||||
print("Warning: Google API key not provided")
|
||||
return []
|
||||
tools = GoogleProviderTools(api_key=api_key)
|
||||
return tools.get_tools()
|
||||
|
||||
else:
|
||||
print(f"Warning: Unknown provider '{provider}'")
|
||||
return []
|
||||
@@ -627,4 +968,24 @@ def get_all_provider_tools() -> List[Tool]:
|
||||
except Exception as e:
|
||||
print(f"⚠️ Could not load OpenRouter tools: {e}")
|
||||
|
||||
# Check for Anthropic configuration
|
||||
anthropic_key = os.getenv("ANTHROPIC_API_KEY")
|
||||
if anthropic_key:
|
||||
try:
|
||||
anthropic_tools = get_provider_tools("anthropic", api_key=anthropic_key)
|
||||
all_tools.extend(anthropic_tools)
|
||||
print(f"✅ Added {len(anthropic_tools)} Anthropic tools")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Could not load Anthropic tools: {e}")
|
||||
|
||||
# Check for Google configuration
|
||||
google_key = os.getenv("GOOGLE_API_KEY")
|
||||
if google_key:
|
||||
try:
|
||||
google_tools = get_provider_tools("google", api_key=google_key)
|
||||
all_tools.extend(google_tools)
|
||||
print(f"✅ Added {len(google_tools)} Google tools")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Could not load Google tools: {e}")
|
||||
|
||||
return all_tools
|
||||
Reference in new issue
Block a user