alita-sdk 0.3.516__py3-none-any.whl → 0.3.528__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.
Potentially problematic release.
This version of alita-sdk might be problematic. Click here for more details.
- alita_sdk/runtime/clients/client.py +49 -21
- alita_sdk/runtime/clients/sandbox_client.py +0 -35
- alita_sdk/runtime/langchain/assistant.py +3 -2
- alita_sdk/runtime/langchain/constants.py +129 -7
- alita_sdk/runtime/langchain/langraph_agent.py +1 -1
- alita_sdk/runtime/toolkits/application.py +5 -2
- alita_sdk/runtime/toolkits/tools.py +2 -1
- alita_sdk/runtime/tools/llm.py +156 -8
- alita_sdk/tools/testrail/api_wrapper.py +1 -1
- {alita_sdk-0.3.516.dist-info → alita_sdk-0.3.528.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.516.dist-info → alita_sdk-0.3.528.dist-info}/RECORD +15 -15
- {alita_sdk-0.3.516.dist-info → alita_sdk-0.3.528.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.516.dist-info → alita_sdk-0.3.528.dist-info}/entry_points.txt +0 -0
- {alita_sdk-0.3.516.dist-info → alita_sdk-0.3.528.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.516.dist-info → alita_sdk-0.3.528.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@ from langchain_core.messages import (
|
|
|
13
13
|
from langchain_core.tools import ToolException
|
|
14
14
|
from langgraph.store.base import BaseStore
|
|
15
15
|
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
|
|
16
|
+
from langchain_anthropic import ChatAnthropic
|
|
16
17
|
|
|
17
18
|
from ..langchain.assistant import Assistant as LangChainAssistant
|
|
18
19
|
# from ..llamaindex.assistant import Assistant as LLamaAssistant
|
|
@@ -219,21 +220,25 @@ class AlitaClient:
|
|
|
219
220
|
request_timeout=self.model_timeout
|
|
220
221
|
)
|
|
221
222
|
|
|
222
|
-
def get_llm(self, model_name: str, model_config: dict)
|
|
223
|
+
def get_llm(self, model_name: str, model_config: dict):
|
|
223
224
|
"""
|
|
224
|
-
Get a ChatOpenAI model instance based on the model name and configuration.
|
|
225
|
+
Get a ChatOpenAI or ChatAnthropic model instance based on the model name and configuration.
|
|
225
226
|
|
|
226
227
|
Args:
|
|
227
228
|
model_name: Name of the model to retrieve
|
|
228
229
|
model_config: Configuration parameters for the model
|
|
229
230
|
|
|
230
231
|
Returns:
|
|
231
|
-
An instance of ChatOpenAI configured with the provided parameters.
|
|
232
|
+
An instance of ChatOpenAI or ChatAnthropic configured with the provided parameters.
|
|
232
233
|
"""
|
|
233
234
|
if not model_name:
|
|
234
235
|
raise ValueError("Model name must be provided")
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
# Determine if this is an Anthropic model
|
|
238
|
+
model_name_lower = model_name.lower()
|
|
239
|
+
is_anthropic = "anthropic" in model_name_lower or "claude" in model_name_lower
|
|
240
|
+
|
|
241
|
+
logger.info(f"Creating {'ChatAnthropic' if is_anthropic else 'ChatOpenAI'} model: {model_name} with config: {model_config}")
|
|
237
242
|
|
|
238
243
|
try:
|
|
239
244
|
from tools import this # pylint: disable=E0401,C0415
|
|
@@ -256,25 +261,48 @@ class AlitaClient:
|
|
|
256
261
|
# default nuber for a case when auto is selected for an agent
|
|
257
262
|
llm_max_tokens = 4000
|
|
258
263
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if use_responses_api:
|
|
274
|
-
target_kwargs["use_responses_api"] = True
|
|
264
|
+
if is_anthropic:
|
|
265
|
+
# ChatAnthropic configuration
|
|
266
|
+
target_kwargs = {
|
|
267
|
+
"base_url": f"{self.base_url}{self.llm_path}",
|
|
268
|
+
"model": model_name,
|
|
269
|
+
"api_key": self.auth_token,
|
|
270
|
+
"streaming": model_config.get("streaming", True),
|
|
271
|
+
"max_tokens": llm_max_tokens,
|
|
272
|
+
"effort": model_config.get("reasoning_effort"),
|
|
273
|
+
"temperature": model_config.get("temperature"),
|
|
274
|
+
"max_retries": model_config.get("max_retries", 3),
|
|
275
|
+
"default_headers": {"openai-organization": str(self.project_id)},
|
|
276
|
+
}
|
|
275
277
|
|
|
276
|
-
|
|
278
|
+
# Add http_client if provided
|
|
279
|
+
if "http_client" in model_config:
|
|
280
|
+
target_kwargs["http_client"] = model_config["http_client"]
|
|
281
|
+
|
|
282
|
+
llm = ChatAnthropic(**target_kwargs)
|
|
283
|
+
else:
|
|
284
|
+
# ChatOpenAI configuration
|
|
285
|
+
target_kwargs = {
|
|
286
|
+
"base_url": f"{self.base_url}{self.llm_path}",
|
|
287
|
+
"model": model_name,
|
|
288
|
+
"api_key": self.auth_token,
|
|
289
|
+
"streaming": model_config.get("streaming", True),
|
|
290
|
+
"stream_usage": model_config.get("stream_usage", True),
|
|
291
|
+
"max_tokens": llm_max_tokens,
|
|
292
|
+
"temperature": model_config.get("temperature"),
|
|
293
|
+
"reasoning_effort": model_config.get("reasoning_effort"),
|
|
294
|
+
"max_retries": model_config.get("max_retries", 3),
|
|
295
|
+
"seed": model_config.get("seed", None),
|
|
296
|
+
"openai_organization": str(self.project_id),
|
|
297
|
+
}
|
|
277
298
|
|
|
299
|
+
if use_responses_api:
|
|
300
|
+
target_kwargs["use_responses_api"] = True
|
|
301
|
+
|
|
302
|
+
llm = ChatOpenAI(**target_kwargs)
|
|
303
|
+
|
|
304
|
+
return llm
|
|
305
|
+
|
|
278
306
|
def generate_image(self,
|
|
279
307
|
prompt: str,
|
|
280
308
|
n: int = 1,
|
|
@@ -6,7 +6,6 @@ import requests
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
from json import dumps
|
|
8
8
|
import chardet
|
|
9
|
-
from ...tools import instantiate_toolkit
|
|
10
9
|
|
|
11
10
|
logger = logging.getLogger(__name__)
|
|
12
11
|
|
|
@@ -49,27 +48,6 @@ class SandboxArtifact:
|
|
|
49
48
|
return f'{data['error']}. {data['content'] if data['content'] else ''}'
|
|
50
49
|
detected = chardet.detect(data)
|
|
51
50
|
return data
|
|
52
|
-
# TODO: add proper handling for binary files (images, pdf, etc.) for sandbox
|
|
53
|
-
# if detected['encoding'] is not None:
|
|
54
|
-
# try:
|
|
55
|
-
# return data.decode(detected['encoding'])
|
|
56
|
-
# except Exception:
|
|
57
|
-
# logger.error('Error while default encoding')
|
|
58
|
-
# return parse_file_content(file_name=artifact_name,
|
|
59
|
-
# file_content=data,
|
|
60
|
-
# is_capture_image=is_capture_image,
|
|
61
|
-
# page_number=page_number,
|
|
62
|
-
# sheet_name=sheet_name,
|
|
63
|
-
# excel_by_sheets=excel_by_sheets,
|
|
64
|
-
# llm=llm)
|
|
65
|
-
# else:
|
|
66
|
-
# return parse_file_content(file_name=artifact_name,
|
|
67
|
-
# file_content=data,
|
|
68
|
-
# is_capture_image=is_capture_image,
|
|
69
|
-
# page_number=page_number,
|
|
70
|
-
# sheet_name=sheet_name,
|
|
71
|
-
# excel_by_sheets=excel_by_sheets,
|
|
72
|
-
# llm=llm)
|
|
73
51
|
|
|
74
52
|
def delete(self, artifact_name: str, bucket_name=None):
|
|
75
53
|
if not bucket_name:
|
|
@@ -185,19 +163,6 @@ class SandboxClient:
|
|
|
185
163
|
data = requests.get(url, headers=self.headers, verify=False).json()
|
|
186
164
|
return data
|
|
187
165
|
|
|
188
|
-
def toolkit(self, toolkit_id: int):
|
|
189
|
-
url = f"{self.base_url}{self.api_path}/tool/prompt_lib/{self.project_id}/{toolkit_id}"
|
|
190
|
-
response = requests.get(url, headers=self.headers, verify=False)
|
|
191
|
-
if not response.ok:
|
|
192
|
-
raise ValueError(f"Failed to fetch toolkit {toolkit_id}: {response.text}")
|
|
193
|
-
|
|
194
|
-
tool_data = response.json()
|
|
195
|
-
if 'settings' not in tool_data:
|
|
196
|
-
tool_data['settings'] = {}
|
|
197
|
-
tool_data['settings']['alita'] = self
|
|
198
|
-
|
|
199
|
-
return instantiate_toolkit(tool_data)
|
|
200
|
-
|
|
201
166
|
def get_list_of_apps(self):
|
|
202
167
|
apps = []
|
|
203
168
|
limit = 10
|
|
@@ -278,6 +278,7 @@ class Assistant:
|
|
|
278
278
|
prompt_instructions = self.prompt
|
|
279
279
|
|
|
280
280
|
# Add tool binding only if tools are present
|
|
281
|
+
tool_names = []
|
|
281
282
|
if simple_tools:
|
|
282
283
|
tool_names = [tool.name for tool in simple_tools]
|
|
283
284
|
logger.info("Binding tools: %s", tool_names)
|
|
@@ -290,8 +291,8 @@ class Assistant:
|
|
|
290
291
|
plan_addon = PLAN_ADDON if 'update_plan' in tool_names else ""
|
|
291
292
|
pyodite_addon = PYODITE_ADDON if 'pyodide_sandbox' in tool_names else ""
|
|
292
293
|
escaped_prompt = DEFAULT_ASSISTANT.format(
|
|
293
|
-
|
|
294
|
-
|
|
294
|
+
users_instructions=user_addon,
|
|
295
|
+
planning_instructions=plan_addon,
|
|
295
296
|
pyodite_addon=pyodite_addon
|
|
296
297
|
)
|
|
297
298
|
|
|
@@ -345,14 +345,136 @@ PYODITE_ADDON = """
|
|
|
345
345
|
|
|
346
346
|
## Using the Python (Pyodide) sandbox
|
|
347
347
|
|
|
348
|
-
Python sandbox
|
|
348
|
+
Python sandbox available via `pyodide_sandbox` (stateless) or `stateful_pyodide_sandbox` tools.
|
|
349
|
+
|
|
350
|
+
### Use for:
|
|
351
|
+
- Lightweight data analysis, parsing, validation
|
|
352
|
+
- Testing algorithms and calculations
|
|
353
|
+
- Processing standard library modules
|
|
354
|
+
|
|
355
|
+
### Limitations:
|
|
356
|
+
- No local filesystem access (beyond sandbox cache)
|
|
357
|
+
- No OS commands or subprocess operations
|
|
358
|
+
- No native C extensions
|
|
359
|
+
- No background processes
|
|
360
|
+
|
|
361
|
+
### CRITICAL: How to return results
|
|
362
|
+
|
|
363
|
+
The sandbox returns a dict with these keys:
|
|
364
|
+
- **`result`**: The last evaluated expression (final line without assignment)
|
|
365
|
+
- **`output`**: Anything printed via `print()`
|
|
366
|
+
- **`error`**: Any stderr output
|
|
367
|
+
- **`execution_info`**: Timing and package info
|
|
368
|
+
|
|
369
|
+
**Two valid patterns to return data:**
|
|
370
|
+
|
|
371
|
+
✅ Option 1 - Last expression (returned in `result` key):
|
|
372
|
+
```python
|
|
373
|
+
import json
|
|
374
|
+
data = {"result": 42, "status": "complete"}
|
|
375
|
+
data # Auto-captured as result
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
✅ Option 2 - Print output (returned in `output` key):
|
|
379
|
+
```python
|
|
380
|
+
import json
|
|
381
|
+
data = {"result": 42, "status": "complete"}
|
|
382
|
+
print(json.dumps(data)) # Captured as output
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Both work! Choose based on preference. For structured data, JSON format is recommended.
|
|
386
|
+
|
|
387
|
+
### Using alita_client (auto-injected)
|
|
388
|
+
|
|
389
|
+
The `alita_client` object is automatically available in sandbox code. It provides access to Alita platform APIs.
|
|
390
|
+
|
|
391
|
+
**Key capabilities:**
|
|
392
|
+
|
|
393
|
+
**Artifacts** - Store/retrieve files in buckets:
|
|
394
|
+
```python
|
|
395
|
+
# Get artifact from bucket and decode
|
|
396
|
+
csv_data = alita_client.artifact('my_bucket').get('file.csv').decode('utf-8')
|
|
397
|
+
|
|
398
|
+
# Create/overwrite artifact
|
|
399
|
+
alita_client.artifact('my_bucket').create('output.txt', 'data content')
|
|
400
|
+
|
|
401
|
+
# List artifacts in bucket
|
|
402
|
+
files = alita_client.artifact('my_bucket').list()
|
|
403
|
+
|
|
404
|
+
# Append to artifact
|
|
405
|
+
alita_client.artifact('my_bucket').append('log.txt', 'new line\\n')
|
|
406
|
+
|
|
407
|
+
# Delete artifact
|
|
408
|
+
alita_client.artifact('my_bucket').delete('old_file.txt')
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Secrets** - Access stored credentials:
|
|
412
|
+
```python
|
|
413
|
+
api_key = alita_client.unsecret('my_api_key')
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**MCP Tools** - Call Model Context Protocol tools:
|
|
417
|
+
```python
|
|
418
|
+
# List available tools
|
|
419
|
+
tools = alita_client.get_mcp_toolkits()
|
|
420
|
+
|
|
421
|
+
# Call a tool
|
|
422
|
+
result = alita_client.mcp_tool_call({
|
|
423
|
+
'server_name': 'my_server',
|
|
424
|
+
'params': {
|
|
425
|
+
'name': 'tool_name',
|
|
426
|
+
'arguments': {'arg1': 'value1'}
|
|
427
|
+
}
|
|
428
|
+
})
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Toolkits** - Instantiate and use toolkits:
|
|
432
|
+
```python
|
|
433
|
+
toolkit = alita_client.toolkit(toolkit_id=123)
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Applications** - Get app details:
|
|
437
|
+
```python
|
|
438
|
+
apps = alita_client.get_list_of_apps()
|
|
439
|
+
app_details = alita_client.get_app_details(application_id=456)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Image Generation**:
|
|
443
|
+
```python
|
|
444
|
+
result = alita_client.generate_image(
|
|
445
|
+
prompt="A sunset over mountains",
|
|
446
|
+
n=1,
|
|
447
|
+
size="1024x1024"
|
|
448
|
+
)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Common pattern - Load CSV from artifacts:**
|
|
452
|
+
```python
|
|
453
|
+
import csv
|
|
454
|
+
from io import StringIO
|
|
455
|
+
|
|
456
|
+
# Load CSV from artifact
|
|
457
|
+
csv_text = alita_client.artifact('tests').get('data.csv').decode('utf-8')
|
|
458
|
+
|
|
459
|
+
# Parse CSV
|
|
460
|
+
reader = csv.DictReader(StringIO(csv_text))
|
|
461
|
+
data = list(reader)
|
|
462
|
+
|
|
463
|
+
# Return result
|
|
464
|
+
data
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Execution modes:
|
|
468
|
+
- **Stateless** (default): Faster, each run starts fresh
|
|
469
|
+
- **Stateful**: Preserves variables/imports between calls
|
|
349
470
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
471
|
+
### Code requirements:
|
|
472
|
+
1. Always include necessary imports
|
|
473
|
+
2. Either end with an expression OR use `print()` for output
|
|
474
|
+
3. Work with in-memory data only
|
|
475
|
+
4. Include error handling with try-except
|
|
355
476
|
|
|
356
|
-
|
|
477
|
+
### When NOT to use:
|
|
478
|
+
For large datasets, long-running tasks, or native system access, request alternative tools instead.
|
|
357
479
|
|
|
358
480
|
"""
|
|
@@ -937,7 +937,7 @@ class LangGraphAgentRunnable(CompiledStateGraph):
|
|
|
937
937
|
"with no accompanying text."
|
|
938
938
|
)
|
|
939
939
|
|
|
940
|
-
|
|
940
|
+
logger.info(f"Input: {thread_id} - {input}")
|
|
941
941
|
try:
|
|
942
942
|
if self.checkpointer and self.checkpointer.get_tuple(config):
|
|
943
943
|
if config.pop("should_continue", False):
|
|
@@ -22,7 +22,8 @@ class ApplicationToolkit(BaseToolkit):
|
|
|
22
22
|
|
|
23
23
|
@classmethod
|
|
24
24
|
def get_toolkit(cls, client: 'AlitaClient', application_id: int, application_version_id: int,
|
|
25
|
-
selected_tools: list[str] = [], store: Optional[BaseStore] = None
|
|
25
|
+
selected_tools: list[str] = [], store: Optional[BaseStore] = None,
|
|
26
|
+
ignored_mcp_servers: Optional[list] = None):
|
|
26
27
|
|
|
27
28
|
app_details = client.get_app_details(application_id)
|
|
28
29
|
version_details = client.get_app_version_details(application_id, application_version_id)
|
|
@@ -34,7 +35,8 @@ class ApplicationToolkit(BaseToolkit):
|
|
|
34
35
|
|
|
35
36
|
app = client.application(application_id, application_version_id, store=store,
|
|
36
37
|
llm=client.get_llm(version_details['llm_settings']['model_name'],
|
|
37
|
-
model_settings)
|
|
38
|
+
model_settings),
|
|
39
|
+
ignored_mcp_servers=ignored_mcp_servers)
|
|
38
40
|
return cls(tools=[Application(name=app_details.get("name"),
|
|
39
41
|
description=app_details.get("description"),
|
|
40
42
|
application=app,
|
|
@@ -46,6 +48,7 @@ class ApplicationToolkit(BaseToolkit):
|
|
|
46
48
|
"application_version_id": application_version_id,
|
|
47
49
|
"store": store,
|
|
48
50
|
"llm": client.get_llm(version_details['llm_settings']['model_name'], model_settings),
|
|
51
|
+
"ignored_mcp_servers": ignored_mcp_servers,
|
|
49
52
|
})])
|
|
50
53
|
|
|
51
54
|
def get_tools(self):
|
|
@@ -59,7 +59,8 @@ def get_tools(tools_list: list, alita_client=None, llm=None, memory_store: BaseS
|
|
|
59
59
|
alita_client,
|
|
60
60
|
application_id=int(tool['settings']['application_id']),
|
|
61
61
|
application_version_id=int(tool['settings']['application_version_id']),
|
|
62
|
-
selected_tools=[]
|
|
62
|
+
selected_tools=[],
|
|
63
|
+
ignored_mcp_servers=ignored_mcp_servers
|
|
63
64
|
).get_tools())
|
|
64
65
|
# backward compatibility for pipeline application type as subgraph node
|
|
65
66
|
if tool.get('agent_type', '') == 'pipeline':
|
alita_sdk/runtime/tools/llm.py
CHANGED
|
@@ -14,6 +14,35 @@ from ..langchain.utils import create_pydantic_model, propagate_the_input_mapping
|
|
|
14
14
|
logger = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
# def _is_thinking_model(llm_client: Any) -> bool:
|
|
18
|
+
# """
|
|
19
|
+
# Check if a model uses extended thinking capability by reading cached metadata.
|
|
20
|
+
|
|
21
|
+
# Thinking models require special message formatting where assistant messages
|
|
22
|
+
# must start with thinking blocks before tool_use blocks.
|
|
23
|
+
|
|
24
|
+
# This function reads the `_supports_reasoning` attribute that should be set
|
|
25
|
+
# when the LLM client is created (by checking the model's supports_reasoning field).
|
|
26
|
+
|
|
27
|
+
# Args:
|
|
28
|
+
# llm_client: LLM client instance with optional _supports_reasoning attribute
|
|
29
|
+
|
|
30
|
+
# Returns:
|
|
31
|
+
# True if the model is a thinking model, False otherwise
|
|
32
|
+
# """
|
|
33
|
+
# if not llm_client:
|
|
34
|
+
# return False
|
|
35
|
+
|
|
36
|
+
# # Check if supports_reasoning was cached on the client
|
|
37
|
+
# supports_reasoning = getattr(llm_client, '_supports_reasoning', False)
|
|
38
|
+
|
|
39
|
+
# if supports_reasoning:
|
|
40
|
+
# model_name = getattr(llm_client, 'model_name', None) or getattr(llm_client, 'model', 'unknown')
|
|
41
|
+
# logger.debug(f"Model '{model_name}' is a thinking/reasoning model (cached from API metadata)")
|
|
42
|
+
|
|
43
|
+
# return supports_reasoning
|
|
44
|
+
|
|
45
|
+
|
|
17
46
|
class LLMNode(BaseTool):
|
|
18
47
|
"""Enhanced LLM node with chat history and tool binding support"""
|
|
19
48
|
|
|
@@ -242,7 +271,12 @@ class LLMNode(BaseTool):
|
|
|
242
271
|
return {"messages": new_messages}
|
|
243
272
|
|
|
244
273
|
except Exception as e:
|
|
274
|
+
# Enhanced error logging with model diagnostics
|
|
275
|
+
model_info = getattr(llm_client, 'model_name', None) or getattr(llm_client, 'model', 'unknown')
|
|
245
276
|
logger.error(f"Error in LLM Node: {format_exc()}")
|
|
277
|
+
logger.error(f"Model being used: {model_info}")
|
|
278
|
+
logger.error(f"Error type: {type(e).__name__}")
|
|
279
|
+
|
|
246
280
|
error_msg = f"Error: {e}"
|
|
247
281
|
new_messages = messages + [AIMessage(content=error_msg)]
|
|
248
282
|
return {"messages": new_messages}
|
|
@@ -403,6 +437,20 @@ class LLMNode(BaseTool):
|
|
|
403
437
|
async def __perform_tool_calling(self, completion, messages, llm_client, config):
|
|
404
438
|
# Handle iterative tool-calling and execution
|
|
405
439
|
logger.info(f"__perform_tool_calling called with {len(completion.tool_calls) if hasattr(completion, 'tool_calls') else 0} tool calls")
|
|
440
|
+
|
|
441
|
+
# Check if this is a thinking model - they require special message handling
|
|
442
|
+
# model_name = getattr(llm_client, 'model_name', None) or getattr(llm_client, 'model', '')
|
|
443
|
+
# if _is_thinking_model(llm_client):
|
|
444
|
+
# logger.warning(
|
|
445
|
+
# f"⚠️ THINKING/REASONING MODEL DETECTED: '{model_name}'\n"
|
|
446
|
+
# f"Tool execution with thinking models may fail due to message format requirements.\n"
|
|
447
|
+
# f"Thinking models require 'thinking_blocks' to be preserved between turns, which this "
|
|
448
|
+
# f"framework cannot do.\n"
|
|
449
|
+
# f"Recommendation: Use standard model variants (e.g., claude-3-5-sonnet-20241022-v2:0) "
|
|
450
|
+
# f"instead of thinking/reasoning variants for tool calling.\n"
|
|
451
|
+
# f"See: https://docs.litellm.ai/docs/reasoning_content"
|
|
452
|
+
# )
|
|
453
|
+
|
|
406
454
|
new_messages = messages + [completion]
|
|
407
455
|
iteration = 0
|
|
408
456
|
|
|
@@ -511,6 +559,29 @@ class LLMNode(BaseTool):
|
|
|
511
559
|
except Exception as e:
|
|
512
560
|
error_str = str(e).lower()
|
|
513
561
|
|
|
562
|
+
# Check for thinking model message format errors
|
|
563
|
+
is_thinking_format_error = any(indicator in error_str for indicator in [
|
|
564
|
+
'expected `thinking`',
|
|
565
|
+
'expected `redacted_thinking`',
|
|
566
|
+
'thinking block',
|
|
567
|
+
'must start with a thinking block',
|
|
568
|
+
'when `thinking` is enabled'
|
|
569
|
+
])
|
|
570
|
+
|
|
571
|
+
# Check for non-recoverable errors that should fail immediately
|
|
572
|
+
# These indicate configuration or permission issues, not content size issues
|
|
573
|
+
is_non_recoverable = any(indicator in error_str for indicator in [
|
|
574
|
+
'model identifier is invalid',
|
|
575
|
+
'authentication',
|
|
576
|
+
'unauthorized',
|
|
577
|
+
'access denied',
|
|
578
|
+
'permission denied',
|
|
579
|
+
'invalid credentials',
|
|
580
|
+
'api key',
|
|
581
|
+
'quota exceeded',
|
|
582
|
+
'rate limit'
|
|
583
|
+
])
|
|
584
|
+
|
|
514
585
|
# Check for context window / token limit errors
|
|
515
586
|
is_context_error = any(indicator in error_str for indicator in [
|
|
516
587
|
'context window', 'context_window', 'token limit', 'too long',
|
|
@@ -518,17 +589,76 @@ class LLMNode(BaseTool):
|
|
|
518
589
|
'contextwindowexceedederror', 'max_tokens', 'content too large'
|
|
519
590
|
])
|
|
520
591
|
|
|
521
|
-
# Check for Bedrock/Claude output limit errors
|
|
522
|
-
# These often manifest as "model identifier is invalid" when output exceeds limits
|
|
592
|
+
# Check for Bedrock/Claude output limit errors (recoverable by truncation)
|
|
523
593
|
is_output_limit_error = any(indicator in error_str for indicator in [
|
|
524
|
-
'model identifier is invalid',
|
|
525
|
-
'bedrockexception',
|
|
526
594
|
'output token',
|
|
527
595
|
'response too large',
|
|
528
596
|
'max_tokens_to_sample',
|
|
529
|
-
'output_token_limit'
|
|
597
|
+
'output_token_limit',
|
|
598
|
+
'output exceeds'
|
|
530
599
|
])
|
|
531
600
|
|
|
601
|
+
# Handle thinking model format errors
|
|
602
|
+
if is_thinking_format_error:
|
|
603
|
+
model_info = getattr(llm_client, 'model_name', None) or getattr(llm_client, 'model', 'unknown')
|
|
604
|
+
logger.error(f"Thinking model message format error during tool execution iteration {iteration}")
|
|
605
|
+
logger.error(f"Model: {model_info}")
|
|
606
|
+
logger.error(f"Error details: {e}")
|
|
607
|
+
|
|
608
|
+
error_msg = (
|
|
609
|
+
f"⚠️ THINKING MODEL FORMAT ERROR\n\n"
|
|
610
|
+
f"The model '{model_info}' uses extended thinking and requires specific message formatting.\n\n"
|
|
611
|
+
f"**Issue**: When 'thinking' is enabled, assistant messages must start with thinking blocks "
|
|
612
|
+
f"before any tool_use blocks. This framework cannot preserve thinking_blocks during iterative "
|
|
613
|
+
f"tool execution.\n\n"
|
|
614
|
+
f"**Root Cause**: Anthropic's Messages API is stateless - clients must manually preserve and "
|
|
615
|
+
f"resend thinking_blocks with every tool response. LangChain's message abstraction doesn't "
|
|
616
|
+
f"include thinking_blocks, so they are lost between turns.\n\n"
|
|
617
|
+
f"**Solutions**:\n"
|
|
618
|
+
f"1. **Recommended**: Use non-thinking model variants:\n"
|
|
619
|
+
f" - claude-3-5-sonnet-20241022-v2:0 (instead of thinking variants)\n"
|
|
620
|
+
f" - anthropic.claude-3-5-sonnet-20241022-v2:0 (Bedrock)\n"
|
|
621
|
+
f"2. Disable extended thinking: Set reasoning_effort=None or remove thinking config\n"
|
|
622
|
+
f"3. Use LiteLLM directly with modify_params=True (handles thinking_blocks automatically)\n"
|
|
623
|
+
f"4. Avoid tool calling with thinking models (use for reasoning tasks only)\n\n"
|
|
624
|
+
f"**Technical Context**: {str(e)}\n\n"
|
|
625
|
+
f"References:\n"
|
|
626
|
+
f"- https://docs.claude.com/en/docs/build-with-claude/extended-thinking\n"
|
|
627
|
+
f"- https://docs.litellm.ai/docs/reasoning_content (See 'Tool Calling with thinking' section)"
|
|
628
|
+
)
|
|
629
|
+
new_messages.append(AIMessage(content=error_msg))
|
|
630
|
+
raise ValueError(error_msg)
|
|
631
|
+
|
|
632
|
+
# Handle non-recoverable errors immediately
|
|
633
|
+
if is_non_recoverable:
|
|
634
|
+
# Enhanced error logging with model information for better diagnostics
|
|
635
|
+
model_info = getattr(llm_client, 'model_name', None) or getattr(llm_client, 'model', 'unknown')
|
|
636
|
+
logger.error(f"Non-recoverable error during tool execution iteration {iteration}")
|
|
637
|
+
logger.error(f"Model: {model_info}")
|
|
638
|
+
logger.error(f"Error details: {e}")
|
|
639
|
+
logger.error(f"Error type: {type(e).__name__}")
|
|
640
|
+
|
|
641
|
+
# Provide detailed error message for debugging
|
|
642
|
+
error_details = []
|
|
643
|
+
error_details.append(f"Model configuration error: {str(e)}")
|
|
644
|
+
error_details.append(f"Model identifier: {model_info}")
|
|
645
|
+
|
|
646
|
+
# Check for common Bedrock model ID issues
|
|
647
|
+
if 'model identifier is invalid' in error_str:
|
|
648
|
+
error_details.append("\nPossible causes:")
|
|
649
|
+
error_details.append("1. Model not available in the configured AWS region")
|
|
650
|
+
error_details.append("2. Model not enabled in your AWS Bedrock account")
|
|
651
|
+
error_details.append("3. LiteLLM model group prefix not stripped (check for prefixes like '1_')")
|
|
652
|
+
error_details.append("4. Incorrect model version or typo in model name")
|
|
653
|
+
error_details.append("\nPlease verify:")
|
|
654
|
+
error_details.append("- AWS Bedrock console shows this model as available")
|
|
655
|
+
error_details.append("- LiteLLM router configuration is correct")
|
|
656
|
+
error_details.append("- Model ID doesn't contain unexpected prefixes")
|
|
657
|
+
|
|
658
|
+
error_msg = "\n".join(error_details)
|
|
659
|
+
new_messages.append(AIMessage(content=error_msg))
|
|
660
|
+
break
|
|
661
|
+
|
|
532
662
|
if is_context_error or is_output_limit_error:
|
|
533
663
|
error_type = "output limit" if is_output_limit_error else "context window"
|
|
534
664
|
logger.warning(f"{error_type.title()} exceeded during tool execution iteration {iteration}")
|
|
@@ -595,9 +725,27 @@ class LLMNode(BaseTool):
|
|
|
595
725
|
)
|
|
596
726
|
new_messages[last_tool_msg_idx] = truncated_msg
|
|
597
727
|
|
|
598
|
-
logger.info(f"Truncated large tool result from '{last_tool_name}' and
|
|
599
|
-
|
|
600
|
-
|
|
728
|
+
logger.info(f"Truncated large tool result from '{last_tool_name}' and retrying LLM call")
|
|
729
|
+
|
|
730
|
+
# CRITICAL FIX: Call LLM again with truncated message to get fresh completion
|
|
731
|
+
# This prevents duplicate tool_call_ids that occur when we continue with
|
|
732
|
+
# the same current_completion that still has the original tool_calls
|
|
733
|
+
try:
|
|
734
|
+
current_completion = llm_client.invoke(new_messages, config=config)
|
|
735
|
+
new_messages.append(current_completion)
|
|
736
|
+
|
|
737
|
+
# Continue to process any new tool calls in the fresh completion
|
|
738
|
+
if hasattr(current_completion, 'tool_calls') and current_completion.tool_calls:
|
|
739
|
+
logger.info(f"LLM requested {len(current_completion.tool_calls)} more tool calls after truncation")
|
|
740
|
+
continue
|
|
741
|
+
else:
|
|
742
|
+
logger.info("LLM completed after truncation without requesting more tools")
|
|
743
|
+
break
|
|
744
|
+
except Exception as retry_error:
|
|
745
|
+
logger.error(f"Error retrying LLM after truncation: {retry_error}")
|
|
746
|
+
error_msg = f"Failed to retry after truncation: {str(retry_error)}"
|
|
747
|
+
new_messages.append(AIMessage(content=error_msg))
|
|
748
|
+
break
|
|
601
749
|
else:
|
|
602
750
|
# Couldn't find tool message, add error and break
|
|
603
751
|
if is_output_limit_error:
|
|
@@ -697,7 +697,7 @@ class TestrailAPIWrapper(NonCodeIndexerToolkit):
|
|
|
697
697
|
'id': str(case.get('id', '')),
|
|
698
698
|
IndexerKeywords.UPDATED_ON.value: case.get('updated_on') or -1,
|
|
699
699
|
'labels': [lbl['title'] for lbl in case.get('labels', [])],
|
|
700
|
-
'type':
|
|
700
|
+
'type': "testrail_test_case",
|
|
701
701
|
'priority': case.get('priority_id') or -1,
|
|
702
702
|
'milestone': case.get('milestone_id') or -1,
|
|
703
703
|
'estimate': case.get('estimate') or '',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alita_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.528
|
|
4
4
|
Summary: SDK for building langchain agents using resources from Alita
|
|
5
5
|
Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedj27@gmail.com>, Artem Dubrovskiy <ad13box@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -93,18 +93,18 @@ alita_sdk/configurations/zephyr_essential.py,sha256=TiZedsBlfIDroflipvoqxjJeEWPo
|
|
|
93
93
|
alita_sdk/runtime/__init__.py,sha256=4W0UF-nl3QF2bvET5lnah4o24CoTwSoKXhuN0YnwvEE,828
|
|
94
94
|
alita_sdk/runtime/clients/__init__.py,sha256=BdehU5GBztN1Qi1Wul0cqlU46FxUfMnI6Vq2Zd_oq1M,296
|
|
95
95
|
alita_sdk/runtime/clients/artifact.py,sha256=7C1e9RtftqOJd3Mo5gNDnBuYg1Z9xTqjxmfdWeJH5Cc,4014
|
|
96
|
-
alita_sdk/runtime/clients/client.py,sha256=
|
|
96
|
+
alita_sdk/runtime/clients/client.py,sha256=LUQ-pH3tmp_f4uh_8ss0KP1c-wyr34ZJMT9Qyonpg6Y,53394
|
|
97
97
|
alita_sdk/runtime/clients/datasource.py,sha256=HAZovoQN9jBg0_-lIlGBQzb4FJdczPhkHehAiVG3Wx0,1020
|
|
98
98
|
alita_sdk/runtime/clients/mcp_discovery.py,sha256=aFJ0wYQ8EAmXa9qLUusHZfQXkNec1wbgkqHdVeSFX-g,11697
|
|
99
99
|
alita_sdk/runtime/clients/mcp_manager.py,sha256=DRbqiO761l7UgOdv_keHbD2g0oZodtPHejpArXYZIoE,9050
|
|
100
100
|
alita_sdk/runtime/clients/prompt.py,sha256=li1RG9eBwgNK_Qf0qUaZ8QNTmsncFrAL2pv3kbxZRZg,1447
|
|
101
|
-
alita_sdk/runtime/clients/sandbox_client.py,sha256=
|
|
101
|
+
alita_sdk/runtime/clients/sandbox_client.py,sha256=z8emjrMe9hkEKOnr19qDxRzXG1ug-XJXBKQzGtjXEAs,15390
|
|
102
102
|
alita_sdk/runtime/langchain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
103
|
-
alita_sdk/runtime/langchain/assistant.py,sha256
|
|
103
|
+
alita_sdk/runtime/langchain/assistant.py,sha256=yVTosONjQYUHbzhtTWG53odpXbWCQLLe18oaqniqvx8,18447
|
|
104
104
|
alita_sdk/runtime/langchain/chat_message_template.py,sha256=kPz8W2BG6IMyITFDA5oeb5BxVRkHEVZhuiGl4MBZKdc,2176
|
|
105
|
-
alita_sdk/runtime/langchain/constants.py,sha256=
|
|
105
|
+
alita_sdk/runtime/langchain/constants.py,sha256=tbVA-OPRDzEMspO9raOj_jb57Yt-TUYulG6FOXCmu78,17150
|
|
106
106
|
alita_sdk/runtime/langchain/indexer.py,sha256=0ENHy5EOhThnAiYFc7QAsaTNp9rr8hDV_hTK8ahbatk,37592
|
|
107
|
-
alita_sdk/runtime/langchain/langraph_agent.py,sha256=
|
|
107
|
+
alita_sdk/runtime/langchain/langraph_agent.py,sha256=vQ5HPzgngNgZ6amco7PPx0Gn0TdaW8dvYVexPT68bB8,59363
|
|
108
108
|
alita_sdk/runtime/langchain/mixedAgentParser.py,sha256=M256lvtsL3YtYflBCEp-rWKrKtcY1dJIyRGVv7KW9ME,2611
|
|
109
109
|
alita_sdk/runtime/langchain/mixedAgentRenderes.py,sha256=asBtKqm88QhZRILditjYICwFVKF5KfO38hu2O-WrSWE,5964
|
|
110
110
|
alita_sdk/runtime/langchain/store_manager.py,sha256=i8Fl11IXJhrBXq1F1ukEVln57B1IBe-tqSUvfUmBV4A,2218
|
|
@@ -157,7 +157,7 @@ alita_sdk/runtime/llms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
157
157
|
alita_sdk/runtime/llms/preloaded.py,sha256=tZ_-nIV91cjgdNV5xw5cIlvia9CYUG94PTsoNRmTF-I,11223
|
|
158
158
|
alita_sdk/runtime/models/mcp_models.py,sha256=rbWCAtF8Jjb7uNgQHhVWyDttXaqPNbRLL087Lf0AjNU,2301
|
|
159
159
|
alita_sdk/runtime/toolkits/__init__.py,sha256=7bic6YGLiyAwFD3KZvrntWqS57sND72VoGBhuAx75yI,692
|
|
160
|
-
alita_sdk/runtime/toolkits/application.py,sha256=
|
|
160
|
+
alita_sdk/runtime/toolkits/application.py,sha256=iHs6PzNIbwalDtSP2LuIsqiWGxQSFI2pubKXIFGPB8k,2938
|
|
161
161
|
alita_sdk/runtime/toolkits/artifact.py,sha256=_m7Ppwc04cpL0RPU_5ZHXFjBIWLeylv1if-H16OvF-o,3737
|
|
162
162
|
alita_sdk/runtime/toolkits/configurations.py,sha256=kIDAlnryPQfbZyFxV-9SzN2-Vefzx06TX1BBdIIpN90,141
|
|
163
163
|
alita_sdk/runtime/toolkits/datasource.py,sha256=ZNPCAAZKy90u_5CKkr6fi7gaLuao2KOIV8spGjb-AbA,2926
|
|
@@ -165,7 +165,7 @@ alita_sdk/runtime/toolkits/mcp.py,sha256=4KOobcuCUsZGza1CJ0EUdYRTL9v4pJwM2Joswxi
|
|
|
165
165
|
alita_sdk/runtime/toolkits/planning.py,sha256=6i83WDkjRs-b8UNlDub44NHzUFUgTVuxQ_IHSuHI85U,7433
|
|
166
166
|
alita_sdk/runtime/toolkits/prompt.py,sha256=WIpTkkVYWqIqOWR_LlSWz3ug8uO9tm5jJ7aZYdiGRn0,1192
|
|
167
167
|
alita_sdk/runtime/toolkits/subgraph.py,sha256=wwUK8JjPXkGzyVZ3tAukmvST6eGbqx_U11rpnmbrvtg,2105
|
|
168
|
-
alita_sdk/runtime/toolkits/tools.py,sha256=
|
|
168
|
+
alita_sdk/runtime/toolkits/tools.py,sha256=WjoszaL2o-w_8vy0JkulXc02HP_vNdvl-CWwWTkkYO8,17647
|
|
169
169
|
alita_sdk/runtime/toolkits/vectorstore.py,sha256=H-HQsHhLm-vQWS3kvwkh-OHrOWKuylBXcSH9cQo5jKM,3282
|
|
170
170
|
alita_sdk/runtime/tools/__init__.py,sha256=Fx7iHqkzA90-KfjdcUUzMUI_7kDarjuTsSpSzOW2pN0,568
|
|
171
171
|
alita_sdk/runtime/tools/agent.py,sha256=m98QxOHwnCRTT9j18Olbb5UPS8-ZGeQaGiUyZJSyFck,3162
|
|
@@ -177,7 +177,7 @@ alita_sdk/runtime/tools/function.py,sha256=HSMO1nBTRKMvWC_m0M8TOLGaZ2k_7ksPgLqzu
|
|
|
177
177
|
alita_sdk/runtime/tools/graph.py,sha256=7jImBBSEdP5Mjnn2keOiyUwdGDFhEXLUrgUiugO3mgA,3503
|
|
178
178
|
alita_sdk/runtime/tools/image_generation.py,sha256=Kls9D_ke_SK7xmVr7I9SlQcAEBJc86gf66haN0qIj9k,7469
|
|
179
179
|
alita_sdk/runtime/tools/indexer_tool.py,sha256=whSLPevB4WD6dhh2JDXEivDmTvbjiMV1MrPl9cz5eLA,4375
|
|
180
|
-
alita_sdk/runtime/tools/llm.py,sha256=
|
|
180
|
+
alita_sdk/runtime/tools/llm.py,sha256=lLDqsOef6-zakNcZdd9_5iJyZ3-wBXunPEH0h9qsnyY,44774
|
|
181
181
|
alita_sdk/runtime/tools/loop.py,sha256=uds0WhZvwMxDVFI6MZHrcmMle637cQfBNg682iLxoJA,8335
|
|
182
182
|
alita_sdk/runtime/tools/loop_output.py,sha256=U4hO9PCQgWlXwOq6jdmCGbegtAxGAPXObSxZQ3z38uk,8069
|
|
183
183
|
alita_sdk/runtime/tools/mcp_inspect_tool.py,sha256=38X8euaxDbEGjcfp6ElvExZalpZun6QEr6ZEW4nU5pQ,11496
|
|
@@ -401,7 +401,7 @@ alita_sdk/tools/sql/models.py,sha256=AKJgSl_kEEz4fZfw3kbvdGHXaRZ-yiaqfJOB6YOj3i0
|
|
|
401
401
|
alita_sdk/tools/testio/__init__.py,sha256=KttkGmwKRlY5OG6kr_ZTrMXECpea-61B4w3Z5zlDtB4,2904
|
|
402
402
|
alita_sdk/tools/testio/api_wrapper.py,sha256=BvmL5h634BzG6p7ajnQLmj-uoAw1gjWnd4FHHu1h--Q,21638
|
|
403
403
|
alita_sdk/tools/testrail/__init__.py,sha256=oyw1bmITlfb1cusInMpc-Nuh0XwKV7yxjmW6veXr_n4,4561
|
|
404
|
-
alita_sdk/tools/testrail/api_wrapper.py,sha256=
|
|
404
|
+
alita_sdk/tools/testrail/api_wrapper.py,sha256=XycH0iEH2cCAv7InJotmsGE9lPj6hP45Za1d2jSQ_Lg,39886
|
|
405
405
|
alita_sdk/tools/utils/__init__.py,sha256=Bt1TsxkQIezgkxCgn5wFIOMsTsW5vEoWdM6KznodktU,4027
|
|
406
406
|
alita_sdk/tools/utils/available_tools_decorator.py,sha256=IbrdfeQkswxUFgvvN7-dyLMZMyXLiwvX7kgi3phciCk,273
|
|
407
407
|
alita_sdk/tools/utils/content_parser.py,sha256=KqiZzsurLspxCLemf9eqYhgW266FgWP4r-xElcK8a38,15881
|
|
@@ -427,9 +427,9 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
|
|
|
427
427
|
alita_sdk/tools/zephyr_squad/__init__.py,sha256=gZTEanHf9pRCiZaKobF4Wbm33wUxxXoIjOr544TcXas,2903
|
|
428
428
|
alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
|
|
429
429
|
alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
|
|
430
|
-
alita_sdk-0.3.
|
|
431
|
-
alita_sdk-0.3.
|
|
432
|
-
alita_sdk-0.3.
|
|
433
|
-
alita_sdk-0.3.
|
|
434
|
-
alita_sdk-0.3.
|
|
435
|
-
alita_sdk-0.3.
|
|
430
|
+
alita_sdk-0.3.528.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
431
|
+
alita_sdk-0.3.528.dist-info/METADATA,sha256=eTapGprJ7IEFsGKfI9BndpjRPD-eh0oTLK2yS7cLvlw,24266
|
|
432
|
+
alita_sdk-0.3.528.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
433
|
+
alita_sdk-0.3.528.dist-info/entry_points.txt,sha256=VijN0h4alp1WXm8tfS3P7vuGxN4a5RZqHjXAoEIBZnI,49
|
|
434
|
+
alita_sdk-0.3.528.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
|
|
435
|
+
alita_sdk-0.3.528.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|