kolega-code 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.
- kolega_code/__init__.py +151 -0
- kolega_code/agent/__init__.py +42 -0
- kolega_code/agent/baseagent.py +998 -0
- kolega_code/agent/browseragent.py +123 -0
- kolega_code/agent/coder.py +157 -0
- kolega_code/agent/common.py +41 -0
- kolega_code/agent/compression.py +81 -0
- kolega_code/agent/context.py +112 -0
- kolega_code/agent/conversation.py +408 -0
- kolega_code/agent/generalagent.py +146 -0
- kolega_code/agent/investigationagent.py +123 -0
- kolega_code/agent/planningagent.py +187 -0
- kolega_code/agent/prompt_provider.py +196 -0
- kolega_code/agent/prompt_templates/agents/browser.j2 +102 -0
- kolega_code/agent/prompt_templates/agents/coder_cli_mode.j2 +127 -0
- kolega_code/agent/prompt_templates/agents/general.j2 +68 -0
- kolega_code/agent/prompt_templates/agents/investigation.j2 +72 -0
- kolega_code/agent/prompt_templates/common/frontend_guidance.md +36 -0
- kolega_code/agent/prompt_templates/common/kolega_md_instructions.md +14 -0
- kolega_code/agent/prompt_templates/environment_variables/workspace_env_vars.md +11 -0
- kolega_code/agent/prompt_templates/template_guidance/expo-template.md +379 -0
- kolega_code/agent/prompt_templates/template_guidance/html-website-template.md +3 -0
- kolega_code/agent/prompt_templates/template_guidance/mern-stack-template.md +3 -0
- kolega_code/agent/prompt_templates/template_guidance/react-vite-shadcdn-template.md +182 -0
- kolega_code/agent/prompts.py +192 -0
- kolega_code/agent/tests/__init__.py +0 -0
- kolega_code/agent/tests/llm/__init__.py +0 -0
- kolega_code/agent/tests/llm/test_anthropic_token_counting.py +633 -0
- kolega_code/agent/tests/llm/test_billing_openai_cache.py +74 -0
- kolega_code/agent/tests/llm/test_client.py +773 -0
- kolega_code/agent/tests/llm/test_dashscope_mapping.py +32 -0
- kolega_code/agent/tests/llm/test_error_boundary.py +322 -0
- kolega_code/agent/tests/llm/test_exceptions.py +249 -0
- kolega_code/agent/tests/llm/test_instrumented_client.py +536 -0
- kolega_code/agent/tests/llm/test_instrumented_client_integration.py +547 -0
- kolega_code/agent/tests/llm/test_langfuse_normalization.py +39 -0
- kolega_code/agent/tests/llm/test_model_specs.py +17 -0
- kolega_code/agent/tests/llm/test_openai_cached_tokens.py +58 -0
- kolega_code/agent/tests/llm/test_openai_cached_tokens_stream.py +74 -0
- kolega_code/agent/tests/llm/test_openai_message_conversion.py +30 -0
- kolega_code/agent/tests/llm/test_openai_token_counting.py +687 -0
- kolega_code/agent/tests/llm/test_tool_execution_ids.py +193 -0
- kolega_code/agent/tests/services/__init__.py +1 -0
- kolega_code/agent/tests/services/test_browser.py +447 -0
- kolega_code/agent/tests/services/test_browser_parity.py +353 -0
- kolega_code/agent/tests/services/test_file_system.py +699 -0
- kolega_code/agent/tests/services/test_sandbox_terminal_input.py +98 -0
- kolega_code/agent/tests/services/test_terminal.py +154 -0
- kolega_code/agent/tests/services/test_terminal_command_tracking.py +385 -0
- kolega_code/agent/tests/services/test_terminal_state_serializer.py +262 -0
- kolega_code/agent/tests/test_agent_tools_inventory.py +267 -0
- kolega_code/agent/tests/test_base_agent.py +1942 -0
- kolega_code/agent/tests/test_coder_attachments.py +330 -0
- kolega_code/agent/tests/test_coder_prompt_extensions.py +61 -0
- kolega_code/agent/tests/test_commands.py +179 -0
- kolega_code/agent/tests/test_duplicate_tool_results.py +556 -0
- kolega_code/agent/tests/test_empty_message_handling.py +48 -0
- kolega_code/agent/tests/test_general_agent.py +242 -0
- kolega_code/agent/tests/test_html.py +320 -0
- kolega_code/agent/tests/test_parallel_tool_calls.py +291 -0
- kolega_code/agent/tests/test_planning_agent.py +227 -0
- kolega_code/agent/tests/test_prompt_provider.py +271 -0
- kolega_code/agent/tests/test_tool_registry.py +102 -0
- kolega_code/agent/tests/test_tools.py +549 -0
- kolega_code/agent/tests/tool_backend/__init__.py +0 -0
- kolega_code/agent/tests/tool_backend/test_agent_tool.py +356 -0
- kolega_code/agent/tests/tool_backend/test_base_tool.py +147 -0
- kolega_code/agent/tests/tool_backend/test_browser_tool.py +335 -0
- kolega_code/agent/tests/tool_backend/test_build_tool.py +93 -0
- kolega_code/agent/tests/tool_backend/test_create_file_tool.py +115 -0
- kolega_code/agent/tests/tool_backend/test_glob_tool.py +196 -0
- kolega_code/agent/tests/tool_backend/test_glob_tool_sandbox_parity.py +230 -0
- kolega_code/agent/tests/tool_backend/test_list_directory_tool.py +292 -0
- kolega_code/agent/tests/tool_backend/test_read_file_tool.py +173 -0
- kolega_code/agent/tests/tool_backend/test_replace_entire_file_tool.py +115 -0
- kolega_code/agent/tests/tool_backend/test_replace_lines_tool.py +141 -0
- kolega_code/agent/tests/tool_backend/test_search_and_replace_tool.py +174 -0
- kolega_code/agent/tests/tool_backend/test_search_codebase_tool.py +228 -0
- kolega_code/agent/tests/tool_backend/test_terminal_tool.py +482 -0
- kolega_code/agent/tests/tool_backend/test_think_hard_integration.py +189 -0
- kolega_code/agent/tests/tool_backend/test_think_hard_streaming.py +445 -0
- kolega_code/agent/tests/tool_backend/test_web_fetch_tool.py +194 -0
- kolega_code/agent/tool_backend/agent_tool.py +414 -0
- kolega_code/agent/tool_backend/apply_edit_tool.py +98 -0
- kolega_code/agent/tool_backend/apply_patch_tool.py +514 -0
- kolega_code/agent/tool_backend/base_tool.py +217 -0
- kolega_code/agent/tool_backend/browser_tool.py +271 -0
- kolega_code/agent/tool_backend/build_tool.py +93 -0
- kolega_code/agent/tool_backend/create_file_tool.py +52 -0
- kolega_code/agent/tool_backend/glob_tool.py +323 -0
- kolega_code/agent/tool_backend/list_directory_tool.py +300 -0
- kolega_code/agent/tool_backend/memory_tool.py +79 -0
- kolega_code/agent/tool_backend/read_file_tool.py +119 -0
- kolega_code/agent/tool_backend/replace_entire_file_tool.py +40 -0
- kolega_code/agent/tool_backend/replace_lines_tool.py +97 -0
- kolega_code/agent/tool_backend/search_and_replace_tool.py +146 -0
- kolega_code/agent/tool_backend/search_codebase_tool.py +377 -0
- kolega_code/agent/tool_backend/streaming_tool.py +47 -0
- kolega_code/agent/tool_backend/terminal_tool.py +643 -0
- kolega_code/agent/tool_backend/think_hard_tool.py +211 -0
- kolega_code/agent/tool_backend/web_fetch_tool.py +205 -0
- kolega_code/agent/tools.py +1704 -0
- kolega_code/agent/utils/commands.py +94 -0
- kolega_code/cli/__init__.py +1 -0
- kolega_code/cli/app.py +2756 -0
- kolega_code/cli/config.py +280 -0
- kolega_code/cli/connection.py +49 -0
- kolega_code/cli/file_index.py +147 -0
- kolega_code/cli/main.py +564 -0
- kolega_code/cli/mentions.py +155 -0
- kolega_code/cli/messages.py +89 -0
- kolega_code/cli/provider_registry.py +96 -0
- kolega_code/cli/session_store.py +207 -0
- kolega_code/cli/settings.py +87 -0
- kolega_code/cli/skills.py +409 -0
- kolega_code/cli/slash_commands.py +108 -0
- kolega_code/cli/tests/__init__.py +1 -0
- kolega_code/cli/tests/test_app.py +4251 -0
- kolega_code/cli/tests/test_cli_config.py +171 -0
- kolega_code/cli/tests/test_connection.py +26 -0
- kolega_code/cli/tests/test_file_index.py +103 -0
- kolega_code/cli/tests/test_main.py +455 -0
- kolega_code/cli/tests/test_mentions.py +108 -0
- kolega_code/cli/tests/test_session_store.py +67 -0
- kolega_code/cli/tests/test_settings.py +62 -0
- kolega_code/cli/tests/test_skills.py +157 -0
- kolega_code/cli/tests/test_slash_commands.py +88 -0
- kolega_code/cli/theme.py +180 -0
- kolega_code/config.py +154 -0
- kolega_code/events.py +202 -0
- kolega_code/llm/client.py +300 -0
- kolega_code/llm/exceptions.py +285 -0
- kolega_code/llm/instrumented_client.py +520 -0
- kolega_code/llm/models.py +1368 -0
- kolega_code/llm/providers/__init__.py +0 -0
- kolega_code/llm/providers/anthropic.py +387 -0
- kolega_code/llm/providers/base.py +71 -0
- kolega_code/llm/providers/google.py +157 -0
- kolega_code/llm/providers/models.py +37 -0
- kolega_code/llm/providers/openai.py +363 -0
- kolega_code/llm/ratelimit.py +40 -0
- kolega_code/llm/specs.py +67 -0
- kolega_code/llm/tool_execution_ids.py +18 -0
- kolega_code/models/__init__.py +9 -0
- kolega_code/models/sandbox_terminal_state.py +47 -0
- kolega_code/runtime.py +50 -0
- kolega_code/sandbox/README.md +200 -0
- kolega_code/sandbox/__init__.py +21 -0
- kolega_code/sandbox/async_filesystem.py +475 -0
- kolega_code/sandbox/base.py +297 -0
- kolega_code/sandbox/browser.py +25 -0
- kolega_code/sandbox/event_loop.py +43 -0
- kolega_code/sandbox/filesystem.py +341 -0
- kolega_code/sandbox/local.py +118 -0
- kolega_code/sandbox/serializer.py +175 -0
- kolega_code/sandbox/terminal.py +868 -0
- kolega_code/sandbox/utils.py +216 -0
- kolega_code/services/base.py +255 -0
- kolega_code/services/browser.py +444 -0
- kolega_code/services/file_system.py +749 -0
- kolega_code/services/html.py +221 -0
- kolega_code/services/terminal.py +903 -0
- kolega_code/tools/__init__.py +22 -0
- kolega_code/tools/core.py +33 -0
- kolega_code/tools/definitions.py +81 -0
- kolega_code/tools/registry.py +73 -0
- kolega_code-0.1.0.dist-info/METADATA +157 -0
- kolega_code-0.1.0.dist-info/RECORD +171 -0
- kolega_code-0.1.0.dist-info/WHEEL +4 -0
- kolega_code-0.1.0.dist-info/entry_points.txt +2 -0
- kolega_code-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines custom exception classes for handling errors related to
|
|
3
|
+
Large Language Model (LLM) interactions across different providers. It provides a
|
|
4
|
+
base `LLMError` class and specific subclasses for common error scenarios.
|
|
5
|
+
Additionally, it includes utility functions to map provider-specific errors
|
|
6
|
+
(OpenAI, Google, Anthropic) to these standardized exceptions.
|
|
7
|
+
|
|
8
|
+
Error Mapping:
|
|
9
|
+
|
|
10
|
+
| Provider | Status Code | Mapped LLMError |
|
|
11
|
+
|-----------|-------------|--------------------------------|
|
|
12
|
+
| OpenAI | 400 | `LLMInvalidRequestError` |
|
|
13
|
+
| OpenAI | 401 | `LLMAuthenticationError` |
|
|
14
|
+
| OpenAI | 403 | `LLMPermissionDeniedError` |
|
|
15
|
+
| OpenAI | 404 | `LLMNotFoundError` |
|
|
16
|
+
| OpenAI | 422 | `LLMUnprocessableEntityError` |
|
|
17
|
+
| OpenAI | 429 | `LLMRateLimitError` |
|
|
18
|
+
| OpenAI | 500 | `LLMInternalServerError` |
|
|
19
|
+
| OpenAI | Other | `LLMError` |
|
|
20
|
+
| Google | 400 | `LLMInvalidRequestError` |
|
|
21
|
+
| Google | 403 | `LLMPermissionDeniedError` |
|
|
22
|
+
| Google | 429 | `LLMRateLimitError` |
|
|
23
|
+
| Google | 500 | `LLMInternalServerError` |
|
|
24
|
+
| Google | Other | `LLMError` |
|
|
25
|
+
| Anthropic | 400 | `LLMInvalidRequestError` |
|
|
26
|
+
| Anthropic | 401 | `LLMAuthenticationError` |
|
|
27
|
+
| Anthropic | 403 | `LLMPermissionDeniedError` |
|
|
28
|
+
| Anthropic | 404 | `LLMNotFoundError` |
|
|
29
|
+
| Anthropic | 413 | `LLMContextWindowExceededError`|
|
|
30
|
+
| Anthropic | 429 | `LLMRateLimitError` |
|
|
31
|
+
| Anthropic | 500 | `LLMInternalServerError` |
|
|
32
|
+
| Anthropic | 529 | `LLMInternalServerError` |
|
|
33
|
+
| Anthropic | Other | `LLMError` |
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import asyncio
|
|
38
|
+
|
|
39
|
+
from anthropic import (
|
|
40
|
+
AnthropicError,
|
|
41
|
+
APIStatusError as AnthropicAPIStatusError,
|
|
42
|
+
InternalServerError as AnthropicInternalServerError,
|
|
43
|
+
)
|
|
44
|
+
from google.genai.errors import APIError as GoogleAPIError
|
|
45
|
+
from openai import OpenAIError
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
import aiohttp
|
|
49
|
+
except ImportError:
|
|
50
|
+
aiohttp = None # Handle case where aiohttp not installed
|
|
51
|
+
|
|
52
|
+
# Handle httpx being optional. If installed, we will map certain httpx errors.
|
|
53
|
+
try:
|
|
54
|
+
import httpx
|
|
55
|
+
except ImportError:
|
|
56
|
+
httpx = None
|
|
57
|
+
|
|
58
|
+
from ..config import ModelProvider
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class LLMError(Exception):
|
|
62
|
+
"""Base exception class for all LLM-related errors."""
|
|
63
|
+
|
|
64
|
+
def __init__(self, message: str, model: str = None, provider: str = None):
|
|
65
|
+
super().__init__(message)
|
|
66
|
+
self.provider = provider
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class LLMBadRequestError(LLMError):
|
|
70
|
+
"""Raised when the request to the LLM service is malformed or invalid."""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class LLMUnsupportedParamsError(LLMError):
|
|
74
|
+
"""Raised when unsupported parameters are provided to the LLM service."""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class LLMContextWindowExceededError(LLMError):
|
|
78
|
+
"""Raised when the input exceeds the model's maximum context window size."""
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class LLMContentPolicyViolationError(LLMError):
|
|
82
|
+
"""Raised when the request violates the LLM provider's content policy."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class LLMInvalidRequestError(LLMError):
|
|
86
|
+
"""Raised when the request is invalid for reasons other than malformed data."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class LLMAuthenticationError(LLMError):
|
|
90
|
+
"""Raised when authentication with the LLM service fails."""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class LLMPermissionDeniedError(LLMError):
|
|
94
|
+
"""Raised when the authenticated user lacks permission for the requested operation."""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class LLMNotFoundError(LLMError):
|
|
98
|
+
"""Raised when the requested resource is not found."""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class LLMTimeout(LLMError):
|
|
102
|
+
"""Raised when the request to the LLM service times out."""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class LLMUnprocessableEntityError(LLMError):
|
|
106
|
+
"""Raised when the request is well-formed but cannot be processed."""
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class LLMRateLimitError(LLMError):
|
|
110
|
+
"""Raised when the rate limit for the LLM service is exceeded."""
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class LLMInternalServerError(LLMError):
|
|
114
|
+
"""Raised when the LLM service encounters an internal error."""
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def map_openai_errors(error: OpenAIError) -> LLMError:
|
|
118
|
+
if hasattr(error, "status_code"):
|
|
119
|
+
if error.status_code == 400:
|
|
120
|
+
return LLMInvalidRequestError(message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value)
|
|
121
|
+
elif error.status_code == 401:
|
|
122
|
+
return LLMAuthenticationError(message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value)
|
|
123
|
+
elif error.status_code == 403:
|
|
124
|
+
return LLMPermissionDeniedError(
|
|
125
|
+
message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value
|
|
126
|
+
)
|
|
127
|
+
elif error.status_code == 404:
|
|
128
|
+
return LLMNotFoundError(message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value)
|
|
129
|
+
elif error.status_code == 422:
|
|
130
|
+
return LLMUnprocessableEntityError(
|
|
131
|
+
message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value
|
|
132
|
+
)
|
|
133
|
+
elif error.status_code == 429:
|
|
134
|
+
return LLMRateLimitError(message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value)
|
|
135
|
+
elif error.status_code == 500:
|
|
136
|
+
return LLMInternalServerError(message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value)
|
|
137
|
+
|
|
138
|
+
return LLMError(message=f"OpenAI APIError: {str(error)}", provider=ModelProvider.OPENAI.value)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def map_google_errors(error: GoogleAPIError) -> LLMError:
|
|
142
|
+
if hasattr(error, "status"):
|
|
143
|
+
|
|
144
|
+
if error.status == 400:
|
|
145
|
+
return LLMInvalidRequestError(message=f"GoogleAPIError: {str(error)}", provider=ModelProvider.GOOGLE.value)
|
|
146
|
+
elif error.status == 403:
|
|
147
|
+
return LLMPermissionDeniedError(
|
|
148
|
+
message=f"GoogleAPIError: {str(error)}", provider=ModelProvider.GOOGLE.value
|
|
149
|
+
)
|
|
150
|
+
elif error.status == 429:
|
|
151
|
+
return LLMRateLimitError(message=f"GoogleAPIError: {str(error)}", provider=ModelProvider.GOOGLE.value)
|
|
152
|
+
elif error.status == 500:
|
|
153
|
+
return LLMInternalServerError(message=f"GoogleAPIError: {str(error)}", provider=ModelProvider.GOOGLE.value)
|
|
154
|
+
|
|
155
|
+
return LLMError(message=f"Google APIError: {str(error)}", provider=ModelProvider.GOOGLE.value)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def map_anthropic_errors(error: AnthropicError) -> LLMError:
|
|
159
|
+
context_window_phrases = (
|
|
160
|
+
"exceeded model token limit",
|
|
161
|
+
"context window",
|
|
162
|
+
"maximum context length",
|
|
163
|
+
"prompt is too long",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if type(error) == AnthropicAPIStatusError:
|
|
167
|
+
try:
|
|
168
|
+
error_data = error.body
|
|
169
|
+
if isinstance(error_data, dict) and "error" in error_data:
|
|
170
|
+
error_info = error_data["error"]
|
|
171
|
+
error_type = error_info.get("type")
|
|
172
|
+
error_message = (error_info.get("message") or "").strip()
|
|
173
|
+
error_message_lower = error_message.lower()
|
|
174
|
+
|
|
175
|
+
# Keep internal/server overload handling by type
|
|
176
|
+
if error_type in ["overloaded_error", "api_error"]:
|
|
177
|
+
return LLMInternalServerError(
|
|
178
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if any(phrase in error_message_lower for phrase in context_window_phrases):
|
|
182
|
+
return LLMContextWindowExceededError(
|
|
183
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Special case: content filtering block should be mapped to content policy violation
|
|
187
|
+
if (
|
|
188
|
+
error_type == "invalid_request_error"
|
|
189
|
+
and error_message == "Output blocked by content filtering policy"
|
|
190
|
+
):
|
|
191
|
+
return LLMContentPolicyViolationError(
|
|
192
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
except Exception:
|
|
196
|
+
pass
|
|
197
|
+
|
|
198
|
+
if type(error) == AnthropicInternalServerError:
|
|
199
|
+
return LLMInternalServerError(message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value)
|
|
200
|
+
|
|
201
|
+
print("continuing Anthropic error mapping...")
|
|
202
|
+
if hasattr(error, "status_code"):
|
|
203
|
+
if error.status_code == 400:
|
|
204
|
+
error_text = str(error).lower()
|
|
205
|
+
if any(phrase in error_text for phrase in context_window_phrases):
|
|
206
|
+
return LLMContextWindowExceededError(
|
|
207
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
208
|
+
)
|
|
209
|
+
return LLMInvalidRequestError(
|
|
210
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
211
|
+
)
|
|
212
|
+
elif error.status_code == 401:
|
|
213
|
+
return LLMAuthenticationError(
|
|
214
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
215
|
+
)
|
|
216
|
+
elif error.status_code == 403:
|
|
217
|
+
return LLMPermissionDeniedError(
|
|
218
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
219
|
+
)
|
|
220
|
+
elif error.status_code == 404:
|
|
221
|
+
return LLMNotFoundError(message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value)
|
|
222
|
+
elif error.status_code == 413:
|
|
223
|
+
return LLMContextWindowExceededError(
|
|
224
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
225
|
+
)
|
|
226
|
+
if error.status_code == 429:
|
|
227
|
+
return LLMRateLimitError(message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value)
|
|
228
|
+
if error.status_code == 500:
|
|
229
|
+
return LLMInternalServerError(
|
|
230
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
231
|
+
)
|
|
232
|
+
if error.status_code == 529:
|
|
233
|
+
return LLMInternalServerError(
|
|
234
|
+
message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
return LLMError(message=f"AnthropicError: {str(error)}", provider=ModelProvider.ANTHROPIC.value)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def map_to_llm_error(error: Exception, provider: str = None) -> LLMError:
|
|
241
|
+
"""Map any exception to a standardized LLM error.
|
|
242
|
+
|
|
243
|
+
This function provides a single point of control for converting any exception
|
|
244
|
+
type into an appropriate LLMError subclass. It ensures that only LLMError
|
|
245
|
+
exceptions escape from the LLM client layer.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
error: The exception to map
|
|
249
|
+
provider: Optional provider name for context
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
An appropriate LLMError subclass instance
|
|
253
|
+
"""
|
|
254
|
+
# If already an LLM error, return as-is
|
|
255
|
+
if isinstance(error, LLMError):
|
|
256
|
+
return error
|
|
257
|
+
|
|
258
|
+
# Map provider-specific errors using existing functions
|
|
259
|
+
if isinstance(error, OpenAIError):
|
|
260
|
+
return map_openai_errors(error)
|
|
261
|
+
elif isinstance(error, GoogleAPIError):
|
|
262
|
+
return map_google_errors(error)
|
|
263
|
+
elif isinstance(error, AnthropicError):
|
|
264
|
+
return map_anthropic_errors(error)
|
|
265
|
+
|
|
266
|
+
# Map common Python exceptions
|
|
267
|
+
if isinstance(error, ValueError):
|
|
268
|
+
return LLMInvalidRequestError(message=f"Invalid parameter: {str(error)}", provider=provider)
|
|
269
|
+
elif isinstance(error, (TimeoutError, asyncio.TimeoutError)):
|
|
270
|
+
return LLMTimeout(message=f"Request timeout: {str(error)}", provider=provider)
|
|
271
|
+
elif isinstance(error, ConnectionError):
|
|
272
|
+
return LLMInternalServerError(message=f"Connection error: {str(error)}", provider=provider)
|
|
273
|
+
elif aiohttp and isinstance(error, aiohttp.ClientError):
|
|
274
|
+
return LLMInternalServerError(message=f"HTTP client error: {str(error)}", provider=provider)
|
|
275
|
+
elif httpx and isinstance(error, httpx.RemoteProtocolError):
|
|
276
|
+
return LLMInternalServerError(message=f"HTTPX protocol error: {str(error)}", provider=provider)
|
|
277
|
+
elif isinstance(error, KeyError):
|
|
278
|
+
return LLMInvalidRequestError(message=f"Missing required parameter: {str(error)}", provider=provider)
|
|
279
|
+
elif isinstance(error, TypeError):
|
|
280
|
+
return LLMInvalidRequestError(message=f"Invalid parameter type: {str(error)}", provider=provider)
|
|
281
|
+
elif isinstance(error, RuntimeError):
|
|
282
|
+
return LLMInternalServerError(message=f"Runtime error: {str(error)}", provider=provider)
|
|
283
|
+
|
|
284
|
+
# Default fallback for any other exception
|
|
285
|
+
return LLMError(message=f"Unexpected error ({type(error).__name__}): {str(error)}", provider=provider)
|