alita-sdk 0.3.609__py3-none-any.whl → 0.3.611__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/langchain/langraph_agent.py +21 -6
- alita_sdk/runtime/tools/function.py +25 -6
- alita_sdk/runtime/utils/serialization.py +155 -0
- {alita_sdk-0.3.609.dist-info → alita_sdk-0.3.611.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.609.dist-info → alita_sdk-0.3.611.dist-info}/RECORD +9 -8
- {alita_sdk-0.3.609.dist-info → alita_sdk-0.3.611.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.609.dist-info → alita_sdk-0.3.611.dist-info}/entry_points.txt +0 -0
- {alita_sdk-0.3.609.dist-info → alita_sdk-0.3.611.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.609.dist-info → alita_sdk-0.3.611.dist-info}/top_level.txt +0 -0
|
@@ -230,18 +230,32 @@ class StateDefaultNode(Runnable):
|
|
|
230
230
|
for key, value in self.default_vars.items():
|
|
231
231
|
if isinstance(value, dict) and 'value' in value:
|
|
232
232
|
temp_value = value['value']
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
declared_type = value.get('type', '').lower()
|
|
234
|
+
|
|
235
|
+
# If the declared type is 'str' or 'string', preserve the string value
|
|
236
|
+
# Don't auto-convert even if it looks like a valid Python literal
|
|
237
|
+
if declared_type in ('str', 'string'):
|
|
237
238
|
result[key] = temp_value
|
|
239
|
+
else:
|
|
240
|
+
# For other types, try to evaluate as Python literal
|
|
241
|
+
try:
|
|
242
|
+
result[key] = ast.literal_eval(temp_value)
|
|
243
|
+
except:
|
|
244
|
+
logger.debug("Unable to evaluate value, using as is")
|
|
245
|
+
result[key] = temp_value
|
|
238
246
|
return result
|
|
239
247
|
|
|
240
248
|
class PrinterNode(Runnable):
|
|
241
249
|
name = "PrinterNode"
|
|
250
|
+
DEFAULT_FINAL_MSG = "How to proceed? To resume the pipeline - type anything..."
|
|
242
251
|
|
|
243
|
-
def __init__(self, input_mapping: Optional[dict[str, dict]]):
|
|
252
|
+
def __init__(self, input_mapping: Optional[dict[str, dict]], final_message: Optional[str] = None):
|
|
244
253
|
self.input_mapping = input_mapping
|
|
254
|
+
# Apply fallback logic for empty/None values
|
|
255
|
+
if final_message and final_message.strip():
|
|
256
|
+
self.final_message = final_message.strip()
|
|
257
|
+
else:
|
|
258
|
+
self.final_message = self.DEFAULT_FINAL_MSG
|
|
245
259
|
|
|
246
260
|
def invoke(self, state: BaseStore, config: Optional[RunnableConfig] = None) -> dict:
|
|
247
261
|
logger.info(f"Printer Node - Current state variables: {state}")
|
|
@@ -261,7 +275,7 @@ class PrinterNode(Runnable):
|
|
|
261
275
|
# convert formatted output to string if it's not
|
|
262
276
|
if not isinstance(formatted_output, str):
|
|
263
277
|
formatted_output = str(formatted_output)
|
|
264
|
-
formatted_output += f"\n\n-----\n*
|
|
278
|
+
formatted_output += f"\n\n-----\n*{self.final_message}*"
|
|
265
279
|
logger.debug(f"Formatted output: {formatted_output}")
|
|
266
280
|
result[PRINTER_NODE_RS] = formatted_output
|
|
267
281
|
return result
|
|
@@ -745,6 +759,7 @@ def create_graph(
|
|
|
745
759
|
elif node_type == 'printer':
|
|
746
760
|
lg_builder.add_node(node_id, PrinterNode(
|
|
747
761
|
input_mapping=node.get('input_mapping', {'printer': {'type': 'fixed', 'value': ''}}),
|
|
762
|
+
final_message=node.get('final_message'),
|
|
748
763
|
))
|
|
749
764
|
|
|
750
765
|
# add interrupts after printer node if specified
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import base64
|
|
1
2
|
import json
|
|
2
3
|
import logging
|
|
3
4
|
from copy import deepcopy
|
|
@@ -12,6 +13,7 @@ from langchain_core.utils.function_calling import convert_to_openai_tool
|
|
|
12
13
|
from pydantic import ValidationError
|
|
13
14
|
|
|
14
15
|
from ..langchain.utils import propagate_the_input_mapping
|
|
16
|
+
from ..utils.serialization import safe_serialize
|
|
15
17
|
|
|
16
18
|
logger = logging.getLogger(__name__)
|
|
17
19
|
|
|
@@ -40,15 +42,32 @@ class FunctionTool(BaseTool):
|
|
|
40
42
|
alita_client: Optional[Any] = None
|
|
41
43
|
|
|
42
44
|
def _prepare_pyodide_input(self, state: Union[str, dict, ToolCall]) -> str:
|
|
43
|
-
"""Prepare input for PyodideSandboxTool by injecting state into the code block.
|
|
44
|
-
|
|
45
|
+
"""Prepare input for PyodideSandboxTool by injecting state into the code block.
|
|
46
|
+
|
|
47
|
+
Uses base64 encoding to avoid string escaping issues when passing JSON
|
|
48
|
+
through multiple layers of parsing (Python -> Deno -> Pyodide).
|
|
49
|
+
"""
|
|
45
50
|
state_copy = replace_escaped_newlines(deepcopy(state))
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
# remove messages to avoid issues with pickling without langchain-core
|
|
53
|
+
if 'messages' in state_copy:
|
|
54
|
+
del state_copy['messages']
|
|
55
|
+
|
|
56
|
+
# Use safe_serialize to handle Pydantic models, datetime, and other non-JSON types
|
|
57
|
+
state_json = safe_serialize(state_copy)
|
|
51
58
|
|
|
59
|
+
# Use base64 encoding to avoid all string escaping issues
|
|
60
|
+
# This is more robust than repr() when the code passes through multiple parsers
|
|
61
|
+
state_json_b64 = base64.b64encode(state_json.encode('utf-8')).decode('ascii')
|
|
62
|
+
|
|
63
|
+
# Generate code that decodes base64 and parses JSON inside Pyodide
|
|
64
|
+
pyodide_predata = f'''#state dict
|
|
65
|
+
import json
|
|
66
|
+
import base64
|
|
67
|
+
_state_json_b64 = "{state_json_b64}"
|
|
68
|
+
_state_json = base64.b64decode(_state_json_b64).decode('utf-8')
|
|
69
|
+
alita_state = json.loads(_state_json)
|
|
70
|
+
'''
|
|
52
71
|
return pyodide_predata
|
|
53
72
|
|
|
54
73
|
def _handle_pyodide_output(self, tool_result: Any) -> dict:
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Serialization utilities for safe JSON encoding of complex objects.
|
|
3
|
+
|
|
4
|
+
Handles Pydantic models, LangChain messages, datetime objects, and other
|
|
5
|
+
non-standard types that may appear in state variables.
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from datetime import datetime, date
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _convert_to_serializable(obj: Any, _seen: set = None) -> Any:
|
|
16
|
+
"""
|
|
17
|
+
Recursively convert an object to JSON-serializable primitives.
|
|
18
|
+
|
|
19
|
+
Handles nested dicts and lists that may contain non-serializable objects.
|
|
20
|
+
Uses a seen set to prevent infinite recursion with circular references.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
obj: Any object to convert
|
|
24
|
+
_seen: Internal set to track seen object ids (for circular reference detection)
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
JSON-serializable representation of the object
|
|
28
|
+
"""
|
|
29
|
+
# Initialize seen set for circular reference detection
|
|
30
|
+
if _seen is None:
|
|
31
|
+
_seen = set()
|
|
32
|
+
|
|
33
|
+
# Check for circular references (only for mutable objects)
|
|
34
|
+
obj_id = id(obj)
|
|
35
|
+
if isinstance(obj, (dict, list, set)) and obj_id in _seen:
|
|
36
|
+
return f"<circular reference: {type(obj).__name__}>"
|
|
37
|
+
|
|
38
|
+
# Primitives - return as-is
|
|
39
|
+
if obj is None or isinstance(obj, (str, int, float, bool)):
|
|
40
|
+
return obj
|
|
41
|
+
|
|
42
|
+
# Add to seen set for mutable containers
|
|
43
|
+
if isinstance(obj, (dict, list, set)):
|
|
44
|
+
_seen = _seen | {obj_id} # Create new set to avoid mutation issues
|
|
45
|
+
|
|
46
|
+
# Dict - recursively process all values
|
|
47
|
+
if isinstance(obj, dict):
|
|
48
|
+
return {
|
|
49
|
+
_convert_to_serializable(k, _seen): _convert_to_serializable(v, _seen)
|
|
50
|
+
for k, v in obj.items()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# List/tuple - recursively process all items
|
|
54
|
+
if isinstance(obj, (list, tuple)):
|
|
55
|
+
return [_convert_to_serializable(item, _seen) for item in obj]
|
|
56
|
+
|
|
57
|
+
# Set - convert to list and process
|
|
58
|
+
if isinstance(obj, set):
|
|
59
|
+
return [_convert_to_serializable(item, _seen) for item in obj]
|
|
60
|
+
|
|
61
|
+
# Bytes - decode to string
|
|
62
|
+
if isinstance(obj, bytes):
|
|
63
|
+
try:
|
|
64
|
+
return obj.decode('utf-8')
|
|
65
|
+
except UnicodeDecodeError:
|
|
66
|
+
return obj.decode('utf-8', errors='replace')
|
|
67
|
+
|
|
68
|
+
# Datetime objects
|
|
69
|
+
if isinstance(obj, datetime):
|
|
70
|
+
return obj.isoformat()
|
|
71
|
+
if isinstance(obj, date):
|
|
72
|
+
return obj.isoformat()
|
|
73
|
+
|
|
74
|
+
# Pydantic BaseModel (v2) - check for model_dump method
|
|
75
|
+
if hasattr(obj, 'model_dump') and callable(getattr(obj, 'model_dump')):
|
|
76
|
+
try:
|
|
77
|
+
return _convert_to_serializable(obj.model_dump(), _seen)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
logger.debug(f"Failed to call model_dump on {type(obj).__name__}: {e}")
|
|
80
|
+
|
|
81
|
+
# Pydantic BaseModel (v1) - check for dict method
|
|
82
|
+
if hasattr(obj, 'dict') and callable(getattr(obj, 'dict')) and hasattr(obj, '__fields__'):
|
|
83
|
+
try:
|
|
84
|
+
return _convert_to_serializable(obj.dict(), _seen)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.debug(f"Failed to call dict on {type(obj).__name__}: {e}")
|
|
87
|
+
|
|
88
|
+
# LangChain BaseMessage - extract key fields
|
|
89
|
+
if hasattr(obj, 'type') and hasattr(obj, 'content'):
|
|
90
|
+
try:
|
|
91
|
+
result = {
|
|
92
|
+
"type": obj.type,
|
|
93
|
+
"content": _convert_to_serializable(obj.content, _seen),
|
|
94
|
+
}
|
|
95
|
+
if hasattr(obj, 'additional_kwargs') and obj.additional_kwargs:
|
|
96
|
+
result["additional_kwargs"] = _convert_to_serializable(obj.additional_kwargs, _seen)
|
|
97
|
+
if hasattr(obj, 'name') and obj.name:
|
|
98
|
+
result["name"] = obj.name
|
|
99
|
+
return result
|
|
100
|
+
except Exception as e:
|
|
101
|
+
logger.debug(f"Failed to extract message fields from {type(obj).__name__}: {e}")
|
|
102
|
+
|
|
103
|
+
# Objects with __dict__ attribute (custom classes)
|
|
104
|
+
if hasattr(obj, '__dict__'):
|
|
105
|
+
try:
|
|
106
|
+
return _convert_to_serializable(obj.__dict__, _seen)
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.debug(f"Failed to serialize __dict__ of {type(obj).__name__}: {e}")
|
|
109
|
+
|
|
110
|
+
# UUID objects
|
|
111
|
+
if hasattr(obj, 'hex') and hasattr(obj, 'int'):
|
|
112
|
+
return str(obj)
|
|
113
|
+
|
|
114
|
+
# Enum objects
|
|
115
|
+
if hasattr(obj, 'value') and hasattr(obj, 'name') and hasattr(obj.__class__, '__members__'):
|
|
116
|
+
return obj.value
|
|
117
|
+
|
|
118
|
+
# Last resort - convert to string
|
|
119
|
+
try:
|
|
120
|
+
return str(obj)
|
|
121
|
+
except Exception:
|
|
122
|
+
return f"<non-serializable: {type(obj).__name__}>"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def safe_serialize(obj: Any, **kwargs) -> str:
|
|
126
|
+
"""
|
|
127
|
+
Safely serialize any object to a JSON string.
|
|
128
|
+
|
|
129
|
+
Pre-processes the entire object tree to convert non-serializable
|
|
130
|
+
objects before passing to json.dumps. This ensures nested dicts
|
|
131
|
+
and lists with non-standard objects are handled correctly.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
obj: Any object to serialize
|
|
135
|
+
**kwargs: Additional arguments passed to json.dumps
|
|
136
|
+
(e.g., indent, sort_keys)
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
JSON string representation of the object
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
>>> from pydantic import BaseModel
|
|
143
|
+
>>> class User(BaseModel):
|
|
144
|
+
... name: str
|
|
145
|
+
>>> state = {"user": User(name="Alice"), "count": 5}
|
|
146
|
+
>>> safe_serialize(state)
|
|
147
|
+
'{"user": {"name": "Alice"}, "count": 5}'
|
|
148
|
+
"""
|
|
149
|
+
# Pre-process the entire object tree
|
|
150
|
+
serializable = _convert_to_serializable(obj)
|
|
151
|
+
|
|
152
|
+
# Set defaults
|
|
153
|
+
kwargs.setdefault('ensure_ascii', False)
|
|
154
|
+
|
|
155
|
+
return json.dumps(serializable, **kwargs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alita_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.611
|
|
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
|
|
@@ -119,7 +119,7 @@ alita_sdk/runtime/langchain/assistant.py,sha256=RcU82QyxtLW8yWeamEBqYJ6B243ehRya
|
|
|
119
119
|
alita_sdk/runtime/langchain/chat_message_template.py,sha256=kPz8W2BG6IMyITFDA5oeb5BxVRkHEVZhuiGl4MBZKdc,2176
|
|
120
120
|
alita_sdk/runtime/langchain/constants.py,sha256=GxZP0dupwaVq0iTKE2nNF-Vp0wzMlkh_aiBAhCuy84E,29451
|
|
121
121
|
alita_sdk/runtime/langchain/indexer.py,sha256=0ENHy5EOhThnAiYFc7QAsaTNp9rr8hDV_hTK8ahbatk,37592
|
|
122
|
-
alita_sdk/runtime/langchain/langraph_agent.py,sha256
|
|
122
|
+
alita_sdk/runtime/langchain/langraph_agent.py,sha256=7mkOpl_cBCb6hZqNCN-B9TePRQjnblLMWDOzcGni-rY,63957
|
|
123
123
|
alita_sdk/runtime/langchain/mixedAgentParser.py,sha256=M256lvtsL3YtYflBCEp-rWKrKtcY1dJIyRGVv7KW9ME,2611
|
|
124
124
|
alita_sdk/runtime/langchain/mixedAgentRenderes.py,sha256=asBtKqm88QhZRILditjYICwFVKF5KfO38hu2O-WrSWE,5964
|
|
125
125
|
alita_sdk/runtime/langchain/store_manager.py,sha256=i8Fl11IXJhrBXq1F1ukEVln57B1IBe-tqSUvfUmBV4A,2218
|
|
@@ -199,7 +199,7 @@ alita_sdk/runtime/tools/artifact.py,sha256=Us-NM1VTfqDNBzs8nMsI3Inu-_V9SoZOqjfUA
|
|
|
199
199
|
alita_sdk/runtime/tools/data_analysis.py,sha256=PHQ0xa2eDkw6FsHAHVTWB58wO8tg76tHrp4lXRQZ0jQ,6396
|
|
200
200
|
alita_sdk/runtime/tools/datasource.py,sha256=pvbaSfI-ThQQnjHG-QhYNSTYRnZB0rYtZFpjCfpzxYI,2443
|
|
201
201
|
alita_sdk/runtime/tools/echo.py,sha256=spw9eCweXzixJqHnZofHE1yWiSUa04L4VKycf3KCEaM,486
|
|
202
|
-
alita_sdk/runtime/tools/function.py,sha256=
|
|
202
|
+
alita_sdk/runtime/tools/function.py,sha256=x5gaaCrxgA5vwq29pUpAgGA5l6THriOJx9d58-G9Ybo,7679
|
|
203
203
|
alita_sdk/runtime/tools/graph.py,sha256=7jImBBSEdP5Mjnn2keOiyUwdGDFhEXLUrgUiugO3mgA,3503
|
|
204
204
|
alita_sdk/runtime/tools/image_generation.py,sha256=waxxFIAgmh9-COcljL9uZ7e_s7EL9OWveUxYk0ulEUM,7855
|
|
205
205
|
alita_sdk/runtime/tools/indexer_tool.py,sha256=whSLPevB4WD6dhh2JDXEivDmTvbjiMV1MrPl9cz5eLA,4375
|
|
@@ -230,6 +230,7 @@ alita_sdk/runtime/utils/mcp_oauth.py,sha256=YfMFZOs1nGSR7ZvGKSE6nKlpJRNkr2h0BZXk
|
|
|
230
230
|
alita_sdk/runtime/utils/mcp_sse_client.py,sha256=wU_fmZbh2sXUYjkJmBjmpfhFLpncjAXE5Wg3fqyNhmk,18318
|
|
231
231
|
alita_sdk/runtime/utils/mcp_tools_discovery.py,sha256=pL1bMUEaZmiABFGsphed0LvhR-wGfkNnCpD_89R01Ws,3908
|
|
232
232
|
alita_sdk/runtime/utils/save_dataframe.py,sha256=i-E1wp-t4wb17Zq3nA3xYwgSILjoXNizaQAA9opWvxY,1576
|
|
233
|
+
alita_sdk/runtime/utils/serialization.py,sha256=J7cQS7-SYD8haUv5Inn44EfsTzmAzOquacgn_t2GU-g,5327
|
|
233
234
|
alita_sdk/runtime/utils/streamlit.py,sha256=0TotNKnvMPHuwBdhMEpM5DhIedQQa1AUz9BlmXFBhAU,107179
|
|
234
235
|
alita_sdk/runtime/utils/toolkit_runtime.py,sha256=MU63Fpxj0b5_r1IUUc0Q3-PN9VwL7rUxp2MRR4tmYR8,5136
|
|
235
236
|
alita_sdk/runtime/utils/toolkit_utils.py,sha256=c56a9jzlOXYYdl67N3arGl5sOqO3ly60bne2OBYuQKc,6758
|
|
@@ -458,9 +459,9 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=ppJayzkKRhTbQVVd2EhQmvADwdosl
|
|
|
458
459
|
alita_sdk/tools/zephyr_squad/__init__.py,sha256=cUSc0ZhpGmWnTQ3ZjllU9QmNlCfaHZ21HCFjfenSMH8,3081
|
|
459
460
|
alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
|
|
460
461
|
alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
|
|
461
|
-
alita_sdk-0.3.
|
|
462
|
-
alita_sdk-0.3.
|
|
463
|
-
alita_sdk-0.3.
|
|
464
|
-
alita_sdk-0.3.
|
|
465
|
-
alita_sdk-0.3.
|
|
466
|
-
alita_sdk-0.3.
|
|
462
|
+
alita_sdk-0.3.611.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
463
|
+
alita_sdk-0.3.611.dist-info/METADATA,sha256=VbmEWybS3DmRjXF8BIB5vG8dLgO5HS7Vm9_qbMG7miQ,24339
|
|
464
|
+
alita_sdk-0.3.611.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
465
|
+
alita_sdk-0.3.611.dist-info/entry_points.txt,sha256=VijN0h4alp1WXm8tfS3P7vuGxN4a5RZqHjXAoEIBZnI,49
|
|
466
|
+
alita_sdk-0.3.611.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
|
|
467
|
+
alita_sdk-0.3.611.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|