omnimancer-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnimancer/__init__.py +42 -0
- omnimancer/__main__.py +9 -0
- omnimancer/cli/__init__.py +8 -0
- omnimancer/cli/agent_manager.py +826 -0
- omnimancer/cli/agent_wizard.py +944 -0
- omnimancer/cli/approval_formatter.py +734 -0
- omnimancer/cli/approval_integration.py +734 -0
- omnimancer/cli/approval_prompt.py +1286 -0
- omnimancer/cli/batch_approval_display.py +617 -0
- omnimancer/cli/batch_approval_filters.py +729 -0
- omnimancer/cli/batch_operation_monitor.py +775 -0
- omnimancer/cli/commands/performance_cmd.py +624 -0
- omnimancer/cli/commands.py +757 -0
- omnimancer/cli/completion_handler.py +281 -0
- omnimancer/cli/config_setup_wizard.py +783 -0
- omnimancer/cli/dynamic_commands.py +371 -0
- omnimancer/cli/handlers/__init__.py +18 -0
- omnimancer/cli/handlers/agent_handler.py +865 -0
- omnimancer/cli/handlers/agent_persona_handler.py +1048 -0
- omnimancer/cli/handlers/custom_agent_handler.py +352 -0
- omnimancer/cli/handlers/permissions_handler.py +1609 -0
- omnimancer/cli/interface.py +6695 -0
- omnimancer/cli/performance_dashboard.py +612 -0
- omnimancer/core/__init__.py +34 -0
- omnimancer/core/agent/__init__.py +256 -0
- omnimancer/core/agent/agent_config.py +715 -0
- omnimancer/core/agent/agent_switcher.py +668 -0
- omnimancer/core/agent/approval_context.py +460 -0
- omnimancer/core/agent/approval_dialog.py +902 -0
- omnimancer/core/agent/approval_interface.py +628 -0
- omnimancer/core/agent/approval_manager.py +760 -0
- omnimancer/core/agent/cli_integration.py +470 -0
- omnimancer/core/agent/config.py +845 -0
- omnimancer/core/agent/custom_agent_integration.py +654 -0
- omnimancer/core/agent/diff_renderer.py +706 -0
- omnimancer/core/agent/file_content_display.py +503 -0
- omnimancer/core/agent/file_modification_workflow.py +658 -0
- omnimancer/core/agent/file_system_manager.py +1790 -0
- omnimancer/core/agent/input_handler.py +614 -0
- omnimancer/core/agent/metrics_collector.py +771 -0
- omnimancer/core/agent/optimization_engine.py +729 -0
- omnimancer/core/agent/performance_monitor.py +717 -0
- omnimancer/core/agent/persona.py +870 -0
- omnimancer/core/agent/persona_validator.py +672 -0
- omnimancer/core/agent/program_executor.py +748 -0
- omnimancer/core/agent/proposed_changes_integration.py +663 -0
- omnimancer/core/agent/read_before_write_errors.py +492 -0
- omnimancer/core/agent/read_before_write_ui.py +647 -0
- omnimancer/core/agent/rich_renderer.py +763 -0
- omnimancer/core/agent/status_config.py +238 -0
- omnimancer/core/agent/status_core.py +446 -0
- omnimancer/core/agent/status_integrated_engine.py +540 -0
- omnimancer/core/agent/status_manager.py +878 -0
- omnimancer/core/agent/status_ui_components.py +535 -0
- omnimancer/core/agent/template_applicator.py +548 -0
- omnimancer/core/agent/terminal_status_listener.py +394 -0
- omnimancer/core/agent/token_tracker.py +679 -0
- omnimancer/core/agent/types.py +60 -0
- omnimancer/core/agent/web_client.py +745 -0
- omnimancer/core/agent/workflow_orchestrator.py +826 -0
- omnimancer/core/agent_engine.py +1625 -0
- omnimancer/core/agent_mode_manager.py +706 -0
- omnimancer/core/agent_progress_ui.py +545 -0
- omnimancer/core/chat_manager.py +141 -0
- omnimancer/core/config_manager.py +2199 -0
- omnimancer/core/config_migration.py +772 -0
- omnimancer/core/config_provider.py +1974 -0
- omnimancer/core/config_security_validator.py +393 -0
- omnimancer/core/config_validator.py +768 -0
- omnimancer/core/conversation_manager.py +352 -0
- omnimancer/core/engine.py +787 -0
- omnimancer/core/enhanced_input.py +523 -0
- omnimancer/core/env_loader.py +83 -0
- omnimancer/core/fallback_manager.py +568 -0
- omnimancer/core/health_monitor.py +462 -0
- omnimancer/core/history_manager.py +462 -0
- omnimancer/core/mcp_integration_layer.py +878 -0
- omnimancer/core/models.py +1889 -0
- omnimancer/core/provider_capabilities.py +403 -0
- omnimancer/core/provider_initializer.py +450 -0
- omnimancer/core/provider_registry.py +432 -0
- omnimancer/core/security/__init__.py +16 -0
- omnimancer/core/security/approval_workflow.py +406 -0
- omnimancer/core/security/audit_logger.py +511 -0
- omnimancer/core/security/permission_controller.py +511 -0
- omnimancer/core/security/sandbox_manager.py +379 -0
- omnimancer/core/security/security_manager.py +530 -0
- omnimancer/core/setup_wizard.py +345 -0
- omnimancer/core/setup_wizard_core.py +449 -0
- omnimancer/core/setup_wizard_guide_generator.py +376 -0
- omnimancer/core/setup_wizard_provider_setup.py +454 -0
- omnimancer/core/setup_wizard_ui.py +317 -0
- omnimancer/core/setup_wizard_validation.py +371 -0
- omnimancer/core/signal_handler.py +174 -0
- omnimancer/mcp/__init__.py +11 -0
- omnimancer/mcp/client.py +725 -0
- omnimancer/mcp/manager.py +649 -0
- omnimancer/providers/__init__.py +24 -0
- omnimancer/providers/azure.py +608 -0
- omnimancer/providers/base.py +262 -0
- omnimancer/providers/bedrock.py +711 -0
- omnimancer/providers/claude.py +426 -0
- omnimancer/providers/claude_code.py +406 -0
- omnimancer/providers/cohere.py +412 -0
- omnimancer/providers/factory.py +988 -0
- omnimancer/providers/gemini.py +708 -0
- omnimancer/providers/mistral.py +554 -0
- omnimancer/providers/ollama.py +510 -0
- omnimancer/providers/openai.py +362 -0
- omnimancer/providers/openrouter.py +709 -0
- omnimancer/providers/perplexity.py +476 -0
- omnimancer/providers/vertex.py +617 -0
- omnimancer/providers/xai.py +484 -0
- omnimancer/ui/__init__.py +6 -0
- omnimancer/ui/cancellation_handler.py +235 -0
- omnimancer/ui/progress_indicator.py +318 -0
- omnimancer/utils/__init__.py +22 -0
- omnimancer/utils/error_handler.py +589 -0
- omnimancer/utils/errors.py +667 -0
- omnimancer/utils/retry.py +238 -0
- omnimancer_cli-0.1.0.dist-info/METADATA +413 -0
- omnimancer_cli-0.1.0.dist-info/RECORD +126 -0
- omnimancer_cli-0.1.0.dist-info/WHEEL +5 -0
- omnimancer_cli-0.1.0.dist-info/entry_points.txt +4 -0
- omnimancer_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- omnimancer_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Claude provider implementation for Omnimancer.
|
|
3
|
+
|
|
4
|
+
This module provides the Claude AI provider implementation using Anthropic's API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Dict, List
|
|
9
|
+
|
|
10
|
+
import certifi
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
from ..core.models import ChatContext, ChatResponse, ModelInfo
|
|
14
|
+
from ..utils.errors import (
|
|
15
|
+
AuthenticationError,
|
|
16
|
+
ModelNotFoundError,
|
|
17
|
+
NetworkError,
|
|
18
|
+
ProviderError,
|
|
19
|
+
RateLimitError,
|
|
20
|
+
)
|
|
21
|
+
from .base import BaseProvider
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ClaudeProvider(BaseProvider):
|
|
25
|
+
"""
|
|
26
|
+
Claude AI provider implementation using Anthropic's API.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
BASE_URL = "https://api.anthropic.com/v1"
|
|
30
|
+
|
|
31
|
+
def __init__(self, api_key: str, model: str = "", **kwargs):
|
|
32
|
+
"""
|
|
33
|
+
Initialize Claude provider.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
api_key: Anthropic API key
|
|
37
|
+
model: Claude model to use (e.g., 'claude-sonnet-4-20250514', 'claude-3-5-sonnet-20241022')
|
|
38
|
+
**kwargs: Additional configuration
|
|
39
|
+
"""
|
|
40
|
+
super().__init__(api_key, model or "claude-sonnet-4-20250514", **kwargs)
|
|
41
|
+
self.max_tokens = kwargs.get("max_tokens") or 4096
|
|
42
|
+
self.temperature = kwargs.get("temperature") or 0.7
|
|
43
|
+
|
|
44
|
+
async def send_message(self, message: str, context: ChatContext) -> ChatResponse:
|
|
45
|
+
"""
|
|
46
|
+
Send a message to Claude API.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
message: User message
|
|
50
|
+
context: Conversation context
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
ChatResponse with Claude's reply
|
|
54
|
+
"""
|
|
55
|
+
# Prepare messages for Claude API
|
|
56
|
+
messages = self._prepare_messages(message, context)
|
|
57
|
+
|
|
58
|
+
# Try with SSL verification first, then fall back if needed
|
|
59
|
+
for ssl_verify in [True, certifi.where(), False]:
|
|
60
|
+
try:
|
|
61
|
+
async with httpx.AsyncClient(verify=ssl_verify) as client:
|
|
62
|
+
response = await client.post(
|
|
63
|
+
f"{self.BASE_URL}/messages",
|
|
64
|
+
headers={
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
"x-api-key": self.api_key,
|
|
67
|
+
"anthropic-version": "2023-06-01",
|
|
68
|
+
},
|
|
69
|
+
json={
|
|
70
|
+
"model": self.model,
|
|
71
|
+
"max_tokens": self.max_tokens,
|
|
72
|
+
"temperature": self.temperature,
|
|
73
|
+
"messages": messages,
|
|
74
|
+
},
|
|
75
|
+
timeout=30.0,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# If we get here, the request succeeded
|
|
79
|
+
return self._handle_response(response)
|
|
80
|
+
|
|
81
|
+
except httpx.ConnectError as e:
|
|
82
|
+
if "SSL" in str(e) or "certificate" in str(e):
|
|
83
|
+
# SSL error, try next verification method
|
|
84
|
+
continue
|
|
85
|
+
else:
|
|
86
|
+
# Non-SSL connection error, don't retry
|
|
87
|
+
raise NetworkError(f"Connection error: {e}")
|
|
88
|
+
except httpx.TimeoutException:
|
|
89
|
+
raise NetworkError("Request to Claude API timed out")
|
|
90
|
+
except httpx.RequestError as e:
|
|
91
|
+
if "SSL" not in str(e) and "certificate" not in str(e):
|
|
92
|
+
# Non-SSL request error, don't retry
|
|
93
|
+
raise NetworkError(f"Network error: {e}")
|
|
94
|
+
# SSL-related error, try next verification method
|
|
95
|
+
continue
|
|
96
|
+
except (
|
|
97
|
+
AuthenticationError,
|
|
98
|
+
RateLimitError,
|
|
99
|
+
ModelNotFoundError,
|
|
100
|
+
ProviderError,
|
|
101
|
+
):
|
|
102
|
+
# Known provider errors, don't retry
|
|
103
|
+
raise
|
|
104
|
+
except Exception as e:
|
|
105
|
+
# Unknown error, don't retry
|
|
106
|
+
raise ProviderError(f"Unexpected error: {e}")
|
|
107
|
+
|
|
108
|
+
# If we get here, all SSL methods failed
|
|
109
|
+
raise NetworkError("Failed to establish SSL connection to Claude API")
|
|
110
|
+
|
|
111
|
+
async def validate_credentials(self) -> bool:
|
|
112
|
+
"""
|
|
113
|
+
Validate Claude API credentials by making a test request.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
True if credentials are valid
|
|
117
|
+
"""
|
|
118
|
+
# Try different SSL verification methods
|
|
119
|
+
for ssl_verify in [True, certifi.where(), False]:
|
|
120
|
+
try:
|
|
121
|
+
async with httpx.AsyncClient(verify=ssl_verify) as client:
|
|
122
|
+
response = await client.post(
|
|
123
|
+
f"{self.BASE_URL}/messages",
|
|
124
|
+
headers={
|
|
125
|
+
"Content-Type": "application/json",
|
|
126
|
+
"x-api-key": self.api_key,
|
|
127
|
+
"anthropic-version": "2023-06-01",
|
|
128
|
+
},
|
|
129
|
+
json={
|
|
130
|
+
"model": self.model,
|
|
131
|
+
"max_tokens": 10,
|
|
132
|
+
"messages": [{"role": "user", "content": "Hi"}],
|
|
133
|
+
},
|
|
134
|
+
timeout=10.0,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# If we get here, connection worked
|
|
138
|
+
# Check for specific status codes
|
|
139
|
+
if response.status_code == 200:
|
|
140
|
+
return True
|
|
141
|
+
elif response.status_code == 401:
|
|
142
|
+
# Authentication failed - invalid API key
|
|
143
|
+
return False
|
|
144
|
+
elif response.status_code == 400:
|
|
145
|
+
# Bad request - but API key might be valid, could be model issue
|
|
146
|
+
try:
|
|
147
|
+
error_data = response.json()
|
|
148
|
+
error_type = error_data.get("error", {}).get("type", "")
|
|
149
|
+
# If it's an authentication error, API key is invalid
|
|
150
|
+
if error_type == "authentication_error":
|
|
151
|
+
return False
|
|
152
|
+
# If it's other errors (like invalid model), API key is probably valid
|
|
153
|
+
return True
|
|
154
|
+
except:
|
|
155
|
+
# Can't parse error, assume API key is valid if we got a response
|
|
156
|
+
return True
|
|
157
|
+
else:
|
|
158
|
+
# Other status codes - if we got a response, API key is probably valid
|
|
159
|
+
return True
|
|
160
|
+
|
|
161
|
+
except httpx.ConnectError as e:
|
|
162
|
+
if "SSL" in str(e) or "certificate" in str(e):
|
|
163
|
+
# SSL error, try next verification method
|
|
164
|
+
continue
|
|
165
|
+
else:
|
|
166
|
+
# Non-SSL connection error
|
|
167
|
+
return False
|
|
168
|
+
except httpx.TimeoutException:
|
|
169
|
+
# Timeout might mean network issues, try next SSL method
|
|
170
|
+
continue
|
|
171
|
+
except httpx.RequestError as e:
|
|
172
|
+
if "SSL" not in str(e) and "certificate" not in str(e):
|
|
173
|
+
# Non-SSL request error
|
|
174
|
+
return False
|
|
175
|
+
# SSL-related error, try next verification method
|
|
176
|
+
continue
|
|
177
|
+
except Exception as e:
|
|
178
|
+
# Other error (timeout, etc.) - if it's not SSL related, stop trying
|
|
179
|
+
if "SSL" not in str(e) and "certificate" not in str(e):
|
|
180
|
+
return False
|
|
181
|
+
# SSL-related error, continue to next method
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
# If we get here, all SSL methods failed
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
def _prepare_messages(
|
|
188
|
+
self, message: str, context: ChatContext
|
|
189
|
+
) -> List[Dict[str, str]]:
|
|
190
|
+
"""
|
|
191
|
+
Prepare messages for Claude API format.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
message: Current user message
|
|
195
|
+
context: Conversation context
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
List of messages formatted for Claude API
|
|
199
|
+
"""
|
|
200
|
+
messages = []
|
|
201
|
+
|
|
202
|
+
# Add context messages (excluding system messages for Claude)
|
|
203
|
+
for msg in context.messages:
|
|
204
|
+
if msg.role.value != "system":
|
|
205
|
+
messages.append({"role": msg.role.value, "content": msg.content})
|
|
206
|
+
|
|
207
|
+
# Add current message
|
|
208
|
+
messages.append({"role": "user", "content": message})
|
|
209
|
+
|
|
210
|
+
return messages
|
|
211
|
+
|
|
212
|
+
def _handle_response(self, response: httpx.Response) -> ChatResponse:
|
|
213
|
+
"""
|
|
214
|
+
Handle Claude API response.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
response: HTTP response from Claude API
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
ChatResponse object
|
|
221
|
+
|
|
222
|
+
Raises:
|
|
223
|
+
Various provider errors based on response status
|
|
224
|
+
"""
|
|
225
|
+
if response.status_code == 200:
|
|
226
|
+
data = response.json()
|
|
227
|
+
content = data.get("content", [])
|
|
228
|
+
|
|
229
|
+
if content and len(content) > 0:
|
|
230
|
+
text_content = content[0].get("text", "")
|
|
231
|
+
usage = data.get("usage", {})
|
|
232
|
+
|
|
233
|
+
return ChatResponse(
|
|
234
|
+
content=text_content,
|
|
235
|
+
model_used=self.model,
|
|
236
|
+
tokens_used=usage.get("output_tokens", 0),
|
|
237
|
+
timestamp=datetime.now(),
|
|
238
|
+
)
|
|
239
|
+
else:
|
|
240
|
+
raise ProviderError("Empty response from Claude API")
|
|
241
|
+
|
|
242
|
+
elif response.status_code == 401:
|
|
243
|
+
raise AuthenticationError("Invalid Claude API key")
|
|
244
|
+
elif response.status_code == 429:
|
|
245
|
+
raise RateLimitError("Claude API rate limit exceeded")
|
|
246
|
+
elif response.status_code == 404:
|
|
247
|
+
raise ModelNotFoundError(f"Claude model '{self.model}' not found")
|
|
248
|
+
else:
|
|
249
|
+
try:
|
|
250
|
+
error_data = response.json()
|
|
251
|
+
error_msg = error_data.get("error", {}).get("message", "Unknown error")
|
|
252
|
+
except:
|
|
253
|
+
error_msg = f"HTTP {response.status_code}"
|
|
254
|
+
|
|
255
|
+
raise ProviderError(f"Claude API error: {error_msg}")
|
|
256
|
+
|
|
257
|
+
def get_model_info(self) -> ModelInfo:
|
|
258
|
+
"""
|
|
259
|
+
Get information about the current Claude model.
|
|
260
|
+
"""
|
|
261
|
+
model_configs = {
|
|
262
|
+
"claude-sonnet-4-20250514": {
|
|
263
|
+
"description": "Claude Sonnet 4 - Latest and most capable model",
|
|
264
|
+
"max_tokens": 200000,
|
|
265
|
+
"cost_per_token": 0.000015,
|
|
266
|
+
},
|
|
267
|
+
"claude-opus-4-20250514": {
|
|
268
|
+
"description": "Claude Opus 4 - Most powerful model for complex tasks",
|
|
269
|
+
"max_tokens": 200000,
|
|
270
|
+
"cost_per_token": 0.000075,
|
|
271
|
+
},
|
|
272
|
+
"claude-3-5-sonnet-20241022": {
|
|
273
|
+
"description": "Claude 3.5 Sonnet - Enhanced reasoning and analysis",
|
|
274
|
+
"max_tokens": 200000,
|
|
275
|
+
"cost_per_token": 0.000015,
|
|
276
|
+
},
|
|
277
|
+
# Legacy models for backward compatibility
|
|
278
|
+
"claude-3-sonnet-20240229": {
|
|
279
|
+
"description": "Claude 3 Sonnet - Balanced performance and speed",
|
|
280
|
+
"max_tokens": 200000,
|
|
281
|
+
"cost_per_token": 0.000015,
|
|
282
|
+
},
|
|
283
|
+
"claude-3-haiku-20240307": {
|
|
284
|
+
"description": "Claude 3 Haiku - Fast and efficient",
|
|
285
|
+
"max_tokens": 200000,
|
|
286
|
+
"cost_per_token": 0.00000025,
|
|
287
|
+
},
|
|
288
|
+
"claude-3-opus-20240229": {
|
|
289
|
+
"description": "Claude 3 Opus - Most capable model",
|
|
290
|
+
"max_tokens": 200000,
|
|
291
|
+
"cost_per_token": 0.000075,
|
|
292
|
+
},
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
config = model_configs.get(
|
|
296
|
+
self.model,
|
|
297
|
+
{
|
|
298
|
+
"description": f"Claude model {self.model}",
|
|
299
|
+
"max_tokens": 200000,
|
|
300
|
+
"cost_per_token": 0.000015,
|
|
301
|
+
},
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
return ModelInfo(
|
|
305
|
+
name=self.model,
|
|
306
|
+
provider="claude",
|
|
307
|
+
description=config["description"],
|
|
308
|
+
max_tokens=config["max_tokens"],
|
|
309
|
+
cost_per_token=config["cost_per_token"],
|
|
310
|
+
available=True,
|
|
311
|
+
supports_tools=True,
|
|
312
|
+
supports_multimodal=True,
|
|
313
|
+
latest_version=self.model == "claude-sonnet-4-20250514",
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
def _get_static_models(self) -> List[ModelInfo]:
|
|
317
|
+
"""
|
|
318
|
+
Get static list of available Claude models.
|
|
319
|
+
"""
|
|
320
|
+
return [
|
|
321
|
+
ModelInfo(
|
|
322
|
+
name="claude-sonnet-4-20250514",
|
|
323
|
+
provider="claude",
|
|
324
|
+
description="Claude Sonnet 4 - Latest and most capable model",
|
|
325
|
+
max_tokens=200000,
|
|
326
|
+
cost_per_token=0.000015,
|
|
327
|
+
available=True,
|
|
328
|
+
supports_tools=True,
|
|
329
|
+
supports_multimodal=True,
|
|
330
|
+
latest_version=True,
|
|
331
|
+
),
|
|
332
|
+
ModelInfo(
|
|
333
|
+
name="claude-opus-4-20250514",
|
|
334
|
+
provider="claude",
|
|
335
|
+
description="Claude Opus 4 - Most powerful model for complex tasks",
|
|
336
|
+
max_tokens=200000,
|
|
337
|
+
cost_per_token=0.000075,
|
|
338
|
+
available=True,
|
|
339
|
+
supports_tools=True,
|
|
340
|
+
supports_multimodal=True,
|
|
341
|
+
),
|
|
342
|
+
ModelInfo(
|
|
343
|
+
name="claude-3-5-sonnet-20241022",
|
|
344
|
+
provider="claude",
|
|
345
|
+
description="Claude 3.5 Sonnet - Enhanced reasoning and analysis",
|
|
346
|
+
max_tokens=200000,
|
|
347
|
+
cost_per_token=0.000015,
|
|
348
|
+
available=True,
|
|
349
|
+
supports_tools=True,
|
|
350
|
+
supports_multimodal=True,
|
|
351
|
+
),
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
async def fetch_live_models(self) -> List[ModelInfo]:
|
|
355
|
+
"""
|
|
356
|
+
Fetch live model list from Anthropic API.
|
|
357
|
+
|
|
358
|
+
Note: Anthropic doesn't have a public models list endpoint,
|
|
359
|
+
so we return an enhanced static list with current pricing.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
List of ModelInfo objects for Claude models
|
|
363
|
+
"""
|
|
364
|
+
# Anthropic doesn't provide a models list endpoint
|
|
365
|
+
# Return the latest known models with updated information
|
|
366
|
+
return [
|
|
367
|
+
ModelInfo(
|
|
368
|
+
name="claude-3-5-sonnet-20241022",
|
|
369
|
+
provider="claude",
|
|
370
|
+
description="Most intelligent model with enhanced coding capabilities",
|
|
371
|
+
max_tokens=8192,
|
|
372
|
+
cost_per_token=0.000003, # $3 per million input tokens
|
|
373
|
+
available=True,
|
|
374
|
+
supports_tools=True,
|
|
375
|
+
supports_multimodal=True,
|
|
376
|
+
latest_version=True,
|
|
377
|
+
),
|
|
378
|
+
ModelInfo(
|
|
379
|
+
name="claude-3-5-haiku-20241022",
|
|
380
|
+
provider="claude",
|
|
381
|
+
description="Fast model optimized for speed and efficiency",
|
|
382
|
+
max_tokens=8192,
|
|
383
|
+
cost_per_token=0.00000025, # $0.25 per million input tokens
|
|
384
|
+
available=True,
|
|
385
|
+
supports_tools=True,
|
|
386
|
+
supports_multimodal=True,
|
|
387
|
+
),
|
|
388
|
+
ModelInfo(
|
|
389
|
+
name="claude-3-opus-20240229",
|
|
390
|
+
provider="claude",
|
|
391
|
+
description="Previous generation powerful model for complex tasks",
|
|
392
|
+
max_tokens=4096,
|
|
393
|
+
cost_per_token=0.000015, # $15 per million input tokens
|
|
394
|
+
available=True,
|
|
395
|
+
supports_tools=True,
|
|
396
|
+
supports_multimodal=True,
|
|
397
|
+
),
|
|
398
|
+
ModelInfo(
|
|
399
|
+
name="claude-3-haiku-20240307",
|
|
400
|
+
provider="claude",
|
|
401
|
+
description="Previous generation fast and lightweight model",
|
|
402
|
+
max_tokens=4096,
|
|
403
|
+
cost_per_token=0.00000025, # $0.25 per million input tokens
|
|
404
|
+
available=True,
|
|
405
|
+
supports_tools=True,
|
|
406
|
+
supports_multimodal=True,
|
|
407
|
+
),
|
|
408
|
+
]
|
|
409
|
+
|
|
410
|
+
def supports_tools(self) -> bool:
|
|
411
|
+
"""
|
|
412
|
+
Check if Claude provider supports tool calling.
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
True - Claude supports tool calling
|
|
416
|
+
"""
|
|
417
|
+
return True
|
|
418
|
+
|
|
419
|
+
def supports_multimodal(self) -> bool:
|
|
420
|
+
"""
|
|
421
|
+
Check if Claude provider supports multimodal inputs.
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
True - Claude supports images and other multimodal inputs
|
|
425
|
+
"""
|
|
426
|
+
return True
|