picogent-py/picogent/providers/anthropic.py

87 lines
2.8 KiB
Python

"""
Anthropic Claude provider using httpx
"""
import httpx
import json
from typing import Dict, List, Any, Optional
from .base import BaseProvider
class AnthropicProvider(BaseProvider):
"""Anthropic Claude provider using direct API calls"""
def __init__(self, api_key: str, model: str = "claude-sonnet-4-20250514"):
super().__init__(api_key, model)
self.base_url = "https://api.anthropic.com/v1"
self.anthropic_version = "2023-06-01"
async def generate_response(
self,
messages: List[Dict[str, Any]],
system_prompt: str,
tools: Optional[List[Dict[str, Any]]] = None,
max_tokens: int = 8192
) -> Dict[str, Any]:
"""Generate response using Anthropic Messages API"""
headers = {
"Content-Type": "application/json",
"x-api-key": self.api_key,
"anthropic-version": self.anthropic_version
}
payload = {
"model": self.model,
"max_tokens": max_tokens,
"system": system_prompt,
"messages": messages
}
# Add tools if provided
if tools:
payload["tools"] = tools
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/messages",
headers=headers,
json=payload,
timeout=120.0
)
if response.status_code != 200:
error_text = response.text
raise Exception(f"Anthropic API error {response.status_code}: {error_text}")
result = response.json()
# Parse the response
content = result.get("content", [])
# Extract text content and tool calls
text_parts = []
tool_calls = []
for block in content:
if block.get("type") == "text":
text_parts.append(block.get("text", ""))
elif block.get("type") == "tool_use":
tool_calls.append({
"id": block.get("id"),
"name": block.get("name"),
"input": block.get("input", {})
})
response_data = {
"content": "\n".join(text_parts) if text_parts else "",
"usage": result.get("usage", {}),
"model": result.get("model", self.model)
}
if tool_calls:
response_data["tool_calls"] = tool_calls
# Also include raw content for session storage
response_data["raw_content"] = content
return response_data