alita-sdk 0.3.365__py3-none-any.whl → 0.3.367__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 +14 -11
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- {alita_sdk-0.3.365.dist-info → alita_sdk-0.3.367.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.365.dist-info → alita_sdk-0.3.367.dist-info}/RECORD +7 -7
- {alita_sdk-0.3.365.dist-info → alita_sdk-0.3.367.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.365.dist-info → alita_sdk-0.3.367.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.365.dist-info → alita_sdk-0.3.367.dist-info}/top_level.txt +0 -0
|
@@ -786,24 +786,27 @@ class LangGraphAgentRunnable(CompiledStateGraph):
|
|
|
786
786
|
else:
|
|
787
787
|
result = super().invoke(input, config=config, *args, **kwargs)
|
|
788
788
|
try:
|
|
789
|
-
if self.output_variables and self.output_variables[0] != "messages":
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
else:
|
|
795
|
-
|
|
789
|
+
# if self.output_variables and self.output_variables[0] != "messages":
|
|
790
|
+
# # If output_variables are specified, use the value of first one or use the last messages as default
|
|
791
|
+
# output = result.get(self.output_variables[0])
|
|
792
|
+
# if not output:
|
|
793
|
+
# output = result['messages'][-1].content
|
|
794
|
+
# else:
|
|
795
|
+
# output = result['messages'][-1].content
|
|
796
|
+
output = result['messages'][-1].content
|
|
796
797
|
except:
|
|
797
798
|
output = list(result.values())[-1]
|
|
798
|
-
thread_id = None
|
|
799
799
|
config_state = self.get_state(config)
|
|
800
|
-
|
|
801
|
-
|
|
800
|
+
is_execution_finished = not config_state.next
|
|
801
|
+
if is_execution_finished:
|
|
802
|
+
thread_id = None
|
|
803
|
+
|
|
804
|
+
|
|
802
805
|
|
|
803
806
|
result_with_state = {
|
|
804
807
|
"output": output,
|
|
805
808
|
"thread_id": thread_id,
|
|
806
|
-
"execution_finished":
|
|
809
|
+
"execution_finished": is_execution_finished
|
|
807
810
|
}
|
|
808
811
|
|
|
809
812
|
# Include all state values in the result
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from pydantic
|
|
4
|
+
from langchain_core.tools import ToolException
|
|
5
|
+
from pydantic import create_model, SecretStr, model_validator
|
|
6
|
+
from pydantic.fields import PrivateAttr, Field
|
|
6
7
|
from sqlalchemy import create_engine, text, inspect, Engine
|
|
7
8
|
from sqlalchemy.orm import sessionmaker
|
|
8
9
|
|
|
@@ -27,7 +28,7 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
27
28
|
username: str
|
|
28
29
|
password: SecretStr
|
|
29
30
|
database_name: str
|
|
30
|
-
_client: Optional[Engine] = PrivateAttr()
|
|
31
|
+
_client: Optional[Engine] = PrivateAttr(default=None)
|
|
31
32
|
|
|
32
33
|
@model_validator(mode='before')
|
|
33
34
|
@classmethod
|
|
@@ -35,27 +36,73 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
35
36
|
for field in SQLConfig.model_fields:
|
|
36
37
|
if field not in values or not values[field]:
|
|
37
38
|
raise ValueError(f"{field} is a required field and must be provided.")
|
|
38
|
-
|
|
39
|
-
dialect = values['dialect']
|
|
40
|
-
host = values['host']
|
|
41
|
-
username = values['username']
|
|
42
|
-
password = values['password']
|
|
43
|
-
database_name = values['database_name']
|
|
44
|
-
port = values['port']
|
|
45
|
-
|
|
46
|
-
if dialect == SQLDialect.POSTGRES:
|
|
47
|
-
connection_string = f'postgresql+psycopg2://{username}:{password}@{host}:{port}/{database_name}'
|
|
48
|
-
elif dialect == SQLDialect.MYSQL:
|
|
49
|
-
connection_string = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database_name}'
|
|
50
|
-
else:
|
|
51
|
-
raise ValueError(f"Unsupported database type. Supported types are: {[e.value for e in SQLDialect]}")
|
|
52
|
-
|
|
53
|
-
cls._client = create_engine(connection_string)
|
|
54
39
|
return values
|
|
55
40
|
|
|
41
|
+
def _mask_password_in_error(self, error_message: str) -> str:
|
|
42
|
+
"""Mask password in error messages, showing only last 4 characters."""
|
|
43
|
+
password_str = self.password.get_secret_value()
|
|
44
|
+
if len(password_str) <= 4:
|
|
45
|
+
masked_password = "****"
|
|
46
|
+
else:
|
|
47
|
+
masked_password = "****" + password_str[-4:]
|
|
48
|
+
|
|
49
|
+
# Replace all occurrences of the password, and any substring of the password that may appear in the error message
|
|
50
|
+
for part in [password_str, password_str.replace('@', ''), password_str.split('@')[-1]]:
|
|
51
|
+
if part and part in error_message:
|
|
52
|
+
error_message = error_message.replace(part, masked_password)
|
|
53
|
+
return error_message
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def client(self) -> Engine:
|
|
57
|
+
"""Lazy property to create and return database engine with error handling."""
|
|
58
|
+
if self._client is None:
|
|
59
|
+
try:
|
|
60
|
+
dialect = self.dialect
|
|
61
|
+
host = self.host
|
|
62
|
+
username = self.username
|
|
63
|
+
password = self.password.get_secret_value()
|
|
64
|
+
database_name = self.database_name
|
|
65
|
+
port = self.port
|
|
66
|
+
|
|
67
|
+
if dialect == SQLDialect.POSTGRES:
|
|
68
|
+
connection_string = f'postgresql+psycopg2://{username}:{password}@{host}:{port}/{database_name}'
|
|
69
|
+
elif dialect == SQLDialect.MYSQL:
|
|
70
|
+
connection_string = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database_name}'
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError(f"Unsupported database type. Supported types are: {[e.value for e in SQLDialect]}")
|
|
73
|
+
|
|
74
|
+
self._client = create_engine(connection_string)
|
|
75
|
+
|
|
76
|
+
# Test the connection
|
|
77
|
+
with self._client.connect() as conn:
|
|
78
|
+
conn.execute(text("SELECT 1"))
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
error_message = str(e)
|
|
82
|
+
masked_error = self._mask_password_in_error(error_message)
|
|
83
|
+
logger.error(f"Database connection failed: {masked_error}")
|
|
84
|
+
raise ValueError(f"Database connection failed: {masked_error}")
|
|
85
|
+
|
|
86
|
+
return self._client
|
|
87
|
+
|
|
88
|
+
def _handle_database_errors(func):
|
|
89
|
+
"""Decorator to catch exceptions and mask passwords in error messages."""
|
|
90
|
+
|
|
91
|
+
def wrapper(self, *args, **kwargs):
|
|
92
|
+
try:
|
|
93
|
+
return func(self, *args, **kwargs)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
error_message = str(e)
|
|
96
|
+
masked_error = self._mask_password_in_error(error_message)
|
|
97
|
+
logger.error(f"Database operation failed in {func.__name__}: {masked_error}")
|
|
98
|
+
raise ToolException(masked_error)
|
|
99
|
+
|
|
100
|
+
return wrapper
|
|
101
|
+
|
|
102
|
+
@_handle_database_errors
|
|
56
103
|
def execute_sql(self, sql_query: str):
|
|
57
104
|
"""Executes the provided SQL query on the configured database."""
|
|
58
|
-
engine = self.
|
|
105
|
+
engine = self.client
|
|
59
106
|
maker_session = sessionmaker(bind=engine)
|
|
60
107
|
session = maker_session()
|
|
61
108
|
try:
|
|
@@ -76,9 +123,10 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
76
123
|
finally:
|
|
77
124
|
session.close()
|
|
78
125
|
|
|
126
|
+
@_handle_database_errors
|
|
79
127
|
def list_tables_and_columns(self):
|
|
80
128
|
"""Lists all tables and their columns in the configured database."""
|
|
81
|
-
inspector = inspect(self.
|
|
129
|
+
inspector = inspect(self.client)
|
|
82
130
|
data = {}
|
|
83
131
|
tables = inspector.get_table_names()
|
|
84
132
|
for table in tables:
|
|
@@ -109,4 +157,4 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
109
157
|
"description": self.list_tables_and_columns.__doc__,
|
|
110
158
|
"args_schema": SQLNoInput,
|
|
111
159
|
}
|
|
112
|
-
]
|
|
160
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alita_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.367
|
|
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
|
|
@@ -44,7 +44,7 @@ alita_sdk/runtime/langchain/assistant.py,sha256=2tH8je9uKegIIIZUuiGU4zqRVg7jyQas
|
|
|
44
44
|
alita_sdk/runtime/langchain/chat_message_template.py,sha256=kPz8W2BG6IMyITFDA5oeb5BxVRkHEVZhuiGl4MBZKdc,2176
|
|
45
45
|
alita_sdk/runtime/langchain/constants.py,sha256=eHVJ_beJNTf1WJo4yq7KMK64fxsRvs3lKc34QCXSbpk,3319
|
|
46
46
|
alita_sdk/runtime/langchain/indexer.py,sha256=0ENHy5EOhThnAiYFc7QAsaTNp9rr8hDV_hTK8ahbatk,37592
|
|
47
|
-
alita_sdk/runtime/langchain/langraph_agent.py,sha256=
|
|
47
|
+
alita_sdk/runtime/langchain/langraph_agent.py,sha256=n7zhgMSB5p2OwaWu4sZGcJR4RpZNvAO9uNLxN2ImgQA,48109
|
|
48
48
|
alita_sdk/runtime/langchain/mixedAgentParser.py,sha256=M256lvtsL3YtYflBCEp-rWKrKtcY1dJIyRGVv7KW9ME,2611
|
|
49
49
|
alita_sdk/runtime/langchain/mixedAgentRenderes.py,sha256=asBtKqm88QhZRILditjYICwFVKF5KfO38hu2O-WrSWE,5964
|
|
50
50
|
alita_sdk/runtime/langchain/store_manager.py,sha256=i8Fl11IXJhrBXq1F1ukEVln57B1IBe-tqSUvfUmBV4A,2218
|
|
@@ -322,7 +322,7 @@ alita_sdk/tools/sharepoint/utils.py,sha256=fZ1YzAu5CTjKSZeslowpOPH974902S8vCp1Wu
|
|
|
322
322
|
alita_sdk/tools/slack/__init__.py,sha256=YiPAoRc6y6uVpfHl0K1Qi-flcyPlWFIMVcVbhicGWXY,3990
|
|
323
323
|
alita_sdk/tools/slack/api_wrapper.py,sha256=5VrV7iSGno8ZcDzEHdGPNhInhtODGPPvAzoZ9W9iQWE,14009
|
|
324
324
|
alita_sdk/tools/sql/__init__.py,sha256=F3eewPEKqVh3gZdNTUvcoFPOgG9Mn11qKoadtCmhQ4Q,3484
|
|
325
|
-
alita_sdk/tools/sql/api_wrapper.py,sha256=
|
|
325
|
+
alita_sdk/tools/sql/api_wrapper.py,sha256=1VkwnMBr7hGn-LsXXhG774QQQTHvUZilnDuflN2pQes,5810
|
|
326
326
|
alita_sdk/tools/sql/models.py,sha256=AKJgSl_kEEz4fZfw3kbvdGHXaRZ-yiaqfJOB6YOj3i0,641
|
|
327
327
|
alita_sdk/tools/testio/__init__.py,sha256=NEvQtzsffqAXryaffVk0GpdcxZQ1AMkfeztnxHwNql4,2798
|
|
328
328
|
alita_sdk/tools/testio/api_wrapper.py,sha256=BvmL5h634BzG6p7ajnQLmj-uoAw1gjWnd4FHHu1h--Q,21638
|
|
@@ -352,8 +352,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
|
|
|
352
352
|
alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
|
|
353
353
|
alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
|
|
354
354
|
alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
|
|
355
|
-
alita_sdk-0.3.
|
|
356
|
-
alita_sdk-0.3.
|
|
357
|
-
alita_sdk-0.3.
|
|
358
|
-
alita_sdk-0.3.
|
|
359
|
-
alita_sdk-0.3.
|
|
355
|
+
alita_sdk-0.3.367.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
356
|
+
alita_sdk-0.3.367.dist-info/METADATA,sha256=Vl32B-AoI7amFTAWHAv_2TaEthWlRBcuOm5WiG8XaH4,19071
|
|
357
|
+
alita_sdk-0.3.367.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
358
|
+
alita_sdk-0.3.367.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
|
|
359
|
+
alita_sdk-0.3.367.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|