claude_adapter.py
1 """ 2 Claude Adapter - Wraps Anthropic Claude for Sovereign OS mesh. 3 4 Note: When running IN Claude (like Claude Code), this adapter is for 5 programmatic API calls. The active Claude instance is the primary agent; 6 this adapter enables fallback queries or parallel consensus checks. 7 """ 8 9 import os 10 from typing import Optional 11 12 from .model_adapter import ModelAdapter, ModelCapabilities, TaskType 13 14 15 class ClaudeAdapter(ModelAdapter): 16 """ 17 Adapter for Anthropic Claude models. 18 19 Wraps the Anthropic API with Sovereign OS context injection. 20 """ 21 22 # Model preference order 23 MODELS = { 24 'opus': 'claude-opus-4-5-20251101', 25 'sonnet': 'claude-sonnet-4-20250514', 26 'haiku': 'claude-haiku-20250115', 27 } 28 29 def __init__(self, model_tier: str = 'sonnet'): 30 super().__init__() 31 self._api_key = os.environ.get("ANTHROPIC_API_KEY") 32 self._client = None 33 self._model_tier = model_tier 34 self._model_id = self.MODELS.get(model_tier, self.MODELS['sonnet']) 35 36 if self._api_key: 37 self._init_client() 38 39 def _init_client(self): 40 """Initialize the Anthropic client.""" 41 try: 42 import anthropic 43 self._client = anthropic.Anthropic(api_key=self._api_key) 44 except ImportError: 45 pass 46 47 @property 48 def name(self) -> str: 49 return f"Claude {self._model_tier.capitalize()}" 50 51 @property 52 def model_id(self) -> str: 53 return self._model_id 54 55 @property 56 def capabilities(self) -> ModelCapabilities: 57 if self._model_tier == 'opus': 58 return ModelCapabilities( 59 coding=1.0, # Best coding model 60 research=0.9, 61 speed=0.6, # Slower but thorough 62 cost_efficiency=0.3, # Expensive 63 context_window=200_000, 64 supports_streaming=True, 65 supports_tools=True, 66 supports_vision=True, 67 ) 68 elif self._model_tier == 'sonnet': 69 return ModelCapabilities( 70 coding=0.9, 71 research=0.85, 72 speed=0.8, 73 cost_efficiency=0.5, 74 context_window=200_000, 75 supports_streaming=True, 76 supports_tools=True, 77 supports_vision=True, 78 ) 79 else: # haiku 80 return ModelCapabilities( 81 coding=0.7, 82 research=0.6, 83 speed=0.95, 84 cost_efficiency=0.8, 85 context_window=200_000, 86 supports_streaming=True, 87 supports_tools=True, 88 supports_vision=True, 89 ) 90 91 def is_available(self) -> bool: 92 """Check if Claude is available via API.""" 93 # Note: This checks API availability, not Claude Code credits 94 return bool(self._api_key and self._client) 95 96 def _raw_query(self, prompt: str, max_tokens: int = 4096, **kwargs) -> str: 97 """Send prompt to Claude and get response.""" 98 if not self._client: 99 return "Error: Claude not initialized. Set ANTHROPIC_API_KEY." 100 101 try: 102 message = self._client.messages.create( 103 model=self._model_id, 104 max_tokens=max_tokens, 105 messages=[ 106 {"role": "user", "content": prompt} 107 ] 108 ) 109 return message.content[0].text 110 except Exception as e: 111 return f"Claude error: {e}" 112 113 114 class ClaudeOpusAdapter(ClaudeAdapter): 115 """Claude Opus - most capable, best for complex coding.""" 116 def __init__(self): 117 super().__init__(model_tier='opus') 118 119 120 class ClaudeSonnetAdapter(ClaudeAdapter): 121 """Claude Sonnet - balanced performance and cost.""" 122 def __init__(self): 123 super().__init__(model_tier='sonnet') 124 125 126 class ClaudeHaikuAdapter(ClaudeAdapter): 127 """Claude Haiku - fastest and cheapest Claude.""" 128 def __init__(self): 129 super().__init__(model_tier='haiku')