alita-sdk 0.3.263__py3-none-any.whl → 0.3.499__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 (248) 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 +1256 -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 +64 -8
  30. alita_sdk/community/inventory/__init__.py +224 -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/visualize.py +1370 -0
  58. alita_sdk/configurations/__init__.py +10 -0
  59. alita_sdk/configurations/ado.py +4 -2
  60. alita_sdk/configurations/azure_search.py +1 -1
  61. alita_sdk/configurations/bigquery.py +1 -1
  62. alita_sdk/configurations/bitbucket.py +94 -2
  63. alita_sdk/configurations/browser.py +18 -0
  64. alita_sdk/configurations/carrier.py +19 -0
  65. alita_sdk/configurations/confluence.py +96 -1
  66. alita_sdk/configurations/delta_lake.py +1 -1
  67. alita_sdk/configurations/figma.py +0 -5
  68. alita_sdk/configurations/github.py +65 -1
  69. alita_sdk/configurations/gitlab.py +79 -0
  70. alita_sdk/configurations/google_places.py +17 -0
  71. alita_sdk/configurations/jira.py +103 -0
  72. alita_sdk/configurations/postman.py +1 -1
  73. alita_sdk/configurations/qtest.py +1 -3
  74. alita_sdk/configurations/report_portal.py +19 -0
  75. alita_sdk/configurations/salesforce.py +19 -0
  76. alita_sdk/configurations/service_now.py +1 -12
  77. alita_sdk/configurations/sharepoint.py +19 -0
  78. alita_sdk/configurations/sonar.py +18 -0
  79. alita_sdk/configurations/sql.py +20 -0
  80. alita_sdk/configurations/testio.py +18 -0
  81. alita_sdk/configurations/testrail.py +88 -0
  82. alita_sdk/configurations/xray.py +94 -1
  83. alita_sdk/configurations/zephyr_enterprise.py +94 -1
  84. alita_sdk/configurations/zephyr_essential.py +95 -0
  85. alita_sdk/runtime/clients/artifact.py +12 -2
  86. alita_sdk/runtime/clients/client.py +235 -66
  87. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  88. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  89. alita_sdk/runtime/clients/sandbox_client.py +373 -0
  90. alita_sdk/runtime/langchain/assistant.py +123 -17
  91. alita_sdk/runtime/langchain/constants.py +8 -1
  92. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  93. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
  94. alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
  95. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +8 -2
  96. alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
  97. alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
  98. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
  99. alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
  100. alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
  101. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
  102. alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
  103. alita_sdk/runtime/langchain/document_loaders/constants.py +187 -40
  104. alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
  105. alita_sdk/runtime/langchain/langraph_agent.py +406 -91
  106. alita_sdk/runtime/langchain/utils.py +51 -8
  107. alita_sdk/runtime/llms/preloaded.py +2 -6
  108. alita_sdk/runtime/models/mcp_models.py +61 -0
  109. alita_sdk/runtime/toolkits/__init__.py +26 -0
  110. alita_sdk/runtime/toolkits/application.py +9 -2
  111. alita_sdk/runtime/toolkits/artifact.py +19 -7
  112. alita_sdk/runtime/toolkits/datasource.py +13 -6
  113. alita_sdk/runtime/toolkits/mcp.py +780 -0
  114. alita_sdk/runtime/toolkits/planning.py +178 -0
  115. alita_sdk/runtime/toolkits/subgraph.py +11 -6
  116. alita_sdk/runtime/toolkits/tools.py +214 -60
  117. alita_sdk/runtime/toolkits/vectorstore.py +9 -4
  118. alita_sdk/runtime/tools/__init__.py +22 -0
  119. alita_sdk/runtime/tools/application.py +16 -4
  120. alita_sdk/runtime/tools/artifact.py +312 -19
  121. alita_sdk/runtime/tools/function.py +100 -4
  122. alita_sdk/runtime/tools/graph.py +81 -0
  123. alita_sdk/runtime/tools/image_generation.py +212 -0
  124. alita_sdk/runtime/tools/llm.py +539 -180
  125. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  126. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  127. alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
  128. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  129. alita_sdk/runtime/tools/planning/models.py +246 -0
  130. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  131. alita_sdk/runtime/tools/router.py +2 -1
  132. alita_sdk/runtime/tools/sandbox.py +375 -0
  133. alita_sdk/runtime/tools/vectorstore.py +62 -63
  134. alita_sdk/runtime/tools/vectorstore_base.py +156 -85
  135. alita_sdk/runtime/utils/AlitaCallback.py +106 -20
  136. alita_sdk/runtime/utils/mcp_client.py +465 -0
  137. alita_sdk/runtime/utils/mcp_oauth.py +244 -0
  138. alita_sdk/runtime/utils/mcp_sse_client.py +405 -0
  139. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  140. alita_sdk/runtime/utils/streamlit.py +41 -14
  141. alita_sdk/runtime/utils/toolkit_utils.py +28 -9
  142. alita_sdk/runtime/utils/utils.py +14 -0
  143. alita_sdk/tools/__init__.py +78 -35
  144. alita_sdk/tools/ado/__init__.py +0 -1
  145. alita_sdk/tools/ado/repos/__init__.py +10 -6
  146. alita_sdk/tools/ado/repos/repos_wrapper.py +12 -11
  147. alita_sdk/tools/ado/test_plan/__init__.py +10 -7
  148. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -23
  149. alita_sdk/tools/ado/wiki/__init__.py +10 -11
  150. alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -28
  151. alita_sdk/tools/ado/work_item/__init__.py +10 -11
  152. alita_sdk/tools/ado/work_item/ado_wrapper.py +63 -10
  153. alita_sdk/tools/advanced_jira_mining/__init__.py +10 -7
  154. alita_sdk/tools/aws/delta_lake/__init__.py +13 -11
  155. alita_sdk/tools/azure_ai/search/__init__.py +11 -7
  156. alita_sdk/tools/base_indexer_toolkit.py +392 -86
  157. alita_sdk/tools/bitbucket/__init__.py +18 -11
  158. alita_sdk/tools/bitbucket/api_wrapper.py +52 -9
  159. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
  160. alita_sdk/tools/browser/__init__.py +40 -16
  161. alita_sdk/tools/browser/crawler.py +3 -1
  162. alita_sdk/tools/browser/utils.py +15 -6
  163. alita_sdk/tools/carrier/__init__.py +17 -17
  164. alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
  165. alita_sdk/tools/carrier/excel_reporter.py +8 -4
  166. alita_sdk/tools/chunkers/__init__.py +3 -1
  167. alita_sdk/tools/chunkers/code/codeparser.py +1 -1
  168. alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
  169. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  170. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  171. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  172. alita_sdk/tools/cloud/aws/__init__.py +9 -6
  173. alita_sdk/tools/cloud/azure/__init__.py +9 -6
  174. alita_sdk/tools/cloud/gcp/__init__.py +9 -6
  175. alita_sdk/tools/cloud/k8s/__init__.py +9 -6
  176. alita_sdk/tools/code/linter/__init__.py +7 -7
  177. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  178. alita_sdk/tools/code/sonar/__init__.py +18 -12
  179. alita_sdk/tools/code_indexer_toolkit.py +199 -0
  180. alita_sdk/tools/confluence/__init__.py +14 -11
  181. alita_sdk/tools/confluence/api_wrapper.py +198 -58
  182. alita_sdk/tools/confluence/loader.py +10 -0
  183. alita_sdk/tools/custom_open_api/__init__.py +9 -4
  184. alita_sdk/tools/elastic/__init__.py +8 -7
  185. alita_sdk/tools/elitea_base.py +543 -64
  186. alita_sdk/tools/figma/__init__.py +10 -8
  187. alita_sdk/tools/figma/api_wrapper.py +352 -153
  188. alita_sdk/tools/github/__init__.py +13 -11
  189. alita_sdk/tools/github/api_wrapper.py +9 -26
  190. alita_sdk/tools/github/github_client.py +75 -12
  191. alita_sdk/tools/github/schemas.py +2 -1
  192. alita_sdk/tools/gitlab/__init__.py +11 -10
  193. alita_sdk/tools/gitlab/api_wrapper.py +135 -45
  194. alita_sdk/tools/gitlab_org/__init__.py +11 -9
  195. alita_sdk/tools/google/bigquery/__init__.py +12 -13
  196. alita_sdk/tools/google_places/__init__.py +18 -10
  197. alita_sdk/tools/jira/__init__.py +14 -8
  198. alita_sdk/tools/jira/api_wrapper.py +315 -168
  199. alita_sdk/tools/keycloak/__init__.py +8 -7
  200. alita_sdk/tools/localgit/local_git.py +56 -54
  201. alita_sdk/tools/memory/__init__.py +27 -11
  202. alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
  203. alita_sdk/tools/ocr/__init__.py +8 -7
  204. alita_sdk/tools/openapi/__init__.py +10 -1
  205. alita_sdk/tools/pandas/__init__.py +8 -7
  206. alita_sdk/tools/pandas/api_wrapper.py +7 -25
  207. alita_sdk/tools/postman/__init__.py +8 -10
  208. alita_sdk/tools/postman/api_wrapper.py +19 -8
  209. alita_sdk/tools/postman/postman_analysis.py +8 -1
  210. alita_sdk/tools/pptx/__init__.py +8 -9
  211. alita_sdk/tools/qtest/__init__.py +19 -13
  212. alita_sdk/tools/qtest/api_wrapper.py +1784 -88
  213. alita_sdk/tools/rally/__init__.py +10 -9
  214. alita_sdk/tools/report_portal/__init__.py +20 -15
  215. alita_sdk/tools/salesforce/__init__.py +19 -15
  216. alita_sdk/tools/servicenow/__init__.py +14 -11
  217. alita_sdk/tools/sharepoint/__init__.py +14 -13
  218. alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
  219. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  220. alita_sdk/tools/sharepoint/utils.py +8 -2
  221. alita_sdk/tools/slack/__init__.py +10 -7
  222. alita_sdk/tools/sql/__init__.py +19 -18
  223. alita_sdk/tools/sql/api_wrapper.py +71 -23
  224. alita_sdk/tools/testio/__init__.py +18 -12
  225. alita_sdk/tools/testrail/__init__.py +10 -10
  226. alita_sdk/tools/testrail/api_wrapper.py +213 -45
  227. alita_sdk/tools/utils/__init__.py +28 -4
  228. alita_sdk/tools/utils/content_parser.py +181 -61
  229. alita_sdk/tools/utils/text_operations.py +254 -0
  230. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
  231. alita_sdk/tools/xray/__init__.py +12 -7
  232. alita_sdk/tools/xray/api_wrapper.py +58 -113
  233. alita_sdk/tools/zephyr/__init__.py +9 -6
  234. alita_sdk/tools/zephyr_enterprise/__init__.py +13 -8
  235. alita_sdk/tools/zephyr_enterprise/api_wrapper.py +17 -7
  236. alita_sdk/tools/zephyr_essential/__init__.py +13 -9
  237. alita_sdk/tools/zephyr_essential/api_wrapper.py +289 -47
  238. alita_sdk/tools/zephyr_essential/client.py +6 -4
  239. alita_sdk/tools/zephyr_scale/__init__.py +10 -7
  240. alita_sdk/tools/zephyr_scale/api_wrapper.py +6 -2
  241. alita_sdk/tools/zephyr_squad/__init__.py +9 -6
  242. {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/METADATA +180 -33
  243. alita_sdk-0.3.499.dist-info/RECORD +433 -0
  244. alita_sdk-0.3.499.dist-info/entry_points.txt +2 -0
  245. alita_sdk-0.3.263.dist-info/RECORD +0 -342
  246. {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/WHEEL +0 -0
  247. {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/licenses/LICENSE +0 -0
  248. {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,124 @@
1
+ """
2
+ MCP Tools Discovery Utility.
3
+ Provides a standalone function to discover tools from remote MCP servers.
4
+ Supports both SSE (Server-Sent Events) and Streamable HTTP transports with auto-detection.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from .mcp_oauth import McpAuthorizationRequired
12
+ from .mcp_client import McpClient
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def discover_mcp_tools(
18
+ url: str,
19
+ headers: Optional[Dict[str, str]] = None,
20
+ timeout: int = 60,
21
+ session_id: Optional[str] = None,
22
+ ) -> List[Dict[str, Any]]:
23
+ """
24
+ Discover available tools from a remote MCP server.
25
+
26
+ This function connects to a remote MCP server and retrieves the list of
27
+ available tools using the MCP protocol. Automatically detects and uses
28
+ the appropriate transport (SSE or Streamable HTTP).
29
+
30
+ Args:
31
+ url: MCP server HTTP URL (http:// or https://)
32
+ headers: Optional HTTP headers for authentication
33
+ timeout: Request timeout in seconds (default: 60)
34
+ session_id: Optional session ID for stateful connections
35
+
36
+ Returns:
37
+ List of tool definitions, each containing:
38
+ - name: Tool name
39
+ - description: Tool description
40
+ - inputSchema: JSON schema for tool input parameters
41
+
42
+ Raises:
43
+ McpAuthorizationRequired: If the server requires OAuth authorization (401)
44
+ Exception: For other connection or protocol errors
45
+
46
+ Example:
47
+ >>> tools = discover_mcp_tools(
48
+ ... url="https://mcp.example.com/sse",
49
+ ... headers={"Authorization": "Bearer token123"}
50
+ ... )
51
+ >>> print(f"Found {len(tools)} tools")
52
+ """
53
+ logger.info(f"[MCP Discovery] Starting tool discovery from {url}")
54
+
55
+ try:
56
+ # Run the async discovery in a new event loop
57
+ tools_list = asyncio.run(
58
+ _discover_tools_async(url, headers, timeout, session_id)
59
+ )
60
+ logger.info(f"[MCP Discovery] Successfully discovered {len(tools_list)} tools from {url}")
61
+ return tools_list
62
+
63
+ except McpAuthorizationRequired:
64
+ # Re-raise auth exceptions directly
65
+ logger.info(f"[MCP Discovery] Authorization required for {url}")
66
+ raise
67
+
68
+ except Exception as e:
69
+ logger.error(f"[MCP Discovery] Failed to discover tools from {url}: {e}")
70
+ raise
71
+
72
+
73
+ async def _discover_tools_async(
74
+ url: str,
75
+ headers: Optional[Dict[str, str]],
76
+ timeout: int,
77
+ session_id: Optional[str],
78
+ ) -> List[Dict[str, Any]]:
79
+ """
80
+ Async implementation of tool discovery using unified MCP client.
81
+ """
82
+ all_tools = []
83
+
84
+ # Create unified MCP client (auto-detects transport)
85
+ client = McpClient(
86
+ url=url,
87
+ session_id=session_id,
88
+ headers=headers,
89
+ timeout=timeout
90
+ )
91
+
92
+ async with client:
93
+ # Initialize MCP session
94
+ await client.initialize()
95
+ logger.debug(f"[MCP Discovery] Session initialized (transport={client.detected_transport})")
96
+
97
+ # Get tools list
98
+ tools = await client.list_tools()
99
+ logger.debug(f"[MCP Discovery] Received {len(tools)} tools")
100
+
101
+ # Convert tools to standard format
102
+ for tool in tools:
103
+ tool_def = {
104
+ 'name': tool.get('name'),
105
+ 'description': tool.get('description', ''),
106
+ 'inputSchema': tool.get('inputSchema', {}),
107
+ }
108
+ all_tools.append(tool_def)
109
+
110
+ return all_tools
111
+
112
+
113
+ async def discover_mcp_tools_async(
114
+ url: str,
115
+ headers: Optional[Dict[str, str]] = None,
116
+ timeout: int = 60,
117
+ session_id: Optional[str] = None,
118
+ ) -> List[Dict[str, Any]]:
119
+ """
120
+ Async version of discover_mcp_tools.
121
+
122
+ See discover_mcp_tools for full documentation.
123
+ """
124
+ return await _discover_tools_async(url, headers, timeout, session_id)
@@ -287,7 +287,6 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
287
287
  model_config={
288
288
  "temperature": 0.1,
289
289
  "max_tokens": 1000,
290
- "top_p": 1.0
291
290
  }
292
291
  )
293
292
  except Exception as e:
@@ -868,10 +867,24 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
868
867
  label = f"{'🔒 ' if is_secret else ''}{'*' if is_required else ''}{field_name.replace('_', ' ').title()}"
869
868
 
870
869
  if field_type == 'string':
871
- if is_secret:
870
+ # Check if this is an enum field
871
+ if field_schema.get('enum'):
872
+ # Dropdown for enum values
873
+ options = field_schema['enum']
874
+ default_index = 0
875
+ if default_value and str(default_value) in options:
876
+ default_index = options.index(str(default_value))
877
+ toolkit_config_values[field_name] = st.selectbox(
878
+ label,
879
+ options=options,
880
+ index=default_index,
881
+ help=field_description,
882
+ key=f"config_{field_name}_{selected_toolkit_idx}"
883
+ )
884
+ elif is_secret:
872
885
  toolkit_config_values[field_name] = st.text_input(
873
886
  label,
874
- value=str(default_value) if default_value else '',
887
+ value=str(default_value) if default_value else '',
875
888
  help=field_description,
876
889
  type="password",
877
890
  key=f"config_{field_name}_{selected_toolkit_idx}"
@@ -879,7 +892,7 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
879
892
  else:
880
893
  toolkit_config_values[field_name] = st.text_input(
881
894
  label,
882
- value=str(default_value) if default_value else '',
895
+ value=str(default_value) if default_value else '',
883
896
  help=field_description,
884
897
  key=f"config_{field_name}_{selected_toolkit_idx}"
885
898
  )
@@ -971,6 +984,23 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
971
984
  key=f"config_{field_name}_{selected_toolkit_idx}"
972
985
  )
973
986
  toolkit_config_values[field_name] = [line.strip() for line in array_input.split('\n') if line.strip()]
987
+ elif field_type == 'object':
988
+ # Handle object/dict types (like headers)
989
+ obj_input = st.text_area(
990
+ f"{label} (JSON object)",
991
+ value=json.dumps(default_value) if isinstance(default_value, dict) else str(default_value) if default_value else '',
992
+ help=f"{field_description} - Enter as JSON object, e.g. {{\"Authorization\": \"Bearer token\"}}",
993
+ placeholder='{"key": "value"}',
994
+ key=f"config_{field_name}_{selected_toolkit_idx}"
995
+ )
996
+ try:
997
+ if obj_input.strip():
998
+ toolkit_config_values[field_name] = json.loads(obj_input)
999
+ else:
1000
+ toolkit_config_values[field_name] = None
1001
+ except json.JSONDecodeError as e:
1002
+ st.error(f"Invalid JSON format for {field_name}: {e}")
1003
+ toolkit_config_values[field_name] = None
974
1004
  else:
975
1005
  st.info("This toolkit doesn't require additional configuration.")
976
1006
 
@@ -1102,7 +1132,7 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
1102
1132
  st_cb = AlitaStreamlitCallback(st)
1103
1133
  logger.info(st.session_state.messages)
1104
1134
  response = st.session_state.agent_executor.invoke(
1105
- {"input": prompt, "chat_history": st.session_state.messages[:-1]},
1135
+ {"input": [prompt], "chat_history": st.session_state.messages[:-1]},
1106
1136
  { 'callbacks': [st_cb], 'configurable': {"thread_id": st.session_state.thread_id}}
1107
1137
  )
1108
1138
  st.write(response["output"])
@@ -1225,7 +1255,6 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
1225
1255
  model_config={
1226
1256
  "temperature": 0.1,
1227
1257
  "max_tokens": 1000,
1228
- "top_p": 1.0
1229
1258
  }
1230
1259
  )
1231
1260
  except Exception as e:
@@ -1356,20 +1385,18 @@ def run_streamlit(st, ai_icon=None, user_icon=None):
1356
1385
  help="Maximum number of tokens in the AI response"
1357
1386
  )
1358
1387
 
1359
- top_p = st.slider(
1360
- "Top-p:",
1361
- min_value=0.1,
1362
- max_value=1.0,
1363
- value=1.0,
1364
- step=0.1,
1365
- help="Controls diversity via nucleus sampling"
1388
+ reasoning_effort = st.selectbox(
1389
+ "Reasoning effort:",
1390
+ options=['null', 'low', 'medium', 'high'],
1391
+ index=0,
1392
+ help="Higher effort better reasoning, slower response"
1366
1393
  )
1367
1394
 
1368
1395
  # Create LLM config
1369
1396
  llm_config = {
1370
1397
  'max_tokens': max_tokens,
1371
1398
  'temperature': temperature,
1372
- 'top_p': top_p
1399
+ 'reasoning_effort': reasoning_effort
1373
1400
  }
1374
1401
 
1375
1402
  col1, col2 = st.columns([3, 1])
@@ -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,8 @@
1
1
  import re
2
2
  from enum import Enum
3
3
 
4
+ # DEPRECATED: Tool names no longer use prefixes
5
+ # Kept for backward compatibility only
4
6
  TOOLKIT_SPLITTER = "___"
5
7
 
6
8
  class IndexerKeywords(Enum):
@@ -9,6 +11,12 @@ class IndexerKeywords(Enum):
9
11
  PARENT = 'parent_id'
10
12
  # DEPENDENCY_ID = 'dependency_id'
11
13
  UPDATED_ON = 'updated_on'
14
+ CONTENT_IN_BYTES = 'loader_content'
15
+ CONTENT_FILE_NAME = 'loader_content_type'
16
+ INDEX_META_TYPE = 'index_meta'
17
+ INDEX_META_IN_PROGRESS = 'in_progress'
18
+ INDEX_META_COMPLETED = 'completed'
19
+ INDEX_META_FAILED = 'failed'
12
20
 
13
21
  # This pattern matches characters that are NOT alphanumeric, underscores, or hyphens
14
22
  clean_string_pattern = re.compile(r'[^a-zA-Z0-9_.-]')
@@ -18,3 +26,9 @@ def clean_string(s: str) -> str:
18
26
  # Replace these characters with an empty string
19
27
  cleaned_string = re.sub(clean_string_pattern, '', s)
20
28
  return cleaned_string
29
+
30
+
31
+ def clean_node_str(s: str) -> str:
32
+ """Cleans a node string by removing all non-alphanumeric characters except underscores and spaces."""
33
+ cleaned_string = re.sub(r'[^\w\s]', '', s)
34
+ return cleaned_string
@@ -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:
@@ -34,6 +58,7 @@ def _safe_import_tool(tool_name, module_path, get_tools_name=None, toolkit_class
34
58
  FAILED_IMPORTS[tool_name] = str(e)
35
59
  logger.debug(f"Failed to import {tool_name}: {e}")
36
60
 
61
+
37
62
  # Safe imports for all tools
38
63
  _safe_import_tool('github', 'github', 'get_tools', 'AlitaGitHubToolkit')
39
64
  _safe_import_tool('openapi', 'openapi', 'get_tools')
@@ -67,7 +92,7 @@ _safe_import_tool('aws', 'cloud.aws', None, 'AWSToolkit')
67
92
  _safe_import_tool('azure', 'cloud.azure', None, 'AzureToolkit')
68
93
  _safe_import_tool('gcp', 'cloud.gcp', None, 'GCPToolkit')
69
94
  _safe_import_tool('k8s', 'cloud.k8s', None, 'KubernetesToolkit')
70
- _safe_import_tool('custom_open_api', 'custom_open_api', None, 'OpenApiToolkit')
95
+ # _safe_import_tool('custom_open_api', 'custom_open_api', None, 'OpenApiToolkit')
71
96
  _safe_import_tool('elastic', 'elastic', None, 'ElasticToolkit')
72
97
  _safe_import_tool('keycloak', 'keycloak', None, 'KeycloakToolkit')
73
98
  _safe_import_tool('localgit', 'localgit', None, 'AlitaLocalGitToolkit')
@@ -79,7 +104,6 @@ _safe_import_tool('carrier', 'carrier', 'get_tools', 'AlitaCarrierToolkit')
79
104
  _safe_import_tool('ocr', 'ocr', 'get_tools', 'OCRToolkit')
80
105
  _safe_import_tool('pptx', 'pptx', 'get_tools', 'PPTXToolkit')
81
106
  _safe_import_tool('postman', 'postman', 'get_tools', 'PostmanToolkit')
82
- _safe_import_tool('memory', 'memory', 'get_tools', 'MemoryToolkit')
83
107
  _safe_import_tool('zephyr_squad', 'zephyr_squad', 'get_tools', 'ZephyrSquadToolkit')
84
108
  _safe_import_tool('zephyr_essential', 'zephyr_essential', 'get_tools', 'ZephyrEssentialToolkit')
85
109
  _safe_import_tool('slack', 'slack', 'get_tools', 'SlackToolkit')
@@ -91,62 +115,81 @@ available_count = len(AVAILABLE_TOOLS)
91
115
  total_attempted = len(AVAILABLE_TOOLS) + len(FAILED_IMPORTS)
92
116
  logger.info(f"Tool imports completed: {available_count}/{total_attempted} successful")
93
117
 
118
+ # Import community module to trigger community toolkit registration
119
+ try:
120
+ from alita_sdk import community # noqa: F401
121
+ logger.debug("Community toolkits registered successfully")
122
+ except ImportError as e:
123
+ logger.debug(f"Community module not available: {e}")
124
+
125
+
94
126
  def get_tools(tools_list, alita, llm, store: Optional[BaseStore] = None, *args, **kwargs):
95
127
  tools = []
128
+
96
129
  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']
130
+ toolkit_tools = []
131
+ settings = tool.get('settings')
106
132
 
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))
133
+ # Skip tools without settings early
134
+ if not settings:
135
+ logger.warning(f"Tool '{tool.get('type', '')}' has no settings, skipping...")
136
+ continue
110
137
 
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))
138
+ # Validate tool names once
139
+ selected_tools = settings.get('selected_tools', [])
140
+ invalid_tools = [name for name in selected_tools if isinstance(name, str) and name.startswith('_')]
141
+ if invalid_tools:
142
+ raise ValueError(f"Tool names {invalid_tools} from toolkit '{tool.get('type', '')}' cannot start with '_'")
116
143
 
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}")
144
+ # Cache tool type and add common settings
145
+ tool_type = tool['type']
146
+ settings['alita'] = alita
147
+ settings['llm'] = llm
148
+ settings['store'] = store
120
149
 
121
- # Handle ADO repos special case (it might be requested as azure_devops_repos)
150
+ # Set pgvector collection schema if present
151
+ if settings.get('pgvector_configuration'):
152
+ # Use tool id if available, otherwise use toolkit_name or type as fallback
153
+ collection_id = tool.get('id') or tool.get('toolkit_name') or tool_type
154
+ settings['pgvector_configuration']['collection_schema'] = str(collection_id)
155
+
156
+ # Handle ADO special cases
157
+ if tool_type in ['ado_boards', 'ado_wiki', 'ado_plans']:
158
+ toolkit_tools.extend(AVAILABLE_TOOLS['ado']['get_tools'](tool_type, tool))
122
159
  elif tool_type in ['ado_repos', 'azure_devops_repos'] and 'ado_repos' in AVAILABLE_TOOLS:
123
160
  try:
124
- get_tools_func = AVAILABLE_TOOLS['ado_repos']['get_tools']
125
- tools.extend(get_tools_func(tool))
161
+ toolkit_tools.extend(AVAILABLE_TOOLS['ado_repos']['get_tools'](tool))
126
162
  except Exception as e:
127
163
  logger.error(f"Error getting ADO repos tools: {e}")
128
-
129
- # Handle custom modules
130
- elif tool.get("settings", {}).get("module"):
164
+ elif tool_type == 'mcp':
165
+ logger.debug(f"Skipping MCP toolkit '{tool.get('toolkit_name')}' - handled by runtime toolkit system")
166
+ elif tool_type == 'planning':
167
+ logger.debug(f"Skipping planning toolkit '{tool.get('toolkit_name')}' - handled by runtime toolkit system")
168
+ elif tool_type in AVAILABLE_TOOLS and 'get_tools' in AVAILABLE_TOOLS[tool_type]:
169
+ try:
170
+ toolkit_tools.extend(AVAILABLE_TOOLS[tool_type]['get_tools'](tool))
171
+ except Exception as e:
172
+ logger.error(f"Error getting tools for {tool_type}: {e}")
173
+ raise ToolException(f"Error getting tools for {tool_type}: {e}")
174
+ elif settings.get("module"):
131
175
  try:
132
- settings = tool.get("settings", {})
133
176
  mod = import_module(settings.pop("module"))
134
177
  tkitclass = getattr(mod, settings.pop("class"))
135
- #
136
- get_toolkit_params = tool["settings"].copy()
178
+ get_toolkit_params = settings.copy()
137
179
  get_toolkit_params["name"] = tool.get("name")
138
- #
139
180
  toolkit = tkitclass.get_toolkit(**get_toolkit_params)
140
- tools.extend(toolkit.get_tools())
181
+ toolkit_tools.extend(toolkit.get_tools())
141
182
  except Exception as e:
142
183
  logger.error(f"Error in getting custom toolkit: {e}")
143
-
144
184
  else:
145
- # Tool not available or not found
146
185
  if tool_type in FAILED_IMPORTS:
147
186
  logger.warning(f"Tool '{tool_type}' is not available: {FAILED_IMPORTS[tool_type]}")
148
187
  else:
149
188
  logger.warning(f"Unknown tool type: {tool_type}")
189
+ #
190
+ # Always inject toolkit_id to each tool
191
+ _inject_toolkit_id(tool, toolkit_tools)
192
+ tools.extend(toolkit_tools)
150
193
 
151
194
  return tools
152
195
 
@@ -9,7 +9,6 @@ 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', ''),
@@ -5,11 +5,12 @@ 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
 
@@ -26,6 +27,7 @@ def _get_toolkit(tool) -> BaseToolkit:
26
27
  embedding_model=tool['settings'].get('embedding_model'),
27
28
  collection_name=tool['toolkit_name'],
28
29
  alita=tool['settings'].get('alita', None),
30
+ llm=tool['settings'].get('llm', None),
29
31
  )
30
32
 
31
33
  def get_toolkit():
@@ -36,12 +38,10 @@ def get_tools(tool):
36
38
 
37
39
  class AzureDevOpsReposToolkit(BaseToolkit):
38
40
  tools: List[BaseTool] = []
39
- toolkit_max_length: int = 0
40
41
 
41
42
  @staticmethod
42
43
  def toolkit_config_schema() -> BaseModel:
43
44
  selected_tools = {x['name']: x['args_schema'].schema() for x in ReposApiWrapper.model_construct().get_available_tools()}
44
- AzureDevOpsReposToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
45
45
  m = create_model(
46
46
  name,
47
47
  ado_repos_configuration=(AdoReposConfiguration, Field(description="Ado Repos configuration", default=None,
@@ -77,6 +77,7 @@ class AzureDevOpsReposToolkit(BaseToolkit):
77
77
  return m
78
78
 
79
79
  @classmethod
80
+ @filter_missconfigured_index_tools
80
81
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
81
82
  from os import environ
82
83
 
@@ -95,16 +96,19 @@ class AzureDevOpsReposToolkit(BaseToolkit):
95
96
  azure_devops_repos_wrapper = ReposApiWrapper(**wrapper_payload)
96
97
  available_tools = azure_devops_repos_wrapper.get_available_tools()
97
98
  tools = []
98
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
99
99
  for tool in available_tools:
100
100
  if selected_tools:
101
101
  if tool["name"] not in selected_tools:
102
102
  continue
103
+ description = tool["description"] + f"\nADO instance: {azure_devops_repos_wrapper.organization_url}/{azure_devops_repos_wrapper.project}"
104
+ if toolkit_name:
105
+ description = f"{description}\nToolkit: {toolkit_name}"
106
+ description = description[:1000]
103
107
  tools.append(
104
108
  BaseAction(
105
109
  api_wrapper=azure_devops_repos_wrapper,
106
- name=prefix + tool["name"],
107
- description=tool["description"] + f"\nADO instance: {azure_devops_repos_wrapper.organization_url}/{azure_devops_repos_wrapper.project}",
110
+ name=tool["name"],
111
+ description=description,
108
112
  args_schema=tool["args_schema"],
109
113
  )
110
114
  )