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.

@@ -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
- # 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
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
- if config_state.next:
801
- thread_id = config['configurable']['thread_id']
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": not config_state.next
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, Any
2
+ from typing import Optional
3
3
 
4
- from pydantic import BaseModel, create_model, model_validator, Field, SecretStr
5
- from pydantic.fields import PrivateAttr
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._client
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._client)
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.365
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=Nrhhcr7fIGaMFwps2XV0ZPL72Ek4wHo7Zml-JaE3AvU,48039
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=Rky0_CX9HWDQ2mClHGAgP3LHjYVX4iymPuilZMtaDlQ,3687
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.365.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
356
- alita_sdk-0.3.365.dist-info/METADATA,sha256=MEwGE5tSEKyqZhKFzGM0fQcYLTOzHnrLermRmpJItwU,19071
357
- alita_sdk-0.3.365.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
358
- alita_sdk-0.3.365.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
359
- alita_sdk-0.3.365.dist-info/RECORD,,
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,,