alita-sdk 0.3.462__py3-none-any.whl → 0.3.627__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.
Files changed (261) hide show
  1. alita_sdk/cli/agent/__init__.py +5 -0
  2. alita_sdk/cli/agent/default.py +258 -0
  3. alita_sdk/cli/agent_executor.py +15 -3
  4. alita_sdk/cli/agent_loader.py +56 -8
  5. alita_sdk/cli/agent_ui.py +93 -31
  6. alita_sdk/cli/agents.py +2274 -230
  7. alita_sdk/cli/callbacks.py +96 -25
  8. alita_sdk/cli/cli.py +10 -1
  9. alita_sdk/cli/config.py +162 -9
  10. alita_sdk/cli/context/__init__.py +30 -0
  11. alita_sdk/cli/context/cleanup.py +198 -0
  12. alita_sdk/cli/context/manager.py +731 -0
  13. alita_sdk/cli/context/message.py +285 -0
  14. alita_sdk/cli/context/strategies.py +289 -0
  15. alita_sdk/cli/context/token_estimation.py +127 -0
  16. alita_sdk/cli/input_handler.py +419 -0
  17. alita_sdk/cli/inventory.py +1073 -0
  18. alita_sdk/cli/testcases/__init__.py +94 -0
  19. alita_sdk/cli/testcases/data_generation.py +119 -0
  20. alita_sdk/cli/testcases/discovery.py +96 -0
  21. alita_sdk/cli/testcases/executor.py +84 -0
  22. alita_sdk/cli/testcases/logger.py +85 -0
  23. alita_sdk/cli/testcases/parser.py +172 -0
  24. alita_sdk/cli/testcases/prompts.py +91 -0
  25. alita_sdk/cli/testcases/reporting.py +125 -0
  26. alita_sdk/cli/testcases/setup.py +108 -0
  27. alita_sdk/cli/testcases/test_runner.py +282 -0
  28. alita_sdk/cli/testcases/utils.py +39 -0
  29. alita_sdk/cli/testcases/validation.py +90 -0
  30. alita_sdk/cli/testcases/workflow.py +196 -0
  31. alita_sdk/cli/toolkit.py +14 -17
  32. alita_sdk/cli/toolkit_loader.py +35 -5
  33. alita_sdk/cli/tools/__init__.py +36 -2
  34. alita_sdk/cli/tools/approval.py +224 -0
  35. alita_sdk/cli/tools/filesystem.py +910 -64
  36. alita_sdk/cli/tools/planning.py +389 -0
  37. alita_sdk/cli/tools/terminal.py +414 -0
  38. alita_sdk/community/__init__.py +72 -12
  39. alita_sdk/community/inventory/__init__.py +236 -0
  40. alita_sdk/community/inventory/config.py +257 -0
  41. alita_sdk/community/inventory/enrichment.py +2137 -0
  42. alita_sdk/community/inventory/extractors.py +1469 -0
  43. alita_sdk/community/inventory/ingestion.py +3172 -0
  44. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  45. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  46. alita_sdk/community/inventory/parsers/base.py +295 -0
  47. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  48. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  49. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  50. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  51. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  52. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  53. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  54. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  55. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  56. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  57. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  58. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  59. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  60. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  61. alita_sdk/community/inventory/patterns/loader.py +348 -0
  62. alita_sdk/community/inventory/patterns/registry.py +198 -0
  63. alita_sdk/community/inventory/presets.py +535 -0
  64. alita_sdk/community/inventory/retrieval.py +1403 -0
  65. alita_sdk/community/inventory/toolkit.py +173 -0
  66. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  67. alita_sdk/community/inventory/visualize.py +1370 -0
  68. alita_sdk/configurations/__init__.py +1 -1
  69. alita_sdk/configurations/ado.py +141 -20
  70. alita_sdk/configurations/bitbucket.py +0 -3
  71. alita_sdk/configurations/confluence.py +76 -42
  72. alita_sdk/configurations/figma.py +76 -0
  73. alita_sdk/configurations/gitlab.py +17 -5
  74. alita_sdk/configurations/openapi.py +329 -0
  75. alita_sdk/configurations/qtest.py +72 -1
  76. alita_sdk/configurations/report_portal.py +96 -0
  77. alita_sdk/configurations/sharepoint.py +148 -0
  78. alita_sdk/configurations/testio.py +83 -0
  79. alita_sdk/runtime/clients/artifact.py +3 -3
  80. alita_sdk/runtime/clients/client.py +353 -48
  81. alita_sdk/runtime/clients/sandbox_client.py +0 -21
  82. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  83. alita_sdk/runtime/langchain/assistant.py +123 -26
  84. alita_sdk/runtime/langchain/constants.py +642 -1
  85. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
  86. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  87. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +6 -3
  88. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
  89. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
  90. alita_sdk/runtime/langchain/document_loaders/constants.py +12 -7
  91. alita_sdk/runtime/langchain/langraph_agent.py +279 -73
  92. alita_sdk/runtime/langchain/utils.py +82 -15
  93. alita_sdk/runtime/llms/preloaded.py +2 -6
  94. alita_sdk/runtime/skills/__init__.py +91 -0
  95. alita_sdk/runtime/skills/callbacks.py +498 -0
  96. alita_sdk/runtime/skills/discovery.py +540 -0
  97. alita_sdk/runtime/skills/executor.py +610 -0
  98. alita_sdk/runtime/skills/input_builder.py +371 -0
  99. alita_sdk/runtime/skills/models.py +330 -0
  100. alita_sdk/runtime/skills/registry.py +355 -0
  101. alita_sdk/runtime/skills/skill_runner.py +330 -0
  102. alita_sdk/runtime/toolkits/__init__.py +7 -0
  103. alita_sdk/runtime/toolkits/application.py +21 -9
  104. alita_sdk/runtime/toolkits/artifact.py +15 -5
  105. alita_sdk/runtime/toolkits/datasource.py +13 -6
  106. alita_sdk/runtime/toolkits/mcp.py +139 -251
  107. alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
  108. alita_sdk/runtime/toolkits/planning.py +178 -0
  109. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  110. alita_sdk/runtime/toolkits/subgraph.py +251 -6
  111. alita_sdk/runtime/toolkits/tools.py +238 -32
  112. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  113. alita_sdk/runtime/tools/__init__.py +3 -1
  114. alita_sdk/runtime/tools/application.py +20 -6
  115. alita_sdk/runtime/tools/artifact.py +511 -28
  116. alita_sdk/runtime/tools/data_analysis.py +183 -0
  117. alita_sdk/runtime/tools/function.py +43 -15
  118. alita_sdk/runtime/tools/image_generation.py +50 -44
  119. alita_sdk/runtime/tools/llm.py +852 -67
  120. alita_sdk/runtime/tools/loop.py +3 -1
  121. alita_sdk/runtime/tools/loop_output.py +3 -1
  122. alita_sdk/runtime/tools/mcp_remote_tool.py +25 -10
  123. alita_sdk/runtime/tools/mcp_server_tool.py +7 -6
  124. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  125. alita_sdk/runtime/tools/planning/models.py +246 -0
  126. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  127. alita_sdk/runtime/tools/router.py +2 -4
  128. alita_sdk/runtime/tools/sandbox.py +9 -6
  129. alita_sdk/runtime/tools/skill_router.py +776 -0
  130. alita_sdk/runtime/tools/tool.py +3 -1
  131. alita_sdk/runtime/tools/vectorstore.py +7 -2
  132. alita_sdk/runtime/tools/vectorstore_base.py +51 -11
  133. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  134. alita_sdk/runtime/utils/constants.py +5 -1
  135. alita_sdk/runtime/utils/mcp_client.py +492 -0
  136. alita_sdk/runtime/utils/mcp_oauth.py +202 -5
  137. alita_sdk/runtime/utils/mcp_sse_client.py +36 -7
  138. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  139. alita_sdk/runtime/utils/serialization.py +155 -0
  140. alita_sdk/runtime/utils/streamlit.py +6 -10
  141. alita_sdk/runtime/utils/toolkit_utils.py +16 -5
  142. alita_sdk/runtime/utils/utils.py +36 -0
  143. alita_sdk/tools/__init__.py +113 -29
  144. alita_sdk/tools/ado/repos/__init__.py +51 -33
  145. alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
  146. alita_sdk/tools/ado/test_plan/__init__.py +25 -9
  147. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
  148. alita_sdk/tools/ado/utils.py +1 -18
  149. alita_sdk/tools/ado/wiki/__init__.py +25 -8
  150. alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
  151. alita_sdk/tools/ado/work_item/__init__.py +26 -9
  152. alita_sdk/tools/ado/work_item/ado_wrapper.py +56 -3
  153. alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
  154. alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
  155. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  156. alita_sdk/tools/azure_ai/search/__init__.py +11 -8
  157. alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
  158. alita_sdk/tools/base/tool.py +5 -1
  159. alita_sdk/tools/base_indexer_toolkit.py +170 -45
  160. alita_sdk/tools/bitbucket/__init__.py +17 -12
  161. alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
  162. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
  163. alita_sdk/tools/browser/__init__.py +5 -4
  164. alita_sdk/tools/carrier/__init__.py +5 -6
  165. alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
  166. alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
  167. alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
  168. alita_sdk/tools/chunkers/__init__.py +3 -1
  169. alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
  170. alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
  171. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  172. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  173. alita_sdk/tools/cloud/aws/__init__.py +10 -7
  174. alita_sdk/tools/cloud/azure/__init__.py +10 -7
  175. alita_sdk/tools/cloud/gcp/__init__.py +10 -7
  176. alita_sdk/tools/cloud/k8s/__init__.py +10 -7
  177. alita_sdk/tools/code/linter/__init__.py +10 -8
  178. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  179. alita_sdk/tools/code/sonar/__init__.py +10 -7
  180. alita_sdk/tools/code_indexer_toolkit.py +73 -23
  181. alita_sdk/tools/confluence/__init__.py +21 -15
  182. alita_sdk/tools/confluence/api_wrapper.py +78 -23
  183. alita_sdk/tools/confluence/loader.py +4 -2
  184. alita_sdk/tools/custom_open_api/__init__.py +12 -5
  185. alita_sdk/tools/elastic/__init__.py +11 -8
  186. alita_sdk/tools/elitea_base.py +493 -30
  187. alita_sdk/tools/figma/__init__.py +58 -11
  188. alita_sdk/tools/figma/api_wrapper.py +1235 -143
  189. alita_sdk/tools/figma/figma_client.py +73 -0
  190. alita_sdk/tools/figma/toon_tools.py +2748 -0
  191. alita_sdk/tools/github/__init__.py +13 -14
  192. alita_sdk/tools/github/github_client.py +224 -100
  193. alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
  194. alita_sdk/tools/github/schemas.py +14 -5
  195. alita_sdk/tools/github/tool.py +5 -1
  196. alita_sdk/tools/github/tool_prompts.py +9 -22
  197. alita_sdk/tools/gitlab/__init__.py +15 -11
  198. alita_sdk/tools/gitlab/api_wrapper.py +207 -41
  199. alita_sdk/tools/gitlab_org/__init__.py +10 -8
  200. alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
  201. alita_sdk/tools/google/bigquery/__init__.py +13 -12
  202. alita_sdk/tools/google/bigquery/tool.py +5 -1
  203. alita_sdk/tools/google_places/__init__.py +10 -8
  204. alita_sdk/tools/google_places/api_wrapper.py +1 -1
  205. alita_sdk/tools/jira/__init__.py +17 -11
  206. alita_sdk/tools/jira/api_wrapper.py +91 -40
  207. alita_sdk/tools/keycloak/__init__.py +11 -8
  208. alita_sdk/tools/localgit/__init__.py +9 -3
  209. alita_sdk/tools/localgit/local_git.py +62 -54
  210. alita_sdk/tools/localgit/tool.py +5 -1
  211. alita_sdk/tools/memory/__init__.py +11 -3
  212. alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
  213. alita_sdk/tools/ocr/__init__.py +11 -8
  214. alita_sdk/tools/openapi/__init__.py +490 -114
  215. alita_sdk/tools/openapi/api_wrapper.py +1368 -0
  216. alita_sdk/tools/openapi/tool.py +20 -0
  217. alita_sdk/tools/pandas/__init__.py +20 -12
  218. alita_sdk/tools/pandas/api_wrapper.py +38 -25
  219. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  220. alita_sdk/tools/postman/__init__.py +11 -11
  221. alita_sdk/tools/pptx/__init__.py +10 -9
  222. alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
  223. alita_sdk/tools/qtest/__init__.py +30 -10
  224. alita_sdk/tools/qtest/api_wrapper.py +430 -13
  225. alita_sdk/tools/rally/__init__.py +10 -8
  226. alita_sdk/tools/rally/api_wrapper.py +1 -1
  227. alita_sdk/tools/report_portal/__init__.py +12 -9
  228. alita_sdk/tools/salesforce/__init__.py +10 -9
  229. alita_sdk/tools/servicenow/__init__.py +17 -14
  230. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  231. alita_sdk/tools/sharepoint/__init__.py +10 -8
  232. alita_sdk/tools/sharepoint/api_wrapper.py +4 -4
  233. alita_sdk/tools/slack/__init__.py +10 -8
  234. alita_sdk/tools/slack/api_wrapper.py +2 -2
  235. alita_sdk/tools/sql/__init__.py +11 -9
  236. alita_sdk/tools/testio/__init__.py +10 -8
  237. alita_sdk/tools/testrail/__init__.py +11 -8
  238. alita_sdk/tools/testrail/api_wrapper.py +1 -1
  239. alita_sdk/tools/utils/__init__.py +9 -4
  240. alita_sdk/tools/utils/content_parser.py +77 -3
  241. alita_sdk/tools/utils/text_operations.py +410 -0
  242. alita_sdk/tools/utils/tool_prompts.py +79 -0
  243. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +17 -13
  244. alita_sdk/tools/xray/__init__.py +12 -9
  245. alita_sdk/tools/yagmail/__init__.py +9 -3
  246. alita_sdk/tools/zephyr/__init__.py +9 -7
  247. alita_sdk/tools/zephyr_enterprise/__init__.py +11 -8
  248. alita_sdk/tools/zephyr_essential/__init__.py +10 -8
  249. alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
  250. alita_sdk/tools/zephyr_essential/client.py +2 -2
  251. alita_sdk/tools/zephyr_scale/__init__.py +11 -9
  252. alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
  253. alita_sdk/tools/zephyr_squad/__init__.py +10 -8
  254. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +147 -7
  255. alita_sdk-0.3.627.dist-info/RECORD +468 -0
  256. alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
  257. alita_sdk-0.3.462.dist-info/RECORD +0 -384
  258. alita_sdk-0.3.462.dist-info/entry_points.txt +0 -2
  259. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
  260. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
  261. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,183 @@
1
+ """
2
+ Data Analysis internal tool for Alita SDK.
3
+
4
+ This tool provides Pandas-based data analysis capabilities as an internal tool,
5
+ accessible through the "Enable internal tools" dropdown menu.
6
+
7
+ It uses the conversation attachment bucket for file storage, providing seamless
8
+ integration with drag-and-drop file uploads in chat.
9
+ """
10
+ import logging
11
+ from typing import Any, List, Literal, Optional, Type
12
+
13
+ from langchain_core.tools import BaseTool, BaseToolkit
14
+ from pydantic import BaseModel, ConfigDict, create_model, Field
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ name = "data_analysis"
19
+
20
+
21
+ def get_tools(tools_list: list, alita_client=None, llm=None, memory_store=None):
22
+ """
23
+ Get data analysis tools for the provided tool configurations.
24
+
25
+ Args:
26
+ tools_list: List of tool configurations
27
+ alita_client: Alita client instance (required for data analysis)
28
+ llm: LLM client instance (required for code generation)
29
+ memory_store: Optional memory store instance (unused)
30
+
31
+ Returns:
32
+ List of data analysis tools
33
+ """
34
+ all_tools = []
35
+
36
+ for tool in tools_list:
37
+ if (tool.get('type') == 'data_analysis' or
38
+ tool.get('toolkit_name') == 'data_analysis'):
39
+ try:
40
+ if not alita_client:
41
+ logger.error("Alita client is required for data analysis tools")
42
+ continue
43
+
44
+ settings = tool.get('settings', {})
45
+ bucket_name = settings.get('bucket_name')
46
+
47
+ if not bucket_name:
48
+ logger.error("bucket_name is required for data analysis tools")
49
+ continue
50
+
51
+ toolkit_instance = DataAnalysisToolkit.get_toolkit(
52
+ alita_client=alita_client,
53
+ llm=llm,
54
+ bucket_name=bucket_name,
55
+ toolkit_name=tool.get('toolkit_name', '')
56
+ )
57
+ all_tools.extend(toolkit_instance.get_tools())
58
+ except Exception as e:
59
+ logger.error(f"Error in data analysis toolkit get_tools: {e}")
60
+ logger.error(f"Tool config: {tool}")
61
+ raise
62
+
63
+ return all_tools
64
+
65
+
66
+ class DataAnalysisToolkit(BaseToolkit):
67
+ """
68
+ Data Analysis toolkit providing Pandas-based data analysis capabilities.
69
+
70
+ This is an internal tool that uses the conversation attachment bucket
71
+ for file storage, enabling seamless integration with chat file uploads.
72
+ """
73
+ tools: List[BaseTool] = []
74
+
75
+ @staticmethod
76
+ def toolkit_config_schema() -> Type[BaseModel]:
77
+ """Get the configuration schema for the data analysis toolkit."""
78
+ # Import PandasWrapper to get available tools schema
79
+ from alita_sdk.tools.pandas.api_wrapper import PandasWrapper
80
+
81
+ selected_tools = {
82
+ x['name']: x['args_schema'].model_json_schema()
83
+ for x in PandasWrapper.model_construct().get_available_tools()
84
+ }
85
+
86
+ return create_model(
87
+ 'data_analysis',
88
+ bucket_name=(
89
+ Optional[str],
90
+ Field(
91
+ default=None,
92
+ title="Bucket name",
93
+ description="Bucket where files are stored (auto-injected from conversation)"
94
+ )
95
+ ),
96
+ selected_tools=(
97
+ List[Literal[tuple(selected_tools)]],
98
+ Field(
99
+ default=[],
100
+ json_schema_extra={'args_schemas': selected_tools}
101
+ )
102
+ ),
103
+ __config__=ConfigDict(json_schema_extra={
104
+ 'metadata': {
105
+ "label": "Data Analysis",
106
+ "icon_url": "data-analysis.svg",
107
+ "hidden": True, # Hidden from regular toolkit menu
108
+ "categories": ["internal_tool"],
109
+ "extra_categories": ["data analysis", "pandas", "dataframes", "data science"],
110
+ }
111
+ })
112
+ )
113
+
114
+ @classmethod
115
+ def get_toolkit(
116
+ cls,
117
+ alita_client=None,
118
+ llm=None,
119
+ bucket_name: str = None,
120
+ toolkit_name: Optional[str] = None,
121
+ selected_tools: Optional[List[str]] = None,
122
+ **kwargs
123
+ ):
124
+ """
125
+ Get toolkit with data analysis tools.
126
+
127
+ Args:
128
+ alita_client: Alita client instance (required)
129
+ llm: LLM for code generation (optional, uses alita_client.llm if not provided)
130
+ bucket_name: Conversation attachment bucket (required)
131
+ toolkit_name: Optional name prefix for tools
132
+ selected_tools: Optional list of tool names to include (default: all)
133
+ **kwargs: Additional arguments
134
+
135
+ Returns:
136
+ DataAnalysisToolkit instance with configured tools
137
+
138
+ Raises:
139
+ ValueError: If alita_client or bucket_name is not provided
140
+ """
141
+ if not alita_client:
142
+ raise ValueError("Alita client is required for data analysis")
143
+
144
+ if not bucket_name:
145
+ raise ValueError("bucket_name is required for data analysis (should be conversation attachment bucket)")
146
+
147
+ # Import the PandasWrapper from existing toolkit
148
+ from alita_sdk.tools.pandas.api_wrapper import PandasWrapper
149
+ from alita_sdk.tools.base.tool import BaseAction
150
+
151
+ # Create wrapper with conversation bucket
152
+ wrapper = PandasWrapper(
153
+ alita=alita_client,
154
+ llm=llm,
155
+ bucket_name=bucket_name
156
+ )
157
+
158
+ # Get tools from wrapper
159
+ available_tools = wrapper.get_available_tools()
160
+ tools = []
161
+
162
+ for tool in available_tools:
163
+ # Filter by selected_tools if provided
164
+ if selected_tools and tool["name"] not in selected_tools:
165
+ continue
166
+
167
+ description = tool["description"]
168
+ if toolkit_name:
169
+ description = f"Toolkit: {toolkit_name}\n{description}"
170
+ description = description[:1000]
171
+
172
+ tools.append(BaseAction(
173
+ api_wrapper=wrapper,
174
+ name=tool["name"],
175
+ description=description,
176
+ args_schema=tool["args_schema"],
177
+ metadata={"toolkit_name": toolkit_name, "toolkit_type": name} if toolkit_name else {}
178
+ ))
179
+
180
+ return cls(tools=tools)
181
+
182
+ def get_tools(self):
183
+ return self.tools
@@ -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,36 @@ 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
- # add state into the code block here since it might be changed during the execution of the code
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) and compression to minimize args list
49
+ """
50
+ import base64
51
+ import zlib
52
+
45
53
  state_copy = replace_escaped_newlines(deepcopy(state))
54
+ if 'messages' in state_copy:
55
+ del state_copy['messages']
56
+
57
+ # Use safe_serialize to handle Pydantic models, datetime, and other non-JSON types
58
+ state_json = safe_serialize(state_copy)
46
59
 
47
- del state_copy['messages'] # remove messages to avoid issues with pickling without langchain-core
48
- # inject state into the code block as alita_state variable
49
- state_json = json.dumps(state_copy, ensure_ascii=False)
50
- pyodide_predata = f'#state dict\nimport json\nalita_state = json.loads({json.dumps(state_json)})\n'
60
+ # Use base64 encoding to avoid all string escaping issues
61
+ # This is more robust than repr() when the code passes through multiple parsers
62
+ # use compression to avoid issue with `{"error": "Error executing code: [Errno 7] Argument list too long: 'deno'"}`
63
+ compressed = zlib.compress(state_json.encode('utf-8'))
64
+ encoded = base64.b64encode(compressed).decode('ascii')
65
+
66
+ pyodide_predata = f'''#state dict
67
+ import json
68
+ import base64
69
+ import zlib
51
70
 
71
+ compressed_state = base64.b64decode('{encoded}')
72
+ state_json = zlib.decompress(compressed_state).decode('utf-8')
73
+ alita_state = json.loads(state_json)
74
+ '''
52
75
  return pyodide_predata
53
76
 
54
77
  def _handle_pyodide_output(self, tool_result: Any) -> dict:
@@ -107,7 +130,8 @@ class FunctionTool(BaseTool):
107
130
 
108
131
  # special handler for PyodideSandboxTool
109
132
  if self._is_pyodide_tool():
110
- code = func_args['code']
133
+ # replace new lines in strings in code block
134
+ code = func_args['code'].replace('\\n', '\\\\n')
111
135
  func_args['code'] = f"{self._prepare_pyodide_input(state)}\n{code}"
112
136
  try:
113
137
  tool_result = self.tool.invoke(func_args, config, **kwargs)
@@ -129,14 +153,18 @@ class FunctionTool(BaseTool):
129
153
  return {"messages": [{"role": "assistant", "content": dumps(tool_result)}]}
130
154
  else:
131
155
  if "messages" in self.output_variables:
132
- messages_dict = {
133
- "messages": [{
134
- "role": "assistant",
135
- "content": dumps(tool_result)
136
- if not isinstance(tool_result, ToolException) and not isinstance(tool_result, str)
137
- else str(tool_result)
138
- }]
139
- }
156
+ if 'messages' in tool_result:
157
+ # case when the sub-graph has been executed
158
+ messages_dict = {"messages": tool_result['messages']}
159
+ else:
160
+ messages_dict = {
161
+ "messages": [{
162
+ "role": "assistant",
163
+ "content": dumps(tool_result)
164
+ if not isinstance(tool_result, ToolException) and not isinstance(tool_result, str)
165
+ else str(tool_result)
166
+ }]
167
+ }
140
168
  for var in self.output_variables:
141
169
  if var != "messages":
142
170
  if isinstance(tool_result, dict) and var in tool_result:
@@ -1,7 +1,9 @@
1
1
  """
2
2
  Image generation tool for Alita SDK.
3
3
  """
4
+ import json
4
5
  import logging
6
+ import uuid
5
7
  from typing import Optional, Type, Any, List, Literal
6
8
  from langchain_core.tools import BaseTool, BaseToolkit
7
9
  from pydantic import BaseModel, Field, create_model, ConfigDict
@@ -76,7 +78,12 @@ class ImageGenerationTool(BaseTool):
76
78
  """Tool for generating images using the Alita client."""
77
79
 
78
80
  name: str = "generate_image"
79
- description: str = "Generate images from text prompts using AI models"
81
+ description: str = (
82
+ "Generate images from text prompts using AI models. "
83
+ "Returns a JSON object with 'cached_image_id' field containing a reference to the generated image data. "
84
+ "The cached_image_id can be used to save or process the image. "
85
+ "The actual image data is stored temporarily and can be retrieved using the cached_image_id reference."
86
+ )
80
87
  args_schema: Type[BaseModel] = ImageGenerationInput
81
88
  alita_client: Any = None
82
89
 
@@ -85,10 +92,10 @@ class ImageGenerationTool(BaseTool):
85
92
  self.alita_client = client
86
93
 
87
94
  def _run(self, prompt: str, n: int = 1, size: str = "auto",
88
- quality: str = "auto", style: Optional[str] = None) -> list:
95
+ quality: str = "auto", style: Optional[str] = None) -> str:
89
96
  """Generate an image based on the provided parameters."""
90
97
  try:
91
- logger.info(f"Generating image with prompt: {prompt[:50]}...")
98
+ logger.debug(f"Generating image with prompt: {prompt[:50]}...")
92
99
 
93
100
  result = self.alita_client.generate_image(
94
101
  prompt=prompt,
@@ -98,57 +105,56 @@ class ImageGenerationTool(BaseTool):
98
105
  style=style
99
106
  )
100
107
 
101
- # Return multimodal content format for LLM consumption
108
+ # Return simple JSON structure with reference ID instead of full base64
102
109
  if 'data' in result:
103
110
  images = result['data']
104
- content_chunks = []
105
111
 
106
- # Add a text description of what was generated
107
- if len(images) == 1:
108
- content_chunks.append({
109
- "type": "text",
110
- "text": f"Generated image for prompt: '{prompt}'"
111
- })
112
- else:
113
- content_chunks.append({
114
- "type": "text",
115
- "text": f"Generated {len(images)} images for "
116
- f"prompt: '{prompt}'"
112
+ # Process all images with unified structure
113
+ images_list = []
114
+ for idx, image_data in enumerate(images, 1):
115
+ if not image_data.get('b64_json'):
116
+ continue
117
+
118
+ cached_image_id = f"img_{uuid.uuid4().hex[:12]}"
119
+
120
+ # Store in cache
121
+ if hasattr(self.alita_client, '_generated_images_cache'):
122
+ self.alita_client._generated_images_cache[cached_image_id] = {
123
+ 'base64_data': image_data['b64_json']
124
+ }
125
+ logger.debug(f"Stored generated image in cache with ID: {cached_image_id}")
126
+
127
+ images_list.append({
128
+ "image_number": idx,
129
+ "image_type": "png",
130
+ "cached_image_id": cached_image_id
117
131
  })
118
132
 
119
- # Add image content for each generated image
120
- for image_data in images:
121
- if image_data.get('url'):
122
- content_chunks.append({
123
- "type": "image_url",
124
- "image_url": {
125
- "url": image_data['url']
126
- }
127
- })
128
- elif image_data.get('b64_json'):
129
- content_chunks.append({
130
- "type": "image_url",
131
- "image_url": {
132
- "url": f"data:image/png;base64,"
133
- f"{image_data['b64_json']}"
134
- }
135
- })
133
+ if not images_list:
134
+ return json.dumps({
135
+ "status": "error",
136
+ "message": "No base64 image data found"
137
+ })
136
138
 
137
- return content_chunks
139
+ return json.dumps({
140
+ "status": "success",
141
+ "prompt": prompt,
142
+ "total_images": len(images_list),
143
+ "images": images_list
144
+ })
138
145
 
139
- # Fallback to text response if no images in result
140
- return [{
141
- "type": "text",
142
- "text": f"Image generation completed but no images "
143
- f"returned: {result}"
144
- }]
146
+ # Fallback to error response if no images in result
147
+ return json.dumps({
148
+ "status": "error",
149
+ "message": f"Image generation completed but no images returned: {result}"
150
+ })
145
151
 
146
152
  except Exception as e:
147
153
  logger.error(f"Error generating image: {e}")
148
- return [{
149
- "type": "text",
150
- "text": f"Error generating image: {str(e)}"
151
- }]
154
+ return json.dumps({
155
+ "status": "error",
156
+ "message": f"Error generating image: {str(e)}"
157
+ })
152
158
 
153
159
  async def _arun(self, prompt: str, n: int = 1, size: str = "256x256",
154
160
  quality: str = "auto",