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
@@ -12,7 +12,9 @@ logger = logging.getLogger(__name__)
12
12
 
13
13
  def instantiate_toolkit_with_client(toolkit_config: Dict[str, Any],
14
14
  llm_client: Any,
15
- alita_client: Optional[Any] = None) -> List[Any]:
15
+ alita_client: Optional[Any] = None,
16
+ mcp_tokens: Optional[Dict[str, Any]] = None,
17
+ use_prefix: bool = False) -> List[Any]:
16
18
  """
17
19
  Instantiate a toolkit with LLM client support.
18
20
 
@@ -22,20 +24,25 @@ def instantiate_toolkit_with_client(toolkit_config: Dict[str, Any],
22
24
  Args:
23
25
  toolkit_config: Configuration dictionary for the toolkit
24
26
  llm_client: LLM client instance for tools that need LLM capabilities
25
- client: Optional additional client instance
27
+ alita_client: Optional additional client instance
28
+ mcp_tokens: Optional dictionary of MCP OAuth tokens by server URL
29
+ use_prefix: If True, tools get prefixed with toolkit_name to prevent collisions
30
+ (for agent use). If False, tools use base names only (for testing interface).
31
+ Default False for backward compatibility with testing.
26
32
 
27
33
  Returns:
28
34
  List of instantiated tools from the toolkit
29
35
 
30
36
  Raises:
31
37
  ValueError: If required configuration or client is missing
38
+ McpAuthorizationRequired: If MCP server requires OAuth authorization
32
39
  Exception: If toolkit instantiation fails
33
40
  """
41
+ toolkit_name = toolkit_config.get('toolkit_name', 'unknown')
34
42
  try:
35
43
  from ..toolkits.tools import get_tools
36
44
 
37
- toolkit_name = toolkit_config.get('toolkit_name')
38
- if not toolkit_name:
45
+ if not toolkit_name or toolkit_name == 'unknown':
39
46
  raise ValueError("toolkit_name is required in configuration")
40
47
 
41
48
  if not llm_client:
@@ -46,18 +53,22 @@ def instantiate_toolkit_with_client(toolkit_config: Dict[str, Any],
46
53
  # Log the configuration being used
47
54
  logger.info(f"Instantiating toolkit {toolkit_name} with LLM client")
48
55
  logger.debug(f"Toolkit {toolkit_name} configuration: {toolkit_config}")
49
-
56
+
57
+ # Use toolkit type from config, or fall back to lowercase toolkit name
58
+ toolkit_type = toolkit_config.get('type', toolkit_name.lower())
59
+
50
60
  # Create a tool configuration dict with required fields
61
+ # Note: MCP toolkit always requires toolkit_name, other toolkits respect use_prefix flag
51
62
  tool_config = {
52
63
  'id': toolkit_config.get('id', random.randint(1, 1000000)),
53
- 'type': toolkit_config.get('type', toolkit_name.lower()),
64
+ 'type': toolkit_config.get('type', toolkit_type),
54
65
  'settings': settings,
55
- 'toolkit_name': toolkit_name
66
+ 'toolkit_name': toolkit_name if (use_prefix or toolkit_type == 'mcp') else None
56
67
  }
57
68
 
58
69
  # Get tools using the toolkit configuration with clients
59
- # Parameter order: get_tools(tools_list, alita_client, llm, memory_store)
60
- tools = get_tools([tool_config], alita_client, llm_client)
70
+ # Parameter order: get_tools(tools_list, alita_client, llm, memory_store, debug_mode, mcp_tokens)
71
+ tools = get_tools([tool_config], alita_client, llm_client, mcp_tokens=mcp_tokens)
61
72
 
62
73
  if not tools:
63
74
  logger.warning(f"No tools returned for toolkit {toolkit_name}")
@@ -67,6 +78,14 @@ def instantiate_toolkit_with_client(toolkit_config: Dict[str, Any],
67
78
  return tools
68
79
 
69
80
  except Exception as e:
81
+ # Re-raise McpAuthorizationRequired without logging as error
82
+ from ..utils.mcp_oauth import McpAuthorizationRequired
83
+
84
+ if isinstance(e, McpAuthorizationRequired):
85
+ logger.info(f"Toolkit {toolkit_name} requires MCP OAuth authorization")
86
+ raise
87
+
88
+ # Log and re-raise other errors
70
89
  logger.error(f"Error instantiating toolkit {toolkit_name} with client: {str(e)}")
71
90
  raise
72
91
 
@@ -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):
@@ -9,6 +14,12 @@ class IndexerKeywords(Enum):
9
14
  PARENT = 'parent_id'
10
15
  # DEPENDENCY_ID = 'dependency_id'
11
16
  UPDATED_ON = 'updated_on'
17
+ CONTENT_IN_BYTES = 'loader_content'
18
+ CONTENT_FILE_NAME = 'loader_content_type'
19
+ INDEX_META_TYPE = 'index_meta'
20
+ INDEX_META_IN_PROGRESS = 'in_progress'
21
+ INDEX_META_COMPLETED = 'completed'
22
+ INDEX_META_FAILED = 'failed'
12
23
 
13
24
  # This pattern matches characters that are NOT alphanumeric, underscores, or hyphens
14
25
  clean_string_pattern = re.compile(r'[^a-zA-Z0-9_.-]')
@@ -18,3 +29,40 @@ def clean_string(s: str) -> str:
18
29
  # Replace these characters with an empty string
19
30
  cleaned_string = re.sub(clean_string_pattern, '', s)
20
31
  return cleaned_string
32
+
33
+
34
+ def clean_node_str(s: str) -> str:
35
+ """Cleans a node string by removing all non-alphanumeric characters except underscores and spaces."""
36
+ cleaned_string = re.sub(r'[^\w\s]', '', s)
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')
@@ -67,11 +98,11 @@ _safe_import_tool('aws', 'cloud.aws', None, 'AWSToolkit')
67
98
  _safe_import_tool('azure', 'cloud.azure', None, 'AzureToolkit')
68
99
  _safe_import_tool('gcp', 'cloud.gcp', None, 'GCPToolkit')
69
100
  _safe_import_tool('k8s', 'cloud.k8s', None, 'KubernetesToolkit')
70
- _safe_import_tool('custom_open_api', 'custom_open_api', None, 'OpenApiToolkit')
101
+ # _safe_import_tool('custom_open_api', 'custom_open_api', None, 'OpenApiToolkit')
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')
@@ -79,7 +110,6 @@ _safe_import_tool('carrier', 'carrier', 'get_tools', 'AlitaCarrierToolkit')
79
110
  _safe_import_tool('ocr', 'ocr', 'get_tools', 'OCRToolkit')
80
111
  _safe_import_tool('pptx', 'pptx', 'get_tools', 'PPTXToolkit')
81
112
  _safe_import_tool('postman', 'postman', 'get_tools', 'PostmanToolkit')
82
- _safe_import_tool('memory', 'memory', 'get_tools', 'MemoryToolkit')
83
113
  _safe_import_tool('zephyr_squad', 'zephyr_squad', 'get_tools', 'ZephyrSquadToolkit')
84
114
  _safe_import_tool('zephyr_essential', 'zephyr_essential', 'get_tools', 'ZephyrEssentialToolkit')
85
115
  _safe_import_tool('slack', 'slack', 'get_tools', 'SlackToolkit')
@@ -91,62 +121,81 @@ available_count = len(AVAILABLE_TOOLS)
91
121
  total_attempted = len(AVAILABLE_TOOLS) + len(FAILED_IMPORTS)
92
122
  logger.info(f"Tool imports completed: {available_count}/{total_attempted} successful")
93
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
+
131
+
94
132
  def get_tools(tools_list, alita, llm, store: Optional[BaseStore] = None, *args, **kwargs):
95
133
  tools = []
134
+
96
135
  for tool in tools_list:
97
- # validate tool name syntax - it cannot be started with _
98
- for tool_name in tool.get('settings', {}).get('selected_tools', []):
99
- if isinstance(tool_name, str) and tool_name.startswith('_'):
100
- raise ValueError(f"Tool name '{tool_name}' from toolkit '{tool.get('type', '')}' cannot start with '_'")
101
-
102
- tool['settings']['alita'] = alita
103
- tool['settings']['llm'] = llm
104
- tool['settings']['store'] = store
105
- tool_type = tool['type']
136
+ toolkit_tools = []
137
+ settings = tool.get('settings')
106
138
 
107
- # Handle special cases for ADO tools
108
- if tool_type in ['ado_boards', 'ado_wiki', 'ado_plans']:
109
- tools.extend(AVAILABLE_TOOLS['ado']['get_tools'](tool_type, tool))
139
+ # Skip tools without settings early
140
+ if not settings:
141
+ logger.warning(f"Tool '{tool.get('type', '')}' has no settings, skipping...")
142
+ continue
110
143
 
111
- # Check if tool is available and has get_tools function
112
- elif tool_type in AVAILABLE_TOOLS and 'get_tools' in AVAILABLE_TOOLS[tool_type]:
113
- try:
114
- get_tools_func = AVAILABLE_TOOLS[tool_type]['get_tools']
115
- tools.extend(get_tools_func(tool))
144
+ # Validate tool names once
145
+ selected_tools = settings.get('selected_tools', [])
146
+ invalid_tools = [name for name in selected_tools if isinstance(name, str) and name.startswith('_')]
147
+ if invalid_tools:
148
+ raise ValueError(f"Tool names {invalid_tools} from toolkit '{tool.get('type', '')}' cannot start with '_'")
116
149
 
117
- except Exception as e:
118
- logger.error(f"Error getting tools for {tool_type}: {e}")
119
- raise ToolException(f"Error getting tools for {tool_type}: {e}")
150
+ # Cache tool type and add common settings
151
+ tool_type = tool['type']
152
+ settings['alita'] = alita
153
+ settings['llm'] = llm
154
+ settings['store'] = store
155
+
156
+ # Set pgvector collection schema if present
157
+ if settings.get('pgvector_configuration'):
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
- # Handle ADO repos special case (it might be requested as azure_devops_repos)
162
+ # Handle ADO special cases
163
+ if tool_type in ['ado_boards', 'ado_wiki', 'ado_plans']:
164
+ toolkit_tools.extend(AVAILABLE_TOOLS['ado']['get_tools'](tool_type, tool))
122
165
  elif tool_type in ['ado_repos', 'azure_devops_repos'] and 'ado_repos' in AVAILABLE_TOOLS:
123
166
  try:
124
- get_tools_func = AVAILABLE_TOOLS['ado_repos']['get_tools']
125
- tools.extend(get_tools_func(tool))
167
+ toolkit_tools.extend(AVAILABLE_TOOLS['ado_repos']['get_tools'](tool))
126
168
  except Exception as e:
127
169
  logger.error(f"Error getting ADO repos tools: {e}")
128
-
129
- # Handle custom modules
130
- elif tool.get("settings", {}).get("module"):
170
+ elif tool_type == 'mcp':
171
+ logger.debug(f"Skipping MCP toolkit '{tool.get('toolkit_name')}' - handled by runtime toolkit system")
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]:
175
+ try:
176
+ toolkit_tools.extend(AVAILABLE_TOOLS[tool_type]['get_tools'](tool))
177
+ except Exception as e:
178
+ logger.error(f"Error getting tools for {tool_type}: {e}")
179
+ raise ToolException(f"Error getting tools for {tool_type}: {e}")
180
+ elif settings.get("module"):
131
181
  try:
132
- settings = tool.get("settings", {})
133
182
  mod = import_module(settings.pop("module"))
134
183
  tkitclass = getattr(mod, settings.pop("class"))
135
- #
136
- get_toolkit_params = tool["settings"].copy()
184
+ get_toolkit_params = settings.copy()
137
185
  get_toolkit_params["name"] = tool.get("name")
138
- #
139
186
  toolkit = tkitclass.get_toolkit(**get_toolkit_params)
140
- tools.extend(toolkit.get_tools())
187
+ toolkit_tools.extend(toolkit.get_tools())
141
188
  except Exception as e:
142
189
  logger.error(f"Error in getting custom toolkit: {e}")
143
-
144
190
  else:
145
- # Tool not available or not found
146
191
  if tool_type in FAILED_IMPORTS:
147
192
  logger.warning(f"Tool '{tool_type}' is not available: {FAILED_IMPORTS[tool_type]}")
148
193
  else:
149
194
  logger.warning(f"Unknown tool type: {tool_type}")
195
+ #
196
+ # Always inject toolkit_id to each tool
197
+ _inject_toolkit_id(tool, toolkit_tools)
198
+ tools.extend(toolkit_tools)
150
199
 
151
200
  return tools
152
201
 
@@ -166,6 +215,18 @@ def get_toolkits():
166
215
  logger.info(f"Successfully loaded {len(toolkit_configs)} toolkit configurations")
167
216
  return toolkit_configs
168
217
 
218
+ def instantiate_toolkit(tool_config):
219
+ """Instantiate a toolkit from its configuration."""
220
+ tool_type = tool_config.get('type')
221
+
222
+ if tool_type in AVAILABLE_TOOLS:
223
+ tool_module = AVAILABLE_TOOLS[tool_type]
224
+
225
+ if 'get_toolkit' in tool_module:
226
+ return tool_module['get_toolkit'](tool_config)
227
+
228
+ raise ValueError(f"Toolkit type '{tool_type}' does not support direct instantiation or is not available.")
229
+
169
230
  def get_available_tools():
170
231
  """Return list of available tool types."""
171
232
  return list(AVAILABLE_TOOLS.keys())
@@ -182,6 +243,42 @@ def get_available_toolkit_models():
182
243
  """Return dict with available toolkit classes."""
183
244
  return deepcopy(AVAILABLE_TOOLS)
184
245
 
246
+
247
+ def get_toolkit_available_tools(toolkit_type: str, settings: dict) -> dict:
248
+ """Return dynamic available tools + per-tool JSON schemas for a toolkit instance.
249
+
250
+ This is the single SDK entrypoint used by backend services (e.g. indexer_worker)
251
+ when the UI needs spec/instance-dependent tool enumeration. Toolkits that don't
252
+ support dynamic enumeration should return an empty payload.
253
+
254
+ Args:
255
+ toolkit_type: toolkit type string (e.g. 'openapi')
256
+ settings: persisted toolkit settings
257
+
258
+ Returns:
259
+ {
260
+ "tools": [{"name": str, "description": str}],
261
+ "args_schemas": {"tool_name": <json schema dict>}
262
+ }
263
+ """
264
+ toolkit_type = (toolkit_type or '').strip().lower()
265
+ if not isinstance(settings, dict):
266
+ settings = {}
267
+
268
+ tool_module = AVAILABLE_TOOLS.get(toolkit_type) or {}
269
+ enumerator = tool_module.get('get_toolkit_available_tools')
270
+ if not callable(enumerator):
271
+ return {"tools": [], "args_schemas": {}}
272
+
273
+ try:
274
+ result = enumerator(settings)
275
+ if not isinstance(result, dict):
276
+ return {"tools": [], "args_schemas": {}, "error": "Invalid response from toolkit enumerator"}
277
+ return result
278
+ except Exception as e: # pylint: disable=W0718
279
+ logger.exception("Failed to compute available tools for toolkit_type=%s", toolkit_type)
280
+ return {"tools": [], "args_schemas": {}, "error": str(e)}
281
+
185
282
  def diagnose_imports():
186
283
  """Print diagnostic information about tool imports."""
187
284
  available_count = len(AVAILABLE_TOOLS)
@@ -218,6 +315,7 @@ def diagnose_imports():
218
315
  __all__ = [
219
316
  'get_tools',
220
317
  'get_toolkits',
318
+ 'get_toolkit_available_tools',
221
319
  'get_available_tools',
222
320
  'get_failed_imports',
223
321
  'get_available_toolkits',
@@ -9,16 +9,16 @@ def get_tools(tool_type, tool):
9
9
  config_dict = {
10
10
  # common
11
11
  "selected_tools": tool['settings'].get('selected_tools', []),
12
- "organization_url": tool['settings']['organization_url'],
13
12
  "ado_configuration": tool['settings']['ado_configuration'],
14
13
  "limit": tool['settings'].get('limit', 5),
15
14
  "toolkit_name": tool.get('toolkit_name', ''),
16
15
  # indexer settings
16
+ "alita": tool['settings'].get('alita', None),
17
17
  "llm": tool['settings'].get('llm', None),
18
18
  "pgvector_configuration": tool['settings'].get('pgvector_configuration', {}),
19
19
  "collection_name": tool['toolkit_name'],
20
20
  "doctype": 'doc',
21
- "embedding_model": tool['settings'].get('embedding_configuration', {}).get('name', None),
21
+ "embedding_model": tool['settings'].get('embedding_model'),
22
22
  "vectorstore_type": "PGVector"
23
23
  }
24
24
  if tool_type == 'ado_plans':
@@ -5,16 +5,17 @@ from pydantic import BaseModel, Field, create_model
5
5
 
6
6
  import requests
7
7
 
8
+ from ...elitea_base import filter_missconfigured_index_tools
8
9
  from ....configurations.ado import AdoReposConfiguration
9
10
  from ....configurations.pgvector import PgVectorConfiguration
10
11
  from ...base.tool import BaseAction
11
12
  from .repos_wrapper import ReposApiWrapper
12
- from ...utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length, check_connection_response
13
+ from ...utils import clean_string, get_max_toolkit_length, check_connection_response
13
14
 
14
15
  name = "ado_repos"
15
16
 
16
17
 
17
- def _get_toolkit(tool) -> BaseToolkit:
18
+ def get_toolkit(tool) -> BaseToolkit:
18
19
  return AzureDevOpsReposToolkit().get_toolkit(
19
20
  selected_tools=tool['settings'].get('selected_tools', []),
20
21
  ado_repos_configuration=tool['settings']['ado_repos_configuration'],
@@ -23,26 +24,21 @@ def _get_toolkit(tool) -> BaseToolkit:
23
24
  active_branch=tool['settings'].get('active_branch', ""),
24
25
  toolkit_name=tool['settings'].get('toolkit_name', ""),
25
26
  pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
26
- collection_name=tool['toolkit_name'],
27
- doctype='code',
28
27
  embedding_model=tool['settings'].get('embedding_model'),
29
- vectorstore_type="PGVector",
28
+ collection_name=tool['toolkit_name'],
29
+ alita=tool['settings'].get('alita', None),
30
+ llm=tool['settings'].get('llm', None),
30
31
  )
31
32
 
32
- def get_toolkit():
33
- return AzureDevOpsReposToolkit.toolkit_config_schema()
34
-
35
33
  def get_tools(tool):
36
- return _get_toolkit(tool).get_tools()
34
+ return get_toolkit(tool).get_tools()
37
35
 
38
36
  class AzureDevOpsReposToolkit(BaseToolkit):
39
37
  tools: List[BaseTool] = []
40
- toolkit_max_length: int = 0
41
38
 
42
39
  @staticmethod
43
40
  def toolkit_config_schema() -> BaseModel:
44
41
  selected_tools = {x['name']: x['args_schema'].schema() for x in ReposApiWrapper.model_construct().get_available_tools()}
45
- AzureDevOpsReposToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
46
42
  m = create_model(
47
43
  name,
48
44
  ado_repos_configuration=(AdoReposConfiguration, Field(description="Ado Repos configuration", default=None,
@@ -62,11 +58,6 @@ class AzureDevOpsReposToolkit(BaseToolkit):
62
58
  "icon_url": "ado-repos-icon.svg",
63
59
  "categories": ["code repositories"],
64
60
  "extra_categories": ["code", "repository", "version control"],
65
- # "configuration_group": {
66
- # "name": "ado_repos",
67
- # "label": "Azure DevOps Repositories",
68
- # "icon_url": "ado-repos-icon.svg",
69
- # }
70
61
  }}}
71
62
  )
72
63
 
@@ -83,6 +74,7 @@ class AzureDevOpsReposToolkit(BaseToolkit):
83
74
  return m
84
75
 
85
76
  @classmethod
77
+ @filter_missconfigured_index_tools
86
78
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
87
79
  from os import environ
88
80
 
@@ -101,17 +93,21 @@ class AzureDevOpsReposToolkit(BaseToolkit):
101
93
  azure_devops_repos_wrapper = ReposApiWrapper(**wrapper_payload)
102
94
  available_tools = azure_devops_repos_wrapper.get_available_tools()
103
95
  tools = []
104
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
105
96
  for tool in available_tools:
106
97
  if selected_tools:
107
98
  if tool["name"] not in selected_tools:
108
99
  continue
100
+ description = tool["description"] + f"\nADO instance: {azure_devops_repos_wrapper.organization_url}/{azure_devops_repos_wrapper.project}"
101
+ if toolkit_name:
102
+ description = f"{description}\nToolkit: {toolkit_name}"
103
+ description = description[:1000]
109
104
  tools.append(
110
105
  BaseAction(
111
106
  api_wrapper=azure_devops_repos_wrapper,
112
- name=prefix + tool["name"],
113
- description=tool["description"] + f"\nADO instance: {azure_devops_repos_wrapper.organization_url}/{azure_devops_repos_wrapper.project}",
107
+ name=tool["name"],
108
+ description=description,
114
109
  args_schema=tool["args_schema"],
110
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
115
111
  )
116
112
  )
117
113
  return cls(tools=tools)
@@ -24,7 +24,8 @@ from msrest.authentication import BasicAuthentication
24
24
  from pydantic import Field, PrivateAttr, create_model, model_validator, SecretStr
25
25
 
26
26
  from ..utils import extract_old_new_pairs, generate_diff, get_content_from_generator
27
- from ...elitea_base import BaseCodeToolApiWrapper
27
+ from ...code_indexer_toolkit import CodeIndexerToolkit
28
+ from ...utils.available_tools_decorator import extend_with_parent_available_tools
28
29
 
29
30
  logger = logging.getLogger(__name__)
30
31
 
@@ -110,8 +111,7 @@ class ArgsSchema(Enum):
110
111
  Field(
111
112
  description=(
112
113
  "Branch to be used for read file operation."
113
- ),
114
- default=None
114
+ )
115
115
  ),
116
116
  )
117
117
  )
@@ -159,6 +159,7 @@ class ArgsSchema(Enum):
159
159
  Field(
160
160
  description="""List of comments, where each comment is a dictionary specifying details about the comment,
161
161
  e.g. [{'file_path': 'src/main.py', 'comment_text': 'Logic needs improvement', 'right_line': 20}]""",
162
+ default=None,
162
163
  examples=[
163
164
  {
164
165
  "file_path": "src/main.py",
@@ -241,7 +242,7 @@ class ArgsSchema(Enum):
241
242
  )
242
243
 
243
244
 
244
- class ReposApiWrapper(BaseCodeToolApiWrapper):
245
+ class ReposApiWrapper(CodeIndexerToolkit):
245
246
  # TODO use ado_repos_configuration fields
246
247
  organization_url: Optional[str]
247
248
  project: Optional[str]
@@ -251,15 +252,6 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
251
252
  token: Optional[SecretStr]
252
253
  _client: Optional[GitClient] = PrivateAttr()
253
254
 
254
- llm: Optional[Any] = None
255
- # Vector store configuration
256
- connection_string: Optional[SecretStr] = None
257
- collection_name: Optional[str] = None
258
- doctype: Optional[str] = 'code'
259
- embedding_model: Optional[str] = "HuggingFaceEmbeddings"
260
- embedding_model_params: Optional[dict] = {"model_name": "sentence-transformers/all-MiniLM-L6-v2"}
261
- vectorstore_type: Optional[str] = "PGVector"
262
-
263
255
  class Config:
264
256
  arbitrary_types_allowed = True
265
257
 
@@ -301,7 +293,7 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
301
293
  if not branch_exists(active_branch):
302
294
  raise ToolException(f"The active branch '{active_branch}' does not exist.")
303
295
 
304
- return values
296
+ return super().validate_toolkit(values)
305
297
 
306
298
  def _get_commits(self, file_path: str, branch: str, top: int = None) -> List[GitCommitRef]:
307
299
  """
@@ -652,6 +644,9 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
652
644
 
653
645
  return dumps(data)
654
646
 
647
+ def download_file(self, path):
648
+ return b"".join(self._client.get_item_content(self.repository_id, path=path, project=self.project, download=True))
649
+
655
650
  def get_file_content(self, commit_id, path):
656
651
  version_descriptor = GitVersionDescriptor(
657
652
  version=commit_id, version_type="commit"
@@ -1179,9 +1174,10 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
1179
1174
  except Exception as e:
1180
1175
  return ToolException(f"Unable to retrieve commits due to error:\n{str(e)}")
1181
1176
 
1177
+ @extend_with_parent_available_tools
1182
1178
  def get_available_tools(self):
1183
1179
  """Return a list of available tools."""
1184
- tools = [
1180
+ return [
1185
1181
  {
1186
1182
  "ref": self.list_branches_in_repo,
1187
1183
  "name": "list_branches_in_repo",
@@ -1272,8 +1268,4 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
1272
1268
  "description": self.get_commits.__doc__,
1273
1269
  "args_schema": ArgsSchema.GetCommits.value,
1274
1270
  },
1275
- ] # Add vector search tools from base class (includes index_data + search tools)
1276
- vector_search_tools = self._get_vector_search_tools()
1277
- tools.extend(vector_search_tools)
1278
-
1279
- return tools
1271
+ ]