/ core / mesh / claude_adapter.py
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')