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,406 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Claude-code provider implementation for Omnimancer.
|
|
3
|
+
|
|
4
|
+
This module provides the Claude-code provider implementation for local Claude-code integration
|
|
5
|
+
with support for opus and sonnet modes with free access.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import subprocess
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import List
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
from ..core.models import ChatContext, ChatResponse, EnhancedModelInfo
|
|
15
|
+
from ..utils.errors import (
|
|
16
|
+
AuthenticationError,
|
|
17
|
+
ModelNotFoundError,
|
|
18
|
+
ProviderError,
|
|
19
|
+
RateLimitError,
|
|
20
|
+
)
|
|
21
|
+
from .base import BaseProvider
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ClaudeCodeProvider(BaseProvider):
|
|
25
|
+
"""
|
|
26
|
+
Claude-code provider implementation for local Claude-code integration.
|
|
27
|
+
|
|
28
|
+
Provides integration with existing Claude-code installations,
|
|
29
|
+
supporting opus and sonnet modes with free local access.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, api_key: str = "local", model: str = "", **kwargs):
|
|
33
|
+
"""
|
|
34
|
+
Initialize Claude-code provider.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
api_key: Not used for Claude-code (local installation), defaults to "local"
|
|
38
|
+
model: Claude-code model mode (e.g., 'claude-code-sonnet', 'claude-code-opus', 'claude-code-haiku')
|
|
39
|
+
**kwargs: Additional configuration including Claude-code specific settings
|
|
40
|
+
"""
|
|
41
|
+
super().__init__(api_key or "local", model or "claude-code-sonnet", **kwargs)
|
|
42
|
+
|
|
43
|
+
# Claude-code specific configuration
|
|
44
|
+
self.claude_code_mode = kwargs.get(
|
|
45
|
+
"claude_code_mode", self._extract_mode_from_model()
|
|
46
|
+
)
|
|
47
|
+
self.claude_code_path = kwargs.get("claude_code_path", "claude")
|
|
48
|
+
self.working_directory = kwargs.get("working_directory", os.getcwd())
|
|
49
|
+
|
|
50
|
+
# Standard parameters (not all may be supported by claude-code)
|
|
51
|
+
self.max_tokens = kwargs.get("max_tokens", 4096)
|
|
52
|
+
self.temperature = kwargs.get("temperature", 0.7)
|
|
53
|
+
|
|
54
|
+
# Validate Claude-code installation
|
|
55
|
+
self._validate_installation()
|
|
56
|
+
|
|
57
|
+
def _extract_mode_from_model(self) -> str:
|
|
58
|
+
"""
|
|
59
|
+
Extract mode from model name.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Mode string (opus or sonnet)
|
|
63
|
+
"""
|
|
64
|
+
if "opus" in self.model.lower():
|
|
65
|
+
return "opus"
|
|
66
|
+
elif "sonnet" in self.model.lower():
|
|
67
|
+
return "sonnet"
|
|
68
|
+
else:
|
|
69
|
+
return "sonnet" # Default to sonnet
|
|
70
|
+
|
|
71
|
+
def _validate_installation(self):
|
|
72
|
+
"""
|
|
73
|
+
Validate that Claude-code is installed and accessible.
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
ProviderError: If Claude-code is not found or not working
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
# Try to run claude with version command
|
|
80
|
+
result = subprocess.run(
|
|
81
|
+
[self.claude_code_path, "--version"],
|
|
82
|
+
capture_output=True,
|
|
83
|
+
text=True,
|
|
84
|
+
timeout=10,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if result.returncode != 0:
|
|
88
|
+
# Try alternative command
|
|
89
|
+
result = subprocess.run(
|
|
90
|
+
[self.claude_code_path, "--help"],
|
|
91
|
+
capture_output=True,
|
|
92
|
+
text=True,
|
|
93
|
+
timeout=10,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if result.returncode != 0:
|
|
97
|
+
raise ProviderError(
|
|
98
|
+
f"Claude command not found or not working at: {self.claude_code_path}"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
except subprocess.TimeoutExpired:
|
|
102
|
+
raise ProviderError("Claude command timed out")
|
|
103
|
+
except FileNotFoundError:
|
|
104
|
+
raise ProviderError(f"Claude executable not found: {self.claude_code_path}")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
raise ProviderError(f"Error validating Claude installation: {e}")
|
|
107
|
+
|
|
108
|
+
async def send_message(self, message: str, context: ChatContext) -> ChatResponse:
|
|
109
|
+
"""
|
|
110
|
+
Send a message to Claude-code.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
message: User message
|
|
114
|
+
context: Conversation context
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
ChatResponse with Claude-code's reply
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
# Prepare the conversation for Claude-code
|
|
122
|
+
conversation = self._prepare_conversation(message, context)
|
|
123
|
+
result = await self._execute_claude_code(conversation)
|
|
124
|
+
response = self._handle_claude_code_response(result)
|
|
125
|
+
return response
|
|
126
|
+
|
|
127
|
+
except Exception as e:
|
|
128
|
+
raise ProviderError(f"Error communicating with Claude-code: {e}")
|
|
129
|
+
|
|
130
|
+
async def validate_credentials(self) -> bool:
|
|
131
|
+
"""
|
|
132
|
+
Validate Claude installation by running a test command.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
True if Claude is working
|
|
136
|
+
"""
|
|
137
|
+
try:
|
|
138
|
+
# Test with a simple message
|
|
139
|
+
test_result = await self._execute_claude_code("Hi")
|
|
140
|
+
return test_result.returncode == 0 and test_result.stdout.strip() != ""
|
|
141
|
+
except Exception:
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
def _prepare_conversation(self, message: str, context: ChatContext) -> str:
|
|
145
|
+
"""
|
|
146
|
+
Prepare conversation for Claude-code.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
message: Current user message
|
|
150
|
+
context: Conversation context
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Formatted conversation string
|
|
154
|
+
"""
|
|
155
|
+
conversation_parts = []
|
|
156
|
+
|
|
157
|
+
# Add context messages
|
|
158
|
+
for msg in context.messages:
|
|
159
|
+
if msg.role.value == "user":
|
|
160
|
+
conversation_parts.append(f"Human: {msg.content}")
|
|
161
|
+
elif msg.role.value == "assistant":
|
|
162
|
+
conversation_parts.append(f"Assistant: {msg.content}")
|
|
163
|
+
elif msg.role.value == "system":
|
|
164
|
+
conversation_parts.append(f"System: {msg.content}")
|
|
165
|
+
|
|
166
|
+
# Add current message
|
|
167
|
+
conversation_parts.append(f"Human: {message}")
|
|
168
|
+
|
|
169
|
+
return "\n\n".join(conversation_parts)
|
|
170
|
+
|
|
171
|
+
async def _execute_claude_code(
|
|
172
|
+
self, conversation: str
|
|
173
|
+
) -> subprocess.CompletedProcess:
|
|
174
|
+
"""
|
|
175
|
+
Execute Claude with the conversation.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
conversation: Formatted conversation string
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Subprocess result
|
|
182
|
+
"""
|
|
183
|
+
# Build command arguments - use --print for non-interactive mode
|
|
184
|
+
cmd = [self.claude_code_path, "--print"]
|
|
185
|
+
|
|
186
|
+
# Add model if supported
|
|
187
|
+
if hasattr(self, "claude_code_mode") and self.claude_code_mode:
|
|
188
|
+
if self.claude_code_mode == "opus":
|
|
189
|
+
cmd.extend(["--model", "opus"])
|
|
190
|
+
elif self.claude_code_mode == "sonnet":
|
|
191
|
+
cmd.extend(["--model", "sonnet"])
|
|
192
|
+
|
|
193
|
+
# Add the conversation as the prompt
|
|
194
|
+
cmd.append(conversation)
|
|
195
|
+
|
|
196
|
+
# Execute the command
|
|
197
|
+
try:
|
|
198
|
+
# Run in an executor to avoid blocking
|
|
199
|
+
import asyncio
|
|
200
|
+
|
|
201
|
+
loop = asyncio.get_event_loop()
|
|
202
|
+
|
|
203
|
+
result = await loop.run_in_executor(
|
|
204
|
+
None,
|
|
205
|
+
lambda: subprocess.run(
|
|
206
|
+
cmd,
|
|
207
|
+
capture_output=True,
|
|
208
|
+
text=True,
|
|
209
|
+
timeout=120, # 2 minute timeout for longer responses
|
|
210
|
+
cwd=self.working_directory,
|
|
211
|
+
),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return result
|
|
215
|
+
|
|
216
|
+
except subprocess.TimeoutExpired:
|
|
217
|
+
raise ProviderError("Claude command timed out")
|
|
218
|
+
except Exception as e:
|
|
219
|
+
raise ProviderError(f"Error executing Claude: {e}")
|
|
220
|
+
|
|
221
|
+
def _handle_claude_code_response(
|
|
222
|
+
self, result: subprocess.CompletedProcess
|
|
223
|
+
) -> ChatResponse:
|
|
224
|
+
"""
|
|
225
|
+
Handle Claude-code command result.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
result: Subprocess result from Claude-code
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
ChatResponse object
|
|
232
|
+
|
|
233
|
+
Raises:
|
|
234
|
+
ProviderError: If Claude-code returned an error
|
|
235
|
+
"""
|
|
236
|
+
if result.returncode == 0:
|
|
237
|
+
# Successful execution
|
|
238
|
+
output = result.stdout.strip()
|
|
239
|
+
|
|
240
|
+
if not output:
|
|
241
|
+
raise ProviderError("Empty response from Claude-code")
|
|
242
|
+
|
|
243
|
+
# Claude-code might include metadata or formatting
|
|
244
|
+
# Try to extract just the assistant's response
|
|
245
|
+
response_content = self._extract_response_content(output)
|
|
246
|
+
|
|
247
|
+
return ChatResponse(
|
|
248
|
+
content=response_content,
|
|
249
|
+
model_used=self.model,
|
|
250
|
+
tokens_used=0, # Claude-code doesn't provide token counts
|
|
251
|
+
timestamp=datetime.now(),
|
|
252
|
+
)
|
|
253
|
+
else:
|
|
254
|
+
# Error occurred
|
|
255
|
+
error_msg = result.stderr.strip() if result.stderr else "Unknown error"
|
|
256
|
+
|
|
257
|
+
# Check for common error patterns
|
|
258
|
+
if "authentication" in error_msg.lower() or "api key" in error_msg.lower():
|
|
259
|
+
raise AuthenticationError(
|
|
260
|
+
f"Claude-code authentication error: {error_msg}"
|
|
261
|
+
)
|
|
262
|
+
elif "rate limit" in error_msg.lower():
|
|
263
|
+
raise RateLimitError(f"Claude-code rate limit: {error_msg}")
|
|
264
|
+
elif "not found" in error_msg.lower():
|
|
265
|
+
raise ModelNotFoundError(f"Claude-code model not found: {error_msg}")
|
|
266
|
+
else:
|
|
267
|
+
raise ProviderError(f"Claude-code error: {error_msg}")
|
|
268
|
+
|
|
269
|
+
def _extract_response_content(self, output: str) -> str:
|
|
270
|
+
"""
|
|
271
|
+
Extract the actual response content from Claude output.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
output: Raw output from Claude --print
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Cleaned response content
|
|
278
|
+
"""
|
|
279
|
+
# Claude --print gives us clean output directly
|
|
280
|
+
# Just return the output stripped of whitespace
|
|
281
|
+
return output.strip()
|
|
282
|
+
|
|
283
|
+
def get_model_info(self) -> EnhancedModelInfo:
|
|
284
|
+
"""
|
|
285
|
+
Get information about the current Claude-code model.
|
|
286
|
+
"""
|
|
287
|
+
model_configs = {
|
|
288
|
+
"claude-code-opus": {
|
|
289
|
+
"description": "Claude-code Opus - Local free access to Claude Opus",
|
|
290
|
+
"max_tokens": 200000,
|
|
291
|
+
"swe_score": 84.9,
|
|
292
|
+
"supports_tools": False,
|
|
293
|
+
"supports_multimodal": True,
|
|
294
|
+
},
|
|
295
|
+
"claude-code-sonnet": {
|
|
296
|
+
"description": "Claude-code Sonnet - Local free access to Claude Sonnet",
|
|
297
|
+
"max_tokens": 200000,
|
|
298
|
+
"swe_score": 73.0,
|
|
299
|
+
"supports_tools": False,
|
|
300
|
+
"supports_multimodal": True,
|
|
301
|
+
},
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
config = model_configs.get(
|
|
305
|
+
self.model,
|
|
306
|
+
{
|
|
307
|
+
"description": f"Claude-code model {self.model}",
|
|
308
|
+
"max_tokens": 200000,
|
|
309
|
+
"swe_score": 75.0,
|
|
310
|
+
"supports_tools": False,
|
|
311
|
+
"supports_multimodal": True,
|
|
312
|
+
},
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
enhanced_info = EnhancedModelInfo(
|
|
316
|
+
name=self.model,
|
|
317
|
+
provider="claude-code",
|
|
318
|
+
description=config["description"],
|
|
319
|
+
max_tokens=config["max_tokens"],
|
|
320
|
+
cost_per_million_input=0.0, # Free local access
|
|
321
|
+
cost_per_million_output=0.0, # Free local access
|
|
322
|
+
swe_score=config["swe_score"],
|
|
323
|
+
available=True,
|
|
324
|
+
supports_tools=config["supports_tools"],
|
|
325
|
+
supports_multimodal=config["supports_multimodal"],
|
|
326
|
+
latest_version=self.model == "claude-code-opus",
|
|
327
|
+
context_window=config["max_tokens"],
|
|
328
|
+
is_free=True, # Local installation is free
|
|
329
|
+
release_date=datetime(2024, 3, 1), # Approximate availability
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
# Update SWE rating based on score
|
|
333
|
+
enhanced_info.update_swe_rating()
|
|
334
|
+
|
|
335
|
+
return enhanced_info
|
|
336
|
+
|
|
337
|
+
def get_available_models(self) -> List[EnhancedModelInfo]:
|
|
338
|
+
"""
|
|
339
|
+
Get list of available Claude-code models.
|
|
340
|
+
"""
|
|
341
|
+
models = [
|
|
342
|
+
EnhancedModelInfo(
|
|
343
|
+
name="claude-code-opus",
|
|
344
|
+
provider="claude-code",
|
|
345
|
+
description="Claude-code Opus - Local free access to Claude Opus",
|
|
346
|
+
max_tokens=200000,
|
|
347
|
+
cost_per_million_input=0.0,
|
|
348
|
+
cost_per_million_output=0.0,
|
|
349
|
+
swe_score=84.9,
|
|
350
|
+
available=True,
|
|
351
|
+
supports_tools=False,
|
|
352
|
+
supports_multimodal=True,
|
|
353
|
+
latest_version=True,
|
|
354
|
+
context_window=200000,
|
|
355
|
+
is_free=True,
|
|
356
|
+
release_date=datetime(2024, 3, 1),
|
|
357
|
+
),
|
|
358
|
+
EnhancedModelInfo(
|
|
359
|
+
name="claude-code-sonnet",
|
|
360
|
+
provider="claude-code",
|
|
361
|
+
description="Claude-code Sonnet - Local free access to Claude Sonnet",
|
|
362
|
+
max_tokens=200000,
|
|
363
|
+
cost_per_million_input=0.0,
|
|
364
|
+
cost_per_million_output=0.0,
|
|
365
|
+
swe_score=73.0,
|
|
366
|
+
available=True,
|
|
367
|
+
supports_tools=False,
|
|
368
|
+
supports_multimodal=True,
|
|
369
|
+
context_window=200000,
|
|
370
|
+
is_free=True,
|
|
371
|
+
release_date=datetime(2024, 3, 1),
|
|
372
|
+
),
|
|
373
|
+
]
|
|
374
|
+
|
|
375
|
+
# Update SWE ratings for all models
|
|
376
|
+
for model in models:
|
|
377
|
+
model.update_swe_rating()
|
|
378
|
+
|
|
379
|
+
return models
|
|
380
|
+
|
|
381
|
+
def supports_tools(self) -> bool:
|
|
382
|
+
"""
|
|
383
|
+
Check if Claude-code provider supports tool calling.
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
False - Claude-code typically doesn't support tool calling
|
|
387
|
+
"""
|
|
388
|
+
return False
|
|
389
|
+
|
|
390
|
+
def supports_multimodal(self) -> bool:
|
|
391
|
+
"""
|
|
392
|
+
Check if Claude-code provider supports multimodal inputs.
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
True - Claude models support multimodal inputs
|
|
396
|
+
"""
|
|
397
|
+
return True
|
|
398
|
+
|
|
399
|
+
def supports_streaming(self) -> bool:
|
|
400
|
+
"""
|
|
401
|
+
Check if Claude-code provider supports streaming responses.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
False - Local command execution doesn't support streaming
|
|
405
|
+
"""
|
|
406
|
+
return False
|