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
@@ -1,6 +1,11 @@
1
+ import base64
2
+ import logging
1
3
  import re
2
4
  from enum import Enum
5
+ from typing import Any
3
6
 
7
+ # DEPRECATED: Tool names no longer use prefixes
8
+ # Kept for backward compatibility only
4
9
  TOOLKIT_SPLITTER = "___"
5
10
 
6
11
  class IndexerKeywords(Enum):
@@ -30,3 +35,34 @@ def clean_node_str(s: str) -> str:
30
35
  """Cleans a node string by removing all non-alphanumeric characters except underscores and spaces."""
31
36
  cleaned_string = re.sub(r'[^\w\s]', '', s)
32
37
  return cleaned_string
38
+
39
+
40
+ def resolve_image_from_cache(client: Any, cached_image_id: str) -> bytes:
41
+ """
42
+ Resolve cached_image_id from client's image cache and return decoded binary data.
43
+
44
+ Args:
45
+ client: AlitaClient instance with _generated_images_cache attribute
46
+ cached_image_id: The cached image ID to resolve
47
+
48
+ Returns:
49
+ bytes: Decoded binary image data
50
+
51
+ Raises:
52
+ ValueError: If cached_image_id not found or decoding fails
53
+ """
54
+ cache = getattr(client, '_generated_images_cache', {})
55
+
56
+ if cached_image_id not in cache:
57
+ raise ValueError(f"Image reference '{cached_image_id}' not found. The image may have expired.")
58
+
59
+ cached_data = cache[cached_image_id]
60
+ base64_data = cached_data.get('base64_data', '')
61
+ logging.debug(f"Resolved cached_image_id '{cached_image_id}' from cache (length: {len(base64_data)} chars)")
62
+ # Decode base64 to binary data for image files
63
+ try:
64
+ binary_data = base64.b64decode(base64_data)
65
+ logging.debug(f"Decoded base64 to binary data ({len(binary_data)} bytes)")
66
+ return binary_data
67
+ except Exception as e:
68
+ raise ValueError(f"Failed to decode image data for '{cached_image_id}': {e}")
@@ -13,6 +13,30 @@ AVAILABLE_TOOLS = {}
13
13
  AVAILABLE_TOOLKITS = {}
14
14
  FAILED_IMPORTS = {}
15
15
 
16
+
17
+ def _inject_toolkit_id(tool_conf: dict, toolkit_tools) -> None:
18
+ """Inject `toolkit_id` into tools that expose `api_wrapper.toolkit_id`.
19
+
20
+ This reads 'id' from the tool configuration and, if it is an integer,
21
+ assigns it to the 'toolkit_id' attribute of the 'api_wrapper' for each
22
+ tool in 'toolkit_tools' that supports it.
23
+
24
+ Args:
25
+ tool_conf: Raw tool configuration item from 'tools_list'.
26
+ toolkit_tools: List of instantiated tools produced by a toolkit.
27
+ """
28
+ toolkit_id = tool_conf.get('id')
29
+ if isinstance(toolkit_id, int):
30
+ for t in toolkit_tools:
31
+ if hasattr(t, 'api_wrapper') and hasattr(t.api_wrapper, 'toolkit_id'):
32
+ t.api_wrapper.toolkit_id = toolkit_id
33
+ else:
34
+ logger.error(
35
+ f"Toolkit ID is missing or not an integer for tool "
36
+ f"`{tool_conf.get('type', '')}` with name `{tool_conf.get('name', '')}`"
37
+ )
38
+
39
+
16
40
  def _safe_import_tool(tool_name, module_path, get_tools_name=None, toolkit_class_name=None):
17
41
  """Safely import a tool module and register available functions/classes."""
18
42
  try:
@@ -21,6 +45,12 @@ def _safe_import_tool(tool_name, module_path, get_tools_name=None, toolkit_class
21
45
  imported = {}
22
46
  if get_tools_name and hasattr(module, get_tools_name):
23
47
  imported['get_tools'] = getattr(module, get_tools_name)
48
+
49
+ if hasattr(module, 'get_toolkit'):
50
+ imported['get_toolkit'] = getattr(module, 'get_toolkit')
51
+
52
+ if hasattr(module, 'get_toolkit_available_tools'):
53
+ imported['get_toolkit_available_tools'] = getattr(module, 'get_toolkit_available_tools')
24
54
 
25
55
  if toolkit_class_name and hasattr(module, toolkit_class_name):
26
56
  imported['toolkit_class'] = getattr(module, toolkit_class_name)
@@ -34,9 +64,10 @@ def _safe_import_tool(tool_name, module_path, get_tools_name=None, toolkit_class
34
64
  FAILED_IMPORTS[tool_name] = str(e)
35
65
  logger.debug(f"Failed to import {tool_name}: {e}")
36
66
 
67
+
37
68
  # Safe imports for all tools
38
69
  _safe_import_tool('github', 'github', 'get_tools', 'AlitaGitHubToolkit')
39
- _safe_import_tool('openapi', 'openapi', 'get_tools')
70
+ _safe_import_tool('openapi', 'openapi', 'get_tools', 'AlitaOpenAPIToolkit')
40
71
  _safe_import_tool('jira', 'jira', 'get_tools', 'JiraToolkit')
41
72
  _safe_import_tool('confluence', 'confluence', 'get_tools', 'ConfluenceToolkit')
42
73
  _safe_import_tool('service_now', 'servicenow', 'get_tools', 'ServiceNowToolkit')
@@ -71,7 +102,7 @@ _safe_import_tool('k8s', 'cloud.k8s', None, 'KubernetesToolkit')
71
102
  _safe_import_tool('elastic', 'elastic', None, 'ElasticToolkit')
72
103
  _safe_import_tool('keycloak', 'keycloak', None, 'KeycloakToolkit')
73
104
  _safe_import_tool('localgit', 'localgit', None, 'AlitaLocalGitToolkit')
74
- _safe_import_tool('pandas', 'pandas', 'get_tools', 'PandasToolkit')
105
+ # pandas toolkit removed - use Data Analysis internal tool instead
75
106
  _safe_import_tool('azure_search', 'azure_ai.search', 'get_tools', 'AzureSearchToolkit')
76
107
  _safe_import_tool('figma', 'figma', 'get_tools', 'FigmaToolkit')
77
108
  _safe_import_tool('salesforce', 'salesforce', 'get_tools', 'SalesforceToolkit')
@@ -90,11 +121,19 @@ available_count = len(AVAILABLE_TOOLS)
90
121
  total_attempted = len(AVAILABLE_TOOLS) + len(FAILED_IMPORTS)
91
122
  logger.info(f"Tool imports completed: {available_count}/{total_attempted} successful")
92
123
 
124
+ # Import community module to trigger community toolkit registration
125
+ try:
126
+ from alita_sdk import community # noqa: F401
127
+ logger.debug("Community toolkits registered successfully")
128
+ except ImportError as e:
129
+ logger.debug(f"Community module not available: {e}")
130
+
93
131
 
94
132
  def get_tools(tools_list, alita, llm, store: Optional[BaseStore] = None, *args, **kwargs):
95
133
  tools = []
96
134
 
97
135
  for tool in tools_list:
136
+ toolkit_tools = []
98
137
  settings = tool.get('settings')
99
138
 
100
139
  # Skip tools without settings early
@@ -116,53 +155,49 @@ def get_tools(tools_list, alita, llm, store: Optional[BaseStore] = None, *args,
116
155
 
117
156
  # Set pgvector collection schema if present
118
157
  if settings.get('pgvector_configuration'):
119
- settings['pgvector_configuration']['collection_schema'] = str(tool['id'])
158
+ # Use tool id if available, otherwise use toolkit_name or type as fallback
159
+ collection_id = tool.get('id') or tool.get('toolkit_name') or tool_type
160
+ settings['pgvector_configuration']['collection_schema'] = str(collection_id)
120
161
 
121
162
  # Handle ADO special cases
122
163
  if tool_type in ['ado_boards', 'ado_wiki', 'ado_plans']:
123
- tools.extend(AVAILABLE_TOOLS['ado']['get_tools'](tool_type, tool))
124
- continue
125
-
126
- # Handle ADO repos aliases
127
- if tool_type in ['ado_repos', 'azure_devops_repos'] and 'ado_repos' in AVAILABLE_TOOLS:
164
+ toolkit_tools.extend(AVAILABLE_TOOLS['ado']['get_tools'](tool_type, tool))
165
+ elif tool_type in ['ado_repos', 'azure_devops_repos'] and 'ado_repos' in AVAILABLE_TOOLS:
128
166
  try:
129
- tools.extend(AVAILABLE_TOOLS['ado_repos']['get_tools'](tool))
167
+ toolkit_tools.extend(AVAILABLE_TOOLS['ado_repos']['get_tools'](tool))
130
168
  except Exception as e:
131
169
  logger.error(f"Error getting ADO repos tools: {e}")
132
- continue
133
-
134
- # Skip MCP toolkit - it's handled by runtime/toolkits/tools.py to avoid duplicate loading
135
- if tool_type == 'mcp':
170
+ elif tool_type == 'mcp':
136
171
  logger.debug(f"Skipping MCP toolkit '{tool.get('toolkit_name')}' - handled by runtime toolkit system")
137
- continue
138
-
139
- # Handle standard tools
140
- if tool_type in AVAILABLE_TOOLS and 'get_tools' in AVAILABLE_TOOLS[tool_type]:
172
+ elif tool_type == 'planning':
173
+ logger.debug(f"Skipping planning toolkit '{tool.get('toolkit_name')}' - handled by runtime toolkit system")
174
+ elif tool_type in AVAILABLE_TOOLS and 'get_tools' in AVAILABLE_TOOLS[tool_type]:
141
175
  try:
142
- tools.extend(AVAILABLE_TOOLS[tool_type]['get_tools'](tool))
176
+ toolkit_tools.extend(AVAILABLE_TOOLS[tool_type]['get_tools'](tool))
143
177
  except Exception as e:
144
178
  logger.error(f"Error getting tools for {tool_type}: {e}")
145
179
  raise ToolException(f"Error getting tools for {tool_type}: {e}")
146
- continue
147
-
148
- # Handle custom modules
149
- if settings.get("module"):
180
+ elif settings.get("module"):
150
181
  try:
151
182
  mod = import_module(settings.pop("module"))
152
183
  tkitclass = getattr(mod, settings.pop("class"))
153
184
  get_toolkit_params = settings.copy()
154
185
  get_toolkit_params["name"] = tool.get("name")
155
186
  toolkit = tkitclass.get_toolkit(**get_toolkit_params)
156
- tools.extend(toolkit.get_tools())
187
+ toolkit_tools.extend(toolkit.get_tools())
157
188
  except Exception as e:
189
+ import traceback
158
190
  logger.error(f"Error in getting custom toolkit: {e}")
159
- continue
160
-
161
- # Tool not available
162
- if tool_type in FAILED_IMPORTS:
163
- logger.warning(f"Tool '{tool_type}' is not available: {FAILED_IMPORTS[tool_type]}")
191
+ logger.error(f"Traceback:\n{traceback.format_exc()}")
164
192
  else:
165
- logger.warning(f"Unknown tool type: {tool_type}")
193
+ if tool_type in FAILED_IMPORTS:
194
+ logger.warning(f"Tool '{tool_type}' is not available: {FAILED_IMPORTS[tool_type]}")
195
+ else:
196
+ logger.warning(f"Unknown tool type: {tool_type}")
197
+ #
198
+ # Always inject toolkit_id to each tool
199
+ _inject_toolkit_id(tool, toolkit_tools)
200
+ tools.extend(toolkit_tools)
166
201
 
167
202
  return tools
168
203
 
@@ -182,6 +217,18 @@ def get_toolkits():
182
217
  logger.info(f"Successfully loaded {len(toolkit_configs)} toolkit configurations")
183
218
  return toolkit_configs
184
219
 
220
+ def instantiate_toolkit(tool_config):
221
+ """Instantiate a toolkit from its configuration."""
222
+ tool_type = tool_config.get('type')
223
+
224
+ if tool_type in AVAILABLE_TOOLS:
225
+ tool_module = AVAILABLE_TOOLS[tool_type]
226
+
227
+ if 'get_toolkit' in tool_module:
228
+ return tool_module['get_toolkit'](tool_config)
229
+
230
+ raise ValueError(f"Toolkit type '{tool_type}' does not support direct instantiation or is not available.")
231
+
185
232
  def get_available_tools():
186
233
  """Return list of available tool types."""
187
234
  return list(AVAILABLE_TOOLS.keys())
@@ -198,6 +245,42 @@ def get_available_toolkit_models():
198
245
  """Return dict with available toolkit classes."""
199
246
  return deepcopy(AVAILABLE_TOOLS)
200
247
 
248
+
249
+ def get_toolkit_available_tools(toolkit_type: str, settings: dict) -> dict:
250
+ """Return dynamic available tools + per-tool JSON schemas for a toolkit instance.
251
+
252
+ This is the single SDK entrypoint used by backend services (e.g. indexer_worker)
253
+ when the UI needs spec/instance-dependent tool enumeration. Toolkits that don't
254
+ support dynamic enumeration should return an empty payload.
255
+
256
+ Args:
257
+ toolkit_type: toolkit type string (e.g. 'openapi')
258
+ settings: persisted toolkit settings
259
+
260
+ Returns:
261
+ {
262
+ "tools": [{"name": str, "description": str}],
263
+ "args_schemas": {"tool_name": <json schema dict>}
264
+ }
265
+ """
266
+ toolkit_type = (toolkit_type or '').strip().lower()
267
+ if not isinstance(settings, dict):
268
+ settings = {}
269
+
270
+ tool_module = AVAILABLE_TOOLS.get(toolkit_type) or {}
271
+ enumerator = tool_module.get('get_toolkit_available_tools')
272
+ if not callable(enumerator):
273
+ return {"tools": [], "args_schemas": {}}
274
+
275
+ try:
276
+ result = enumerator(settings)
277
+ if not isinstance(result, dict):
278
+ return {"tools": [], "args_schemas": {}, "error": "Invalid response from toolkit enumerator"}
279
+ return result
280
+ except Exception as e: # pylint: disable=W0718
281
+ logger.exception("Failed to compute available tools for toolkit_type=%s", toolkit_type)
282
+ return {"tools": [], "args_schemas": {}, "error": str(e)}
283
+
201
284
  def diagnose_imports():
202
285
  """Print diagnostic information about tool imports."""
203
286
  available_count = len(AVAILABLE_TOOLS)
@@ -234,6 +317,7 @@ def diagnose_imports():
234
317
  __all__ = [
235
318
  'get_tools',
236
319
  'get_toolkits',
320
+ 'get_toolkit_available_tools',
237
321
  'get_available_tools',
238
322
  'get_failed_imports',
239
323
  'get_available_toolkits',
@@ -6,23 +6,25 @@ from pydantic import BaseModel, Field, create_model
6
6
  import requests
7
7
 
8
8
  from ...elitea_base import filter_missconfigured_index_tools
9
- from ....configurations.ado import AdoReposConfiguration
9
+ from ....configurations.ado import AdoConfiguration
10
10
  from ....configurations.pgvector import PgVectorConfiguration
11
11
  from ...base.tool import BaseAction
12
12
  from .repos_wrapper import ReposApiWrapper
13
- from ...utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length, check_connection_response
13
+ from ...utils import check_connection_response
14
+ from ....runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
14
15
 
15
16
  name = "ado_repos"
16
17
 
17
18
 
18
- def _get_toolkit(tool) -> BaseToolkit:
19
+ def get_toolkit(tool) -> BaseToolkit:
19
20
  return AzureDevOpsReposToolkit().get_toolkit(
20
21
  selected_tools=tool['settings'].get('selected_tools', []),
21
- ado_repos_configuration=tool['settings']['ado_repos_configuration'],
22
+ ado_configuration=tool['settings']['ado_configuration'],
23
+ repository_id=tool['settings']['repository_id'],
22
24
  limit=tool['settings'].get('limit', 5),
23
- base_branch=tool['settings'].get('base_branch', ""),
24
- active_branch=tool['settings'].get('active_branch', ""),
25
- toolkit_name=tool['settings'].get('toolkit_name', ""),
25
+ base_branch=tool['settings'].get('base_branch', "main"),
26
+ active_branch=tool['settings'].get('active_branch', "main"),
27
+ toolkit_name=tool.get('toolkit_name', ''),
26
28
  pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
27
29
  embedding_model=tool['settings'].get('embedding_model'),
28
30
  collection_name=tool['toolkit_name'],
@@ -30,26 +32,22 @@ def _get_toolkit(tool) -> BaseToolkit:
30
32
  llm=tool['settings'].get('llm', None),
31
33
  )
32
34
 
33
- def get_toolkit():
34
- return AzureDevOpsReposToolkit.toolkit_config_schema()
35
-
36
35
  def get_tools(tool):
37
- return _get_toolkit(tool).get_tools()
36
+ return get_toolkit(tool).get_tools()
38
37
 
39
38
  class AzureDevOpsReposToolkit(BaseToolkit):
40
39
  tools: List[BaseTool] = []
41
- toolkit_max_length: int = 0
42
40
 
43
41
  @staticmethod
44
42
  def toolkit_config_schema() -> BaseModel:
45
43
  selected_tools = {x['name']: x['args_schema'].schema() for x in ReposApiWrapper.model_construct().get_available_tools()}
46
- AzureDevOpsReposToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
47
44
  m = create_model(
48
45
  name,
49
- ado_repos_configuration=(AdoReposConfiguration, Field(description="Ado Repos configuration", default=None,
50
- json_schema_extra={'configuration_types': ['ado_repos']})),
51
- base_branch=(Optional[str], Field(default="", title="Base branch", description="ADO base branch (e.g., main)")),
52
- active_branch=(Optional[str], Field(default="", title="Active branch", description="ADO active branch (e.g., main)")),
46
+ ado_configuration=(AdoConfiguration, Field(description="ADO configuration", default=None,
47
+ json_schema_extra={'configuration_types': ['ado']})),
48
+ repository_id=(str, Field(description="ADO repository ID or name")),
49
+ base_branch=(Optional[str], Field(default="main", title="Base branch", description="ADO base branch (e.g., main)")),
50
+ active_branch=(Optional[str], Field(default="main", title="Active branch", description="ADO active branch (e.g., main)")),
53
51
 
54
52
  # indexer settings
55
53
  pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None, description="PgVector Configuration", json_schema_extra={'configuration_types': ['pgvector']})),
@@ -57,21 +55,38 @@ class AzureDevOpsReposToolkit(BaseToolkit):
57
55
  embedding_model=(Optional[str], Field(default=None, description="Embedding configuration.", json_schema_extra={'configuration_model': 'embedding'})),
58
56
 
59
57
  selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
60
- __config__={'json_schema_extra': {'metadata':
61
- {
62
- "label": "ADO repos",
63
- "icon_url": "ado-repos-icon.svg",
64
- "categories": ["code repositories"],
65
- "extra_categories": ["code", "repository", "version control"],
66
- "max_length": AzureDevOpsReposToolkit.toolkit_max_length
67
- }}}
58
+ __config__={
59
+ 'json_schema_extra': {
60
+ 'metadata': {
61
+ "label": "ADO repos",
62
+ "icon_url": "ado-repos-icon.svg",
63
+ "categories": ["code repositories"],
64
+ "extra_categories": ["code", "repository", "version control"],
65
+ "sections": {
66
+ "auth": {
67
+ "required": True,
68
+ "subsections": [
69
+ {
70
+ "name": "Token",
71
+ "fields": ["token"]
72
+ }
73
+ ]
74
+ }
75
+ },
76
+ "configuration_group": {
77
+ "name": "ado",
78
+ }
79
+ }
80
+ }
81
+ }
68
82
  )
69
83
 
70
84
  @check_connection_response
71
85
  def check_connection(self):
86
+ ado_config = self.ado_configuration
72
87
  response = requests.get(
73
- f'{self.organization_url}/{self.project}/_apis/git/repositories/{self.repository_id}?api-version=7.0',
74
- headers = {'Authorization': f'Bearer {self.token}'},
88
+ f'{ado_config.organization_url}/{ado_config.project}/_apis/git/repositories/{self.repository_id}?api-version=7.0',
89
+ headers = {'Authorization': f'Bearer {ado_config.token.get_secret_value() if ado_config.token else ""}'},
75
90
  timeout=5
76
91
  )
77
92
  return response
@@ -91,25 +106,28 @@ class AzureDevOpsReposToolkit(BaseToolkit):
91
106
 
92
107
  wrapper_payload = {
93
108
  **kwargs,
94
- # TODO use ado_repos_configuration fields
95
- **kwargs['ado_repos_configuration'],
96
- **kwargs['ado_repos_configuration']['ado_configuration'],
109
+ # Extract ADO configuration fields
110
+ **kwargs['ado_configuration'],
97
111
  **(kwargs.get('pgvector_configuration') or {}),
98
112
  }
99
113
  azure_devops_repos_wrapper = ReposApiWrapper(**wrapper_payload)
100
114
  available_tools = azure_devops_repos_wrapper.get_available_tools()
101
115
  tools = []
102
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
103
116
  for tool in available_tools:
104
117
  if selected_tools:
105
118
  if tool["name"] not in selected_tools:
106
119
  continue
120
+ description = tool["description"] + f"\nADO instance: {azure_devops_repos_wrapper.organization_url}/{azure_devops_repos_wrapper.project}"
121
+ if toolkit_name:
122
+ description = f"{description}\nToolkit: {toolkit_name}"
123
+ description = description[:1000]
107
124
  tools.append(
108
125
  BaseAction(
109
126
  api_wrapper=azure_devops_repos_wrapper,
110
- name=prefix + tool["name"],
111
- description=tool["description"] + f"\nADO instance: {azure_devops_repos_wrapper.organization_url}/{azure_devops_repos_wrapper.project}",
127
+ name=tool["name"],
128
+ description=description,
112
129
  args_schema=tool["args_schema"],
130
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
113
131
  )
114
132
  )
115
133
  return cls(tools=tools)