alita-sdk 0.3.257__py3-none-any.whl → 0.3.562__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 (278) hide show
  1. alita_sdk/cli/__init__.py +10 -0
  2. alita_sdk/cli/__main__.py +17 -0
  3. alita_sdk/cli/agent/__init__.py +5 -0
  4. alita_sdk/cli/agent/default.py +258 -0
  5. alita_sdk/cli/agent_executor.py +155 -0
  6. alita_sdk/cli/agent_loader.py +215 -0
  7. alita_sdk/cli/agent_ui.py +228 -0
  8. alita_sdk/cli/agents.py +3601 -0
  9. alita_sdk/cli/callbacks.py +647 -0
  10. alita_sdk/cli/cli.py +168 -0
  11. alita_sdk/cli/config.py +306 -0
  12. alita_sdk/cli/context/__init__.py +30 -0
  13. alita_sdk/cli/context/cleanup.py +198 -0
  14. alita_sdk/cli/context/manager.py +731 -0
  15. alita_sdk/cli/context/message.py +285 -0
  16. alita_sdk/cli/context/strategies.py +289 -0
  17. alita_sdk/cli/context/token_estimation.py +127 -0
  18. alita_sdk/cli/formatting.py +182 -0
  19. alita_sdk/cli/input_handler.py +419 -0
  20. alita_sdk/cli/inventory.py +1073 -0
  21. alita_sdk/cli/mcp_loader.py +315 -0
  22. alita_sdk/cli/toolkit.py +327 -0
  23. alita_sdk/cli/toolkit_loader.py +85 -0
  24. alita_sdk/cli/tools/__init__.py +43 -0
  25. alita_sdk/cli/tools/approval.py +224 -0
  26. alita_sdk/cli/tools/filesystem.py +1751 -0
  27. alita_sdk/cli/tools/planning.py +389 -0
  28. alita_sdk/cli/tools/terminal.py +414 -0
  29. alita_sdk/community/__init__.py +72 -12
  30. alita_sdk/community/inventory/__init__.py +236 -0
  31. alita_sdk/community/inventory/config.py +257 -0
  32. alita_sdk/community/inventory/enrichment.py +2137 -0
  33. alita_sdk/community/inventory/extractors.py +1469 -0
  34. alita_sdk/community/inventory/ingestion.py +3172 -0
  35. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  36. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  37. alita_sdk/community/inventory/parsers/base.py +295 -0
  38. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  39. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  40. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  41. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  42. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  43. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  44. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  45. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  46. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  47. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  48. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  49. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  50. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  51. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  52. alita_sdk/community/inventory/patterns/loader.py +348 -0
  53. alita_sdk/community/inventory/patterns/registry.py +198 -0
  54. alita_sdk/community/inventory/presets.py +535 -0
  55. alita_sdk/community/inventory/retrieval.py +1403 -0
  56. alita_sdk/community/inventory/toolkit.py +173 -0
  57. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  58. alita_sdk/community/inventory/visualize.py +1370 -0
  59. alita_sdk/configurations/__init__.py +11 -0
  60. alita_sdk/configurations/ado.py +148 -2
  61. alita_sdk/configurations/azure_search.py +1 -1
  62. alita_sdk/configurations/bigquery.py +1 -1
  63. alita_sdk/configurations/bitbucket.py +94 -2
  64. alita_sdk/configurations/browser.py +18 -0
  65. alita_sdk/configurations/carrier.py +19 -0
  66. alita_sdk/configurations/confluence.py +130 -1
  67. alita_sdk/configurations/delta_lake.py +1 -1
  68. alita_sdk/configurations/figma.py +76 -5
  69. alita_sdk/configurations/github.py +65 -1
  70. alita_sdk/configurations/gitlab.py +81 -0
  71. alita_sdk/configurations/google_places.py +17 -0
  72. alita_sdk/configurations/jira.py +103 -0
  73. alita_sdk/configurations/openapi.py +111 -0
  74. alita_sdk/configurations/postman.py +1 -1
  75. alita_sdk/configurations/qtest.py +72 -3
  76. alita_sdk/configurations/report_portal.py +115 -0
  77. alita_sdk/configurations/salesforce.py +19 -0
  78. alita_sdk/configurations/service_now.py +1 -12
  79. alita_sdk/configurations/sharepoint.py +167 -0
  80. alita_sdk/configurations/sonar.py +18 -0
  81. alita_sdk/configurations/sql.py +20 -0
  82. alita_sdk/configurations/testio.py +101 -0
  83. alita_sdk/configurations/testrail.py +88 -0
  84. alita_sdk/configurations/xray.py +94 -1
  85. alita_sdk/configurations/zephyr_enterprise.py +94 -1
  86. alita_sdk/configurations/zephyr_essential.py +95 -0
  87. alita_sdk/runtime/clients/artifact.py +21 -4
  88. alita_sdk/runtime/clients/client.py +458 -67
  89. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  90. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  91. alita_sdk/runtime/clients/sandbox_client.py +352 -0
  92. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  93. alita_sdk/runtime/langchain/assistant.py +183 -43
  94. alita_sdk/runtime/langchain/constants.py +647 -1
  95. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  96. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
  97. alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
  98. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  99. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -3
  100. alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
  101. alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
  102. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
  103. alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
  104. alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
  105. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
  106. alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
  107. alita_sdk/runtime/langchain/document_loaders/constants.py +189 -41
  108. alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
  109. alita_sdk/runtime/langchain/langraph_agent.py +407 -92
  110. alita_sdk/runtime/langchain/utils.py +102 -8
  111. alita_sdk/runtime/llms/preloaded.py +2 -6
  112. alita_sdk/runtime/models/mcp_models.py +61 -0
  113. alita_sdk/runtime/skills/__init__.py +91 -0
  114. alita_sdk/runtime/skills/callbacks.py +498 -0
  115. alita_sdk/runtime/skills/discovery.py +540 -0
  116. alita_sdk/runtime/skills/executor.py +610 -0
  117. alita_sdk/runtime/skills/input_builder.py +371 -0
  118. alita_sdk/runtime/skills/models.py +330 -0
  119. alita_sdk/runtime/skills/registry.py +355 -0
  120. alita_sdk/runtime/skills/skill_runner.py +330 -0
  121. alita_sdk/runtime/toolkits/__init__.py +28 -0
  122. alita_sdk/runtime/toolkits/application.py +14 -4
  123. alita_sdk/runtime/toolkits/artifact.py +24 -9
  124. alita_sdk/runtime/toolkits/datasource.py +13 -6
  125. alita_sdk/runtime/toolkits/mcp.py +780 -0
  126. alita_sdk/runtime/toolkits/planning.py +178 -0
  127. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  128. alita_sdk/runtime/toolkits/subgraph.py +11 -6
  129. alita_sdk/runtime/toolkits/tools.py +314 -70
  130. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  131. alita_sdk/runtime/tools/__init__.py +24 -0
  132. alita_sdk/runtime/tools/application.py +16 -4
  133. alita_sdk/runtime/tools/artifact.py +367 -33
  134. alita_sdk/runtime/tools/data_analysis.py +183 -0
  135. alita_sdk/runtime/tools/function.py +100 -4
  136. alita_sdk/runtime/tools/graph.py +81 -0
  137. alita_sdk/runtime/tools/image_generation.py +218 -0
  138. alita_sdk/runtime/tools/llm.py +1013 -177
  139. alita_sdk/runtime/tools/loop.py +3 -1
  140. alita_sdk/runtime/tools/loop_output.py +3 -1
  141. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  142. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  143. alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
  144. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  145. alita_sdk/runtime/tools/planning/models.py +246 -0
  146. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  147. alita_sdk/runtime/tools/router.py +2 -1
  148. alita_sdk/runtime/tools/sandbox.py +375 -0
  149. alita_sdk/runtime/tools/skill_router.py +776 -0
  150. alita_sdk/runtime/tools/tool.py +3 -1
  151. alita_sdk/runtime/tools/vectorstore.py +69 -65
  152. alita_sdk/runtime/tools/vectorstore_base.py +163 -90
  153. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  154. alita_sdk/runtime/utils/mcp_client.py +492 -0
  155. alita_sdk/runtime/utils/mcp_oauth.py +361 -0
  156. alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
  157. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  158. alita_sdk/runtime/utils/streamlit.py +41 -14
  159. alita_sdk/runtime/utils/toolkit_utils.py +28 -9
  160. alita_sdk/runtime/utils/utils.py +48 -0
  161. alita_sdk/tools/__init__.py +135 -37
  162. alita_sdk/tools/ado/__init__.py +2 -2
  163. alita_sdk/tools/ado/repos/__init__.py +15 -19
  164. alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
  165. alita_sdk/tools/ado/test_plan/__init__.py +26 -8
  166. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
  167. alita_sdk/tools/ado/wiki/__init__.py +27 -12
  168. alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
  169. alita_sdk/tools/ado/work_item/__init__.py +27 -12
  170. alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
  171. alita_sdk/tools/advanced_jira_mining/__init__.py +12 -8
  172. alita_sdk/tools/aws/delta_lake/__init__.py +14 -11
  173. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  174. alita_sdk/tools/azure_ai/search/__init__.py +13 -8
  175. alita_sdk/tools/base/tool.py +5 -1
  176. alita_sdk/tools/base_indexer_toolkit.py +454 -110
  177. alita_sdk/tools/bitbucket/__init__.py +27 -19
  178. alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
  179. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
  180. alita_sdk/tools/browser/__init__.py +41 -16
  181. alita_sdk/tools/browser/crawler.py +3 -1
  182. alita_sdk/tools/browser/utils.py +15 -6
  183. alita_sdk/tools/carrier/__init__.py +18 -17
  184. alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
  185. alita_sdk/tools/carrier/excel_reporter.py +8 -4
  186. alita_sdk/tools/chunkers/__init__.py +3 -1
  187. alita_sdk/tools/chunkers/code/codeparser.py +1 -1
  188. alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
  189. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  190. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  191. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  192. alita_sdk/tools/cloud/aws/__init__.py +11 -7
  193. alita_sdk/tools/cloud/azure/__init__.py +11 -7
  194. alita_sdk/tools/cloud/gcp/__init__.py +11 -7
  195. alita_sdk/tools/cloud/k8s/__init__.py +11 -7
  196. alita_sdk/tools/code/linter/__init__.py +9 -8
  197. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  198. alita_sdk/tools/code/sonar/__init__.py +20 -13
  199. alita_sdk/tools/code_indexer_toolkit.py +199 -0
  200. alita_sdk/tools/confluence/__init__.py +21 -14
  201. alita_sdk/tools/confluence/api_wrapper.py +197 -58
  202. alita_sdk/tools/confluence/loader.py +14 -2
  203. alita_sdk/tools/custom_open_api/__init__.py +11 -5
  204. alita_sdk/tools/elastic/__init__.py +10 -8
  205. alita_sdk/tools/elitea_base.py +546 -64
  206. alita_sdk/tools/figma/__init__.py +11 -8
  207. alita_sdk/tools/figma/api_wrapper.py +352 -153
  208. alita_sdk/tools/github/__init__.py +17 -17
  209. alita_sdk/tools/github/api_wrapper.py +9 -26
  210. alita_sdk/tools/github/github_client.py +81 -12
  211. alita_sdk/tools/github/schemas.py +2 -1
  212. alita_sdk/tools/github/tool.py +5 -1
  213. alita_sdk/tools/gitlab/__init__.py +18 -13
  214. alita_sdk/tools/gitlab/api_wrapper.py +224 -80
  215. alita_sdk/tools/gitlab_org/__init__.py +13 -10
  216. alita_sdk/tools/google/bigquery/__init__.py +13 -13
  217. alita_sdk/tools/google/bigquery/tool.py +5 -1
  218. alita_sdk/tools/google_places/__init__.py +20 -11
  219. alita_sdk/tools/jira/__init__.py +21 -11
  220. alita_sdk/tools/jira/api_wrapper.py +315 -168
  221. alita_sdk/tools/keycloak/__init__.py +10 -8
  222. alita_sdk/tools/localgit/__init__.py +8 -3
  223. alita_sdk/tools/localgit/local_git.py +62 -54
  224. alita_sdk/tools/localgit/tool.py +5 -1
  225. alita_sdk/tools/memory/__init__.py +38 -14
  226. alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
  227. alita_sdk/tools/ocr/__init__.py +10 -8
  228. alita_sdk/tools/openapi/__init__.py +281 -108
  229. alita_sdk/tools/openapi/api_wrapper.py +883 -0
  230. alita_sdk/tools/openapi/tool.py +20 -0
  231. alita_sdk/tools/pandas/__init__.py +18 -11
  232. alita_sdk/tools/pandas/api_wrapper.py +40 -45
  233. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  234. alita_sdk/tools/postman/__init__.py +10 -11
  235. alita_sdk/tools/postman/api_wrapper.py +19 -8
  236. alita_sdk/tools/postman/postman_analysis.py +8 -1
  237. alita_sdk/tools/pptx/__init__.py +10 -10
  238. alita_sdk/tools/qtest/__init__.py +21 -14
  239. alita_sdk/tools/qtest/api_wrapper.py +1784 -88
  240. alita_sdk/tools/rally/__init__.py +12 -10
  241. alita_sdk/tools/report_portal/__init__.py +22 -16
  242. alita_sdk/tools/salesforce/__init__.py +21 -16
  243. alita_sdk/tools/servicenow/__init__.py +20 -16
  244. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  245. alita_sdk/tools/sharepoint/__init__.py +16 -14
  246. alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
  247. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  248. alita_sdk/tools/sharepoint/utils.py +8 -2
  249. alita_sdk/tools/slack/__init__.py +11 -7
  250. alita_sdk/tools/sql/__init__.py +21 -19
  251. alita_sdk/tools/sql/api_wrapper.py +71 -23
  252. alita_sdk/tools/testio/__init__.py +20 -13
  253. alita_sdk/tools/testrail/__init__.py +12 -11
  254. alita_sdk/tools/testrail/api_wrapper.py +214 -46
  255. alita_sdk/tools/utils/__init__.py +28 -4
  256. alita_sdk/tools/utils/content_parser.py +182 -62
  257. alita_sdk/tools/utils/text_operations.py +254 -0
  258. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
  259. alita_sdk/tools/xray/__init__.py +17 -14
  260. alita_sdk/tools/xray/api_wrapper.py +58 -113
  261. alita_sdk/tools/yagmail/__init__.py +8 -3
  262. alita_sdk/tools/zephyr/__init__.py +11 -7
  263. alita_sdk/tools/zephyr_enterprise/__init__.py +15 -9
  264. alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
  265. alita_sdk/tools/zephyr_essential/__init__.py +15 -10
  266. alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
  267. alita_sdk/tools/zephyr_essential/client.py +6 -4
  268. alita_sdk/tools/zephyr_scale/__init__.py +12 -8
  269. alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
  270. alita_sdk/tools/zephyr_squad/__init__.py +11 -7
  271. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/METADATA +184 -37
  272. alita_sdk-0.3.562.dist-info/RECORD +450 -0
  273. alita_sdk-0.3.562.dist-info/entry_points.txt +2 -0
  274. alita_sdk/tools/bitbucket/tools.py +0 -304
  275. alita_sdk-0.3.257.dist-info/RECORD +0 -343
  276. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/WHEEL +0 -0
  277. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/licenses/LICENSE +0 -0
  278. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,20 @@
1
+ from typing import Optional, Type
2
+
3
+ from pydantic import BaseModel, Field, field_validator
4
+
5
+ from ..base.tool import BaseAction
6
+ from .api_wrapper import OpenApiApiWrapper
7
+
8
+
9
+ class OpenApiAction(BaseAction):
10
+ """Tool for executing a single OpenAPI operation."""
11
+
12
+ api_wrapper: OpenApiApiWrapper = Field(default_factory=OpenApiApiWrapper)
13
+ name: str
14
+ description: str = ""
15
+ args_schema: Optional[Type[BaseModel]] = None
16
+
17
+ @field_validator('name', mode='before')
18
+ @classmethod
19
+ def remove_spaces(cls, v: str) -> str:
20
+ return v.replace(' ', '')
@@ -5,7 +5,7 @@ from pydantic import BaseModel, ConfigDict, create_model, Field
5
5
 
6
6
  from .api_wrapper import PandasWrapper
7
7
  from ..base.tool import BaseAction
8
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
9
 
10
10
  name = "pandas"
11
11
 
@@ -21,19 +21,22 @@ def get_tools(tool):
21
21
 
22
22
  class PandasToolkit(BaseToolkit):
23
23
  tools: List[BaseTool] = []
24
- toolkit_max_length: int = 0
25
24
 
26
25
  @staticmethod
27
26
  def toolkit_config_schema() -> BaseModel:
28
27
  selected_tools = {x['name']: x['args_schema'].schema() for x in PandasWrapper.model_construct().get_available_tools()}
29
- PandasToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
28
  return create_model(
31
29
  name,
32
- bucket_name=(str, Field(default=None, title="Bucket name", description="Bucket where the content file is stored", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': PandasToolkit.toolkit_max_length})),
30
+ bucket_name=(str, Field(default=None, title="Bucket name", description="Bucket where the content file is stored")),
33
31
  selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
34
- __config__=ConfigDict(json_schema_extra={'metadata': {"label": "Pandas", "icon_url": "pandas-icon.svg",
35
- "categories": ["analysis"],
36
- "extra_categories": ["data science", "data manipulation", "dataframes"]}})
32
+ __config__=ConfigDict(json_schema_extra={'metadata': {
33
+ "label": "Pandas (Deprecated)",
34
+ "icon_url": "pandas-icon.svg",
35
+ "categories": ["analysis"],
36
+ "deprecated": True,
37
+ "deprecation_message": "This toolkit is deprecated. Use the 'Data Analysis' internal tool instead. Enable it via the 'Internal Tools' menu in chat.",
38
+ "extra_categories": ["data science", "data manipulation", "dataframes"]
39
+ }})
37
40
  )
38
41
 
39
42
  @classmethod
@@ -41,17 +44,21 @@ class PandasToolkit(BaseToolkit):
41
44
  if selected_tools is None:
42
45
  selected_tools = []
43
46
  csv_tool_api_wrapper = PandasWrapper(**kwargs)
44
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
45
47
  available_tools = csv_tool_api_wrapper.get_available_tools()
46
48
  tools = []
47
49
  for tool in available_tools:
48
50
  if selected_tools and tool["name"] not in selected_tools:
49
51
  continue
52
+ description = tool["description"]
53
+ if toolkit_name:
54
+ description = f"Toolkit: {toolkit_name}\n{description}"
55
+ description = description[:1000]
50
56
  tools.append(BaseAction(
51
57
  api_wrapper=csv_tool_api_wrapper,
52
- name=prefix + tool["name"],
53
- description=tool["description"],
54
- args_schema=tool["args_schema"]
58
+ name=tool["name"],
59
+ description=description,
60
+ args_schema=tool["args_schema"],
61
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
55
62
  ))
56
63
  return cls(tools=tools)
57
64
 
@@ -93,7 +93,7 @@ class PandasWrapper(BaseToolApiWrapper):
93
93
  if file_extension in ['csv', 'txt']:
94
94
  df = pd.read_csv(file_obj)
95
95
  elif file_extension in ['xlsx', 'xls']:
96
- df = pd.read_excel(file_obj)
96
+ df = pd.read_excel(file_obj, engine='calamine')
97
97
  elif file_extension == 'parquet':
98
98
  df = pd.read_parquet(file_obj)
99
99
  elif file_extension == 'json':
@@ -158,57 +158,62 @@ class PandasWrapper(BaseToolApiWrapper):
158
158
  f"Retrying Code Generation ({attempts}/{max_retries})..."
159
159
  )
160
160
 
161
- def process_query(self, query: str, filename: str) -> str:
162
- """Analyze and process using query on dataset"""
161
+ def pandas_analyze_data(self, query: str, filename: str) -> str:
162
+ """Analyze data from a file using natural language query.
163
+
164
+ This tool allows you to perform data analysis operations on files using natural language.
165
+ It automatically generates and executes Python pandas code based on your query.
166
+
167
+ Supported file formats: CSV, Excel (.xlsx, .xls), Parquet, JSON, XML, HDF5, Feather, Pickle
168
+
169
+ Parameters:
170
+ query: Natural language description of the analysis to perform. Examples:
171
+ - "Calculate the average sales by region"
172
+ - "Show me a bar chart of products by revenue"
173
+ - "Filter rows where price > 100 and status is 'active'"
174
+ - "What is the correlation between age and income?"
175
+ filename: Name of the file in the artifact bucket (e.g., 'sales_data.csv', 'report.xlsx')
176
+
177
+ Returns:
178
+ Analysis results as text, or confirmation message if a chart was generated and saved.
179
+ Charts are automatically saved to the artifact bucket as PNG files.
180
+
181
+ Examples:
182
+ - pandas_analyze_data(query="Show summary statistics", filename="data.csv")
183
+ - pandas_analyze_data(query="Create a histogram of ages", filename="customers.xlsx")
184
+ - pandas_analyze_data(query="What's the total revenue by month?", filename="sales.parquet")
185
+ """
163
186
  df = self._get_dataframe(filename)
164
187
  code = self.generate_code_with_retries(df, query)
165
- dispatch_custom_event(
166
- name="thinking_step",
167
- data={
168
- "message": f"Executing generated code... \n\n```python\n{code}\n```",
169
- "tool_name": "process_query",
170
- "toolkit": "pandas"
171
- }
172
- )
188
+ self._log_tool_event(tool_name="pandas_analyze_data",
189
+ message=f"Executing generated code... \n\n```python\n{code}\n```")
173
190
  try:
174
191
  result = self.execute_code(df, code)
175
192
  except Exception as e:
176
193
  logger.error(f"Code execution failed: {format_exc()}")
177
- dispatch_custom_event(
178
- name="thinking_step",
179
- data={
180
- "message": f"Code execution failed: {format_exc()}",
181
- "tool_name": "process_query",
182
- "toolkit": "pandas"
183
- }
184
- )
185
194
  raise
186
- dispatch_custom_event(
187
- name="thinking_step",
188
- data={
189
- "message": f"Result of code execution... \n\n```\n{result['result']}\n```",
190
- "tool_name": "process_query",
191
- "toolkit": "pandas"
192
- }
193
- )
194
195
  if result.get("df") is not None:
195
196
  df = result.pop("df")
196
197
  # Not saving dataframe to artifact repo for now
197
198
  # self._save_dataframe(df, filename)
198
199
  if result.get('chart'):
200
+ chart_results = []
199
201
  if isinstance(result['chart'], list):
200
202
  for ind, chart in enumerate(result['chart']):
201
203
  chart_filename = f"chart_{uuid4()}.png"
202
204
  chart_data = base64.b64decode(chart)
203
205
  self.alita.create_artifact(self.bucket_name, chart_filename, chart_data)
204
- result['result'] = f"Chart #{ind} saved to {chart_filename}"
206
+ chart_url = f"{self.alita.base_url}/api/v1/artifacts/artifact/default/{self.alita.project_id}/{self.bucket_name}/{chart_filename}"
207
+ chart_results.append(f"Chart #{ind+1} saved and available at: {chart_url}")
208
+ result['result'] = "\n".join(chart_results)
205
209
  else:
206
210
  # Handle single chart case (not in a list)
207
211
  chart = result['chart']
208
212
  chart_filename = f"chart_{uuid4()}.png"
209
213
  chart_data = base64.b64decode(chart)
210
214
  self.alita.create_artifact(self.bucket_name, chart_filename, chart_data)
211
- result['result'] = f"Chart saved to {chart_filename}"
215
+ chart_url = f"{self.alita.base_url}/api/v1/artifacts/artifact/default/{self.alita.project_id}/{self.bucket_name}/{chart_filename}"
216
+ result['result'] = f"Chart saved and available at: {chart_url}\n\nYou can embed this image in your response using markdown: ![Chart]({chart_url})"
212
217
  return result.get("result", None)
213
218
 
214
219
  def save_dataframe(self, source_df: str, target_file: str) -> str:
@@ -271,23 +276,13 @@ class PandasWrapper(BaseToolApiWrapper):
271
276
  def get_available_tools(self):
272
277
  return [
273
278
  {
274
- "name": "process_query",
275
- "ref": self.process_query,
276
- "description": self.process_query.__doc__,
277
- "args_schema": create_model(
278
- "ProcessQueryModel",
279
- query=(str, Field(description="Task to solve")),
280
- filename=(str, Field(description="File to be processed"))
281
- )
282
- },
283
- {
284
- "name": "save_dataframe",
285
- "ref": self.save_dataframe,
286
- "description": self.save_dataframe.__doc__,
279
+ "name": "pandas_analyze_data",
280
+ "ref": self.pandas_analyze_data,
281
+ "description": self.pandas_analyze_data.__doc__,
287
282
  "args_schema": create_model(
288
- "SaveDataFrameModel",
289
- source_df=(str, Field(description="Source dataframe file to be saved")),
290
- target_file=(str, Field(description="Target filename with extension for saving"))
283
+ "AnalyseDataModel",
284
+ query=(str, Field(description="Natural language query describing what analysis to perform on the data")),
285
+ filename=(str, Field(description="Name of the file to analyze (e.g., 'data.csv', 'report.xlsx')"))
291
286
  )
292
287
  }
293
288
  ]
@@ -39,7 +39,9 @@ class CodeGenerator:
39
39
  {"role": "user", "content": [{"type": "text", "text": prompt}]}
40
40
  ]
41
41
  # Generate the code
42
- code = self.llm.invoke(messages).content
42
+ from alita_sdk.runtime.langchain.utils import extract_text_from_completion
43
+ completion = self.llm.invoke(messages)
44
+ code = extract_text_from_completion(completion)
43
45
  return self.validate_and_clean_code(code)
44
46
 
45
47
  except Exception as e:
@@ -6,7 +6,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field, field_validator
6
6
  from ..base.tool import BaseAction
7
7
 
8
8
  from .api_wrapper import PostmanApiWrapper
9
- from ..utils import clean_string, get_max_toolkit_length, TOOLKIT_SPLITTER, check_connection_response
9
+ from ..utils import clean_string, get_max_toolkit_length, check_connection_response
10
10
  from ...configurations.postman import PostmanConfiguration
11
11
 
12
12
  name = "postman"
@@ -43,20 +43,16 @@ def get_tools(tool):
43
43
 
44
44
  class PostmanToolkit(BaseToolkit):
45
45
  tools: List[BaseTool] = []
46
- toolkit_max_length: int = 0
47
46
 
48
47
  @staticmethod
49
48
  def toolkit_config_schema() -> BaseModel:
50
49
  selected_tools = {x['name']: x['args_schema'].schema(
51
50
  ) for x in PostmanApiWrapper.model_construct().get_available_tools()}
52
- PostmanToolkit.toolkit_max_length = get_max_toolkit_length(
53
- selected_tools)
54
51
  m = create_model(
55
52
  name,
56
53
  postman_configuration=(Optional[PostmanConfiguration], Field(description="Postman Configuration",
57
54
  json_schema_extra={'configuration_types': ['postman']})),
58
- collection_id=(str, Field(description="Default collection ID", json_schema_extra={
59
- 'toolkit_name': True, 'max_toolkit_length': PostmanToolkit.toolkit_max_length})),
55
+ collection_id=(str, Field(description="Default collection ID")),
60
56
  environment_config=(dict, Field(
61
57
  description="JSON configuration for request execution (auth headers, project IDs, base URLs, etc.)",
62
58
  default={})),
@@ -90,20 +86,23 @@ class PostmanToolkit(BaseToolkit):
90
86
  **kwargs['postman_configuration'],
91
87
  }
92
88
  postman_api_wrapper = PostmanApiWrapper(**wrapper_payload)
93
- prefix = clean_string(str(toolkit_name), cls.toolkit_max_length) + \
94
- TOOLKIT_SPLITTER if toolkit_name else ''
95
89
  available_tools = postman_api_wrapper.get_available_tools()
96
90
  tools = []
97
91
  for tool in available_tools:
98
92
  if selected_tools:
99
93
  if tool["name"] not in selected_tools:
100
94
  continue
95
+ description = f"{tool['description']}\nAPI URL: {postman_api_wrapper.base_url}"
96
+ if toolkit_name:
97
+ description = f"{description}\nToolkit: {toolkit_name}"
98
+ description = description[:1000]
101
99
  tools.append(PostmanAction(
102
100
  api_wrapper=postman_api_wrapper,
103
- name=prefix + tool["name"],
101
+ name=tool["name"],
104
102
  mode=tool["mode"],
105
- description=f"{tool['description']}\nAPI URL: {postman_api_wrapper.base_url}",
106
- args_schema=tool["args_schema"]
103
+ description=description,
104
+ args_schema=tool["args_schema"],
105
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
107
106
  ))
108
107
  return cls(tools=tools)
109
108
 
@@ -340,7 +340,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
340
340
  raise ToolException(
341
341
  f"Invalid JSON response from Postman API: {str(e)}")
342
342
 
343
- def _apply_authentication(self, headers, params, all_variables, resolve_variables):
343
+ def _apply_authentication(self, headers, params, all_variables, native_auth, resolve_variables):
344
344
  """Apply authentication based on environment_config auth settings.
345
345
 
346
346
  Supports multiple authentication types:
@@ -363,14 +363,15 @@ class PostmanApiWrapper(BaseToolApiWrapper):
363
363
  import base64
364
364
 
365
365
  # Handle structured auth configuration only - no backward compatibility
366
- auth_config = self.environment_config.get('auth')
366
+ auth_config = self.environment_config.get('auth', native_auth)
367
367
  if auth_config and isinstance(auth_config, dict):
368
368
  auth_type = auth_config.get('type', '').lower()
369
369
  auth_params = auth_config.get('params', {})
370
370
 
371
371
  if auth_type == 'bearer':
372
372
  # Bearer token authentication
373
- token = resolve_variables(str(auth_params.get('token', '')))
373
+ tokent_raw = auth_config.get('bearer', [{}])[0].get('value', '')
374
+ token = resolve_variables(str(tokent_raw))
374
375
  if token:
375
376
  headers['Authorization'] = f'Bearer {token}'
376
377
 
@@ -739,7 +740,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
739
740
  all_variables = {}
740
741
 
741
742
  # 1. Start with environment_config variables (lowest priority)
742
- all_variables.update(self.environment_config)
743
+ all_variables.update(self._get_variables_from_env_config())
743
744
 
744
745
  # 2. Add collection variables
745
746
  collection_variables = collection_data.get('variable', [])
@@ -760,8 +761,9 @@ class PostmanApiWrapper(BaseToolApiWrapper):
760
761
  import re
761
762
  def replace_var(match):
762
763
  var_name = match.group(1)
763
- return str(all_variables.get(var_name, match.group(0)))
764
-
764
+ value = all_variables.get(var_name, None)
765
+ return resolve_variables(str(value)) if value else match.group(0)
766
+
765
767
  return re.sub(r'\{\{([^}]+)\}\}', replace_var, text)
766
768
 
767
769
  # Prepare the request
@@ -791,7 +793,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
791
793
  headers = {}
792
794
 
793
795
  # Handle authentication from environment_config
794
- self._apply_authentication(headers, params, all_variables, resolve_variables)
796
+ self._apply_authentication(headers, params, all_variables, request_data.get('auth', None), resolve_variables)
795
797
 
796
798
  # Add headers from request
797
799
  request_headers = request_data.get('header', [])
@@ -1640,7 +1642,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
1640
1642
 
1641
1643
  # Find the request
1642
1644
  request_item = self.analyzer.find_request_by_path(
1643
- collection_data["item"], request_path)
1645
+ collection_data["item"], request_path, collection_data.get("auth", None))
1644
1646
  if not request_item:
1645
1647
  raise ToolException(f"Request '{request_path}' not found")
1646
1648
 
@@ -2161,3 +2163,12 @@ class PostmanApiWrapper(BaseToolApiWrapper):
2161
2163
  parse_items(items)
2162
2164
 
2163
2165
  return result
2166
+
2167
+ def _get_variables_from_env_config(self):
2168
+ """Extracts all enabled variables from the 'values' field in environment_config."""
2169
+ result = {}
2170
+ values = self.environment_config.get("values", [])
2171
+ for var in values:
2172
+ if var.get("enabled", True) and "key" in var and "value" in var:
2173
+ result[var["key"]] = var["value"]
2174
+ return result
@@ -1049,13 +1049,14 @@ class PostmanAnalyzer:
1049
1049
  find_in_items(items, path_parts)
1050
1050
  return results
1051
1051
 
1052
- def find_request_by_path(self, items: List[Dict], request_path: str) -> Optional[Dict]:
1052
+ def find_request_by_path(self, items: List[Dict], request_path: str, auth = None) -> Optional[Dict]:
1053
1053
  """Find a request by its path."""
1054
1054
  path_parts = [part.strip() for part in request_path.split('/') if part.strip()]
1055
1055
  if not path_parts:
1056
1056
  return None
1057
1057
 
1058
1058
  current_items = items
1059
+ current_auth = auth
1059
1060
 
1060
1061
  # Navigate through folders to the request
1061
1062
  for i, part in enumerate(path_parts):
@@ -1065,6 +1066,9 @@ class PostmanAnalyzer:
1065
1066
  if i == len(path_parts) - 1:
1066
1067
  # This should be the request
1067
1068
  if item.get('request'):
1069
+ # if request has no auth, inherit from parent
1070
+ if not item['request'].get('auth') and current_auth:
1071
+ item['request']['auth'] = current_auth
1068
1072
  return item
1069
1073
  else:
1070
1074
  return None
@@ -1072,6 +1076,9 @@ class PostmanAnalyzer:
1072
1076
  # This should be a folder
1073
1077
  if item.get('item'):
1074
1078
  current_items = item['item']
1079
+ # Update current_auth if folder has auth
1080
+ if item.get('auth'):
1081
+ current_auth = item['auth']
1075
1082
  found = True
1076
1083
  break
1077
1084
  else:
@@ -7,7 +7,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
7
7
  from .pptx_wrapper import PPTXWrapper
8
8
 
9
9
  from ..base.tool import BaseAction
10
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
10
+ from ..utils import clean_string, get_max_toolkit_length
11
11
 
12
12
  logger = logging.getLogger(__name__)
13
13
 
@@ -27,8 +27,6 @@ def get_tools(tool):
27
27
  ).get_tools()
28
28
 
29
29
 
30
- TOOLKIT_MAX_LENGTH = 25
31
-
32
30
  class PPTXToolkit(BaseToolkit):
33
31
  """
34
32
  PowerPoint (PPTX) manipulation toolkit for Alita.
@@ -45,8 +43,7 @@ class PPTXToolkit(BaseToolkit):
45
43
 
46
44
  return create_model(
47
45
  name,
48
- bucket_name=(str, Field(description="Bucket name where PPTX files are stored",
49
- json_schema_extra={'toolkit_name': True, 'max_toolkit_length': TOOLKIT_MAX_LENGTH})),
46
+ bucket_name=(str, Field(description="Bucket name where PPTX files are stored")),
50
47
  selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
51
48
  __config__=ConfigDict(json_schema_extra={
52
49
  'metadata': {
@@ -75,19 +72,22 @@ class PPTXToolkit(BaseToolkit):
75
72
  selected_tools = []
76
73
 
77
74
  pptx_api_wrapper = PPTXWrapper(**kwargs)
78
- prefix = clean_string(toolkit_name, TOOLKIT_MAX_LENGTH) + TOOLKIT_SPLITTER if toolkit_name else ''
79
75
  available_tools = pptx_api_wrapper.get_available_tools()
80
76
  tools = []
81
77
 
82
78
  for tool in available_tools:
83
79
  if selected_tools and tool["name"] not in selected_tools:
84
80
  continue
85
-
81
+ description = tool["description"]
82
+ if toolkit_name:
83
+ description = f"Toolkit: {toolkit_name}\n{description}"
84
+ description = description[:1000]
86
85
  tools.append(BaseAction(
87
86
  api_wrapper=pptx_api_wrapper,
88
- name=prefix + tool["name"],
89
- description=tool["description"],
90
- args_schema=tool["args_schema"]
87
+ name=tool["name"],
88
+ description=description,
89
+ args_schema=tool["args_schema"],
90
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
91
91
  ))
92
92
 
93
93
  return cls(tools=tools)
@@ -6,7 +6,8 @@ from pydantic import create_model, BaseModel, ConfigDict, Field, SecretStr
6
6
 
7
7
  from .api_wrapper import QtestApiWrapper
8
8
  from .tool import QtestAction
9
- from ..utils import clean_string, get_max_toolkit_length, TOOLKIT_SPLITTER, check_connection_response
9
+ from ..elitea_base import filter_missconfigured_index_tools
10
+ from ..utils import clean_string, get_max_toolkit_length, check_connection_response
10
11
  from ...configurations.qtest import QtestConfiguration
11
12
 
12
13
  name = "qtest"
@@ -15,29 +16,30 @@ name = "qtest"
15
16
  def get_tools(tool):
16
17
  toolkit = QtestToolkit.get_toolkit(
17
18
  selected_tools=tool['settings'].get('selected_tools', []),
18
- base_url=tool['settings'].get('base_url', None),
19
19
  qtest_project_id=tool['settings'].get('qtest_project_id', tool['settings'].get('project_id', None)),
20
+ no_of_tests_shown_in_dql_search=tool['settings'].get('no_of_tests_shown_in_dql_search'),
20
21
  qtest_configuration=tool['settings']['qtest_configuration'],
21
- toolkit_name=tool.get('toolkit_name')
22
+ toolkit_name=tool.get('toolkit_name'),
23
+ llm=tool['settings'].get('llm', None)
22
24
  )
23
25
  return toolkit.tools
24
26
 
25
27
 
26
28
  class QtestToolkit(BaseToolkit):
27
29
  tools: List[BaseTool] = []
28
- toolkit_max_length: int = 0
29
30
 
30
31
  @staticmethod
31
32
  def toolkit_config_schema() -> BaseModel:
32
33
  selected_tools = {x['name']: x['args_schema'].schema() for x in QtestApiWrapper.model_construct().get_available_tools()}
33
- QtestToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
34
34
  m = create_model(
35
35
  name,
36
- qtest_configuration=(Optional[QtestConfiguration], Field(description="QTest API token", json_schema_extra={
36
+ qtest_configuration=(QtestConfiguration, Field(description="QTest API token", json_schema_extra={
37
37
  'configuration_types': ['qtest']})),
38
- qtest_project_id=(int, Field(default=None, description="QTest project id", json_schema_extra={'toolkit_name': True,
39
- 'max_toolkit_length': QtestToolkit.toolkit_max_length})),
40
- selected_tools=(List[Literal[tuple(selected_tools)]],
38
+ qtest_project_id=(int, Field(description="QTest project id")),
39
+ no_of_tests_shown_in_dql_search=(Optional[int], Field(description="Max number of items returned by dql search",
40
+ default=10)),
41
+
42
+ selected_tools=(List[Literal[tuple(selected_tools)]],
41
43
  Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
42
44
  __config__=ConfigDict(json_schema_extra={'metadata': {"label": "QTest", "icon_url": "qtest.svg",
43
45
  "categories": ["test management"],
@@ -61,6 +63,7 @@ class QtestToolkit(BaseToolkit):
61
63
  return m
62
64
 
63
65
  @classmethod
66
+ @filter_missconfigured_index_tools
64
67
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
65
68
  if selected_tools is None:
66
69
  selected_tools = []
@@ -70,21 +73,25 @@ class QtestToolkit(BaseToolkit):
70
73
  **kwargs['qtest_configuration'],
71
74
  }
72
75
  qtest_api_wrapper = QtestApiWrapper(**wrapper_payload)
73
- prefix = clean_string(str(toolkit_name), cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
74
76
  available_tools = qtest_api_wrapper.get_available_tools()
75
77
  tools = []
76
78
  for tool in available_tools:
77
79
  if selected_tools:
78
80
  if tool["name"] not in selected_tools:
79
81
  continue
82
+ description = f"{tool['description']}\nUrl: {qtest_api_wrapper.base_url}. Project id: {qtest_api_wrapper.qtest_project_id}"
83
+ if toolkit_name:
84
+ description = f"{description}\nToolkit: {toolkit_name}"
85
+ description = description[:1000]
80
86
  tools.append(QtestAction(
81
87
  api_wrapper=qtest_api_wrapper,
82
- name=prefix + tool["name"],
88
+ name=tool["name"],
83
89
  mode=tool["mode"],
84
- description=f"{tool['description']}\nUrl: {qtest_api_wrapper.base_url}. Project id: {qtest_api_wrapper.qtest_project_id}",
85
- args_schema=tool["args_schema"]
90
+ description=description,
91
+ args_schema=tool["args_schema"],
92
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
86
93
  ))
87
94
  return cls(tools=tools)
88
95
 
89
96
  def get_tools(self):
90
- return self.tools
97
+ return self.tools