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
@@ -1,127 +1,300 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
- import re
3
- import logging
4
- from typing import List, Any, Optional, Dict
5
- from langchain_core.tools import BaseTool, BaseToolkit, ToolException
6
- from requests_openapi import Operation, Client, Server
4
+ from typing import Any, Dict, List, Optional
7
5
 
8
- from pydantic import create_model, Field
9
- from functools import partial
6
+ from langchain_core.tools import BaseTool, BaseToolkit
7
+ from pydantic import BaseModel, ConfigDict, Field, create_model
8
+ import yaml
10
9
 
11
- logger = logging.getLogger(__name__)
10
+ from .api_wrapper import _get_base_url_from_spec, build_wrapper
11
+ from .tool import OpenApiAction
12
+ from ..elitea_base import filter_missconfigured_index_tools
13
+ from ...configurations.openapi import OpenApiConfiguration
12
14
 
13
- name = "openapi"
15
+ name = 'openapi'
14
16
 
15
- def get_tools(tool):
16
- headers = {}
17
- if tool['settings'].get('authentication'):
18
- if tool['settings']['authentication']['type'] == 'api_key':
19
- auth_type = tool['settings']['authentication']['settings']['auth_type']
20
- auth_key = tool["settings"]["authentication"]["settings"]["api_key"]
21
- if auth_type.lower() == 'bearer':
22
- headers['Authorization'] = f'Bearer {auth_key}'
23
- if auth_type.lower() == 'basic':
24
- headers['Authorization'] = f'Basic {auth_key}'
25
- if auth_type.lower() == 'custom':
26
- headers[
27
- tool["settings"]["authentication"]["settings"]["custom_header_name"]] = f'{auth_key}'
17
+
18
+ def get_toolkit(tool) -> BaseToolkit:
19
+ settings = tool.get('settings', {}) or {}
20
+ # Extract selected_tools separately to avoid duplicate keyword argument when unpacking **settings
21
+ selected_tools = settings.get('selected_tools', [])
22
+ # Filter out selected_tools from settings to prevent "got multiple values for keyword argument"
23
+ filtered_settings = {k: v for k, v in settings.items() if k != 'selected_tools'}
28
24
  return AlitaOpenAPIToolkit.get_toolkit(
29
- openapi_spec=tool['settings']['schema_settings'],
30
- selected_tools=tool['settings'].get('selected_tools', []),
31
- headers=headers).get_tools()
32
-
33
-
34
- def create_api_tool(name: str, op: Operation):
35
- fields = {}
36
- headers = {}
37
- headers_descriptions = []
38
-
39
- for parameter in op.spec.parameters:
40
- if "header" in parameter.param_in:
41
- headers[parameter.name] = parameter.param_schema.default
42
- headers_descriptions.append(f"Header: {parameter.name}. Description: {parameter.description}.")
43
- continue
44
- fields[parameter.name] = (str, Field(default=parameter.param_schema.default,
45
- description=parameter.description))
46
-
47
- # add headers
48
- if headers:
49
- fields['headers'] = (Optional[dict], Field(default = headers, description="The dict that represents headers for request:\n" + '\n'.join(headers_descriptions)))
50
-
51
- if op.spec.requestBody:
52
- fields['json'] = (Optional[str], Field(default = None, description="JSON request body provided as a string"))
53
-
54
- op.server = Server.from_openapi_server(op.server) # patch this
55
- op.server.get_url = partial(Server.get_url, op.server)
56
- op.server.set_url = partial(Server.set_url, op.server)
57
- return ApiTool(
58
- name=name,
59
- description=op.spec.description if op.spec.description else op.spec.summary,
60
- args_schema=create_model(
61
- 'request_params',
62
- regexp = (Optional[str], Field(description="Regular expression used to remove from final output if any", default=None)),
63
- **fields),
64
- callable=op
25
+ selected_tools=selected_tools,
26
+ toolkit_name=tool.get('toolkit_name'),
27
+ **filtered_settings,
65
28
  )
66
29
 
67
- class ApiTool(BaseTool):
68
- name: str
69
- description: str
70
- callable: Operation
71
-
72
- def _run(self, regexp: str = None, **kwargs):
73
- # set in query parameter from header (actual for authentication)
74
- rq_args = self.args.keys()
75
- headers = self.callable.requestor.headers
76
- for arg in rq_args:
77
- arg_value = headers.get(arg)
78
- if arg_value:
79
- kwargs.update({arg : arg_value})
80
-
81
- if kwargs.get("json"):
82
- # add json to payload
83
- kwargs.update({"json": json.loads(kwargs.get("json"))})
84
- output = self.callable(**kwargs).content
30
+
31
+ def get_tools(tool):
32
+ return get_toolkit(tool).get_tools()
33
+
34
+
35
+ def get_toolkit_available_tools(settings: dict) -> dict:
36
+ """Return instance-dependent tool list + per-tool args JSON schemas.
37
+
38
+ This is used by backend services when the UI needs spec-derived tool names
39
+ and input schemas (one tool per operationId). It must be JSON-serializable.
40
+ """
41
+ if not isinstance(settings, dict):
42
+ settings = {}
43
+
44
+ # Extract and merge openapi_configuration if present (same pattern as get_toolkit)
45
+ openapi_configuration = settings.get('openapi_configuration') or {}
46
+ if hasattr(openapi_configuration, 'model_dump'):
47
+ openapi_configuration = openapi_configuration.model_dump(mode='json')
48
+ if not isinstance(openapi_configuration, dict):
49
+ openapi_configuration = {}
50
+
51
+ # Merge settings with openapi_configuration so api_key, auth_type etc. are at root level
52
+ merged_settings: Dict[str, Any] = {
53
+ **settings,
54
+ **openapi_configuration,
55
+ }
56
+
57
+ spec = merged_settings.get('spec') or merged_settings.get('schema_settings') or merged_settings.get('openapi_spec')
58
+ base_url_override = merged_settings.get('base_url') or merged_settings.get('base_url_override')
59
+
60
+ if not spec or not isinstance(spec, (str, dict)):
61
+ return {"tools": [], "args_schemas": {}, "error": "OpenAPI spec is missing"}
62
+
63
+ try:
64
+ headers = _build_headers_from_settings(merged_settings)
65
+ api_wrapper = build_wrapper(
66
+ openapi_spec=spec,
67
+ base_headers=headers,
68
+ base_url_override=base_url_override,
69
+ )
70
+
71
+ tool_defs = api_wrapper.get_available_tools(selected_tools=None)
72
+
73
+ tools = []
74
+ args_schemas = {}
75
+
76
+ for tool_def in tool_defs:
77
+ name_val = tool_def.get('name')
78
+ if not isinstance(name_val, str) or not name_val:
79
+ continue
80
+
81
+ desc_val = tool_def.get('description')
82
+ if not isinstance(desc_val, str):
83
+ desc_val = ''
84
+
85
+ tools.append({"name": name_val, "description": desc_val})
86
+
87
+ args_schema = tool_def.get('args_schema')
88
+ if args_schema is None:
89
+ args_schemas[name_val] = {"type": "object", "properties": {}, "required": []}
90
+ continue
91
+
92
+ try:
93
+ if hasattr(args_schema, 'model_json_schema'):
94
+ args_schemas[name_val] = args_schema.model_json_schema()
95
+ elif hasattr(args_schema, 'schema'):
96
+ args_schemas[name_val] = args_schema.schema()
97
+ else:
98
+ args_schemas[name_val] = {"type": "object", "properties": {}, "required": []}
99
+ except Exception:
100
+ args_schemas[name_val] = {"type": "object", "properties": {}, "required": []}
101
+
102
+ # Ensure stable JSON-serializability.
85
103
  try:
86
- if regexp is not None:
87
- output = re.sub(rf'{regexp}', "", str(output))
88
- finally:
89
- return output
104
+ json.dumps({"tools": tools, "args_schemas": args_schemas})
105
+ except Exception:
106
+ return {"tools": tools, "args_schemas": {}}
107
+
108
+ return {"tools": tools, "args_schemas": args_schemas}
109
+
110
+ except Exception as e: # pylint: disable=W0718
111
+ return {"tools": [], "args_schemas": {}, "error": str(e)}
90
112
 
91
113
  class AlitaOpenAPIToolkit(BaseToolkit):
92
114
  request_session: Any #: :meta private:
93
115
  tools: List[BaseTool] = []
94
116
 
117
+ @staticmethod
118
+ def toolkit_config_schema() -> BaseModel:
119
+ # OpenAPI tool names + per-tool args schemas depend on the user-provided spec,
120
+ # so `selected_tools` cannot be an enum here (unlike most toolkits).
121
+
122
+ model = create_model(
123
+ name,
124
+ __config__=ConfigDict(
125
+ extra='ignore',
126
+ json_schema_extra={
127
+ 'metadata': {
128
+ 'label': 'OpenAPI',
129
+ 'icon_url': 'openapi.svg',
130
+ 'categories': ['integrations'],
131
+ 'extra_categories': ['api', 'openapi', 'swagger'],
132
+ }
133
+ }
134
+ ),
135
+ openapi_configuration=(
136
+ OpenApiConfiguration,
137
+ Field(
138
+ description='OpenAPI credentials configuration',
139
+ json_schema_extra={'configuration_types': ['openapi']},
140
+ ),
141
+ ),
142
+ base_url=(
143
+ Optional[str],
144
+ Field(
145
+ default=None,
146
+ description=(
147
+ "Optional base URL override (absolute, starting with http:// or https://). "
148
+ "Use this when your OpenAPI spec has no `servers` entry, or when `servers[0].url` "
149
+ "is not absolute (e.g. '/api/v3'). Example: 'https://petstore3.swagger.io'."
150
+ ),
151
+ ),
152
+ ),
153
+ spec=(
154
+ str,
155
+ Field(
156
+ description=(
157
+ 'OpenAPI specification (URL or raw JSON/YAML text). '
158
+ 'Used to generate per-operation tools (one tool per operationId).'
159
+ ),
160
+ json_schema_extra={'ui_component': 'openapi_spec'},
161
+ ),
162
+ ),
163
+ selected_tools=(
164
+ List[str],
165
+ Field(
166
+ default=[],
167
+ description='Optional list of operationIds to enable. If empty, all operations are enabled.',
168
+ json_schema_extra={'args_schemas': {}},
169
+ ),
170
+ ),
171
+ )
172
+ return model
173
+
95
174
  @classmethod
96
- def get_toolkit(cls, openapi_spec: str | dict,
97
- selected_tools: list[dict] | None = None,
98
- headers: Optional[Dict[str, str]] = None):
99
- if selected_tools is not None:
100
- tools_set = set([i if not isinstance(i, dict) else i.get('name') for i in selected_tools])
101
- else:
102
- tools_set = {}
103
- if isinstance(openapi_spec, str):
104
- openapi_spec = json.loads(openapi_spec)
105
- c = Client()
106
- c.load_spec(openapi_spec)
107
- if headers:
108
- c.requestor.headers.update(headers)
109
- tools = []
110
- for i in tools_set:
175
+ @filter_missconfigured_index_tools
176
+ def get_toolkit(
177
+ cls,
178
+ selected_tools: list[str] | None = None,
179
+ toolkit_name: Optional[str] = None,
180
+ **kwargs,
181
+ ):
182
+ if selected_tools is None:
183
+ selected_tools = []
111
184
 
112
- try:
113
- if not i:
114
- raise ToolException("Operation id is missing for some of declared operations.")
115
- tool = c.operations[i]
116
- if not isinstance(tool, Operation):
117
- raise ToolException(f"Operation {i} is not an instance of Operation class.")
118
- tools.append(create_api_tool(i, tool))
119
- except ToolException:
120
- raise
121
- except Exception as e:
122
- logger.warning(f"Tool {i} not found in OpenAPI spec.")
123
- raise ToolException(f"Cannot create API tool ({i}): \n{e}.")
124
- return cls(request_session=c, tools=tools)
185
+ tool_names = _coerce_selected_tool_names(selected_tools)
186
+
187
+ openapi_configuration = kwargs.get('openapi_configuration') or {}
188
+ if hasattr(openapi_configuration, 'model_dump'):
189
+ openapi_configuration = openapi_configuration.model_dump(mode='json')
190
+ if not isinstance(openapi_configuration, dict):
191
+ openapi_configuration = {}
192
+
193
+ merged_settings: Dict[str, Any] = {
194
+ **kwargs,
195
+ **openapi_configuration,
196
+ }
197
+
198
+ openapi_spec = merged_settings.get('spec') or merged_settings.get('schema_settings') or merged_settings.get('openapi_spec')
199
+ base_url_override = merged_settings.get('base_url') or merged_settings.get('base_url_override')
200
+ headers = _build_headers_from_settings(merged_settings)
201
+
202
+ api_wrapper = build_wrapper(
203
+ openapi_spec=openapi_spec,
204
+ base_headers=headers,
205
+ base_url_override=base_url_override,
206
+ )
207
+ base_url = _get_base_url_from_spec(api_wrapper.spec)
208
+
209
+ tools: List[BaseTool] = []
210
+ for tool_def in api_wrapper.get_available_tools(selected_tools=tool_names):
211
+ description = tool_def.get('description') or ''
212
+ if toolkit_name:
213
+ description = f"{description}\nToolkit: {toolkit_name}"
214
+ if base_url:
215
+ description = f"{description}\nBase URL: {base_url}"
216
+ description = description[:1000]
217
+
218
+ tools.append(
219
+ OpenApiAction(
220
+ api_wrapper=api_wrapper,
221
+ name=tool_def['name'],
222
+ description=description,
223
+ args_schema=tool_def.get('args_schema'),
224
+ metadata={"toolkit_name": toolkit_name} if toolkit_name else {},
225
+ )
226
+ )
227
+
228
+ return cls(request_session=api_wrapper, tools=tools)
125
229
 
126
230
  def get_tools(self):
127
231
  return self.tools
232
+
233
+
234
+ def _coerce_selected_tool_names(selected_tools: Any) -> list[str]:
235
+ if not selected_tools:
236
+ return []
237
+
238
+ if isinstance(selected_tools, list):
239
+ tool_names: List[str] = []
240
+ for item in selected_tools:
241
+ if isinstance(item, str):
242
+ tool_names.append(item)
243
+ elif isinstance(item, dict):
244
+ name_val = item.get('name')
245
+ if isinstance(name_val, str) and name_val.strip():
246
+ tool_names.append(name_val)
247
+ return [t for t in tool_names if t]
248
+
249
+ return []
250
+
251
+
252
+ def _secret_to_str(value: Any) -> Optional[str]:
253
+ if value is None:
254
+ return None
255
+ if hasattr(value, 'get_secret_value'):
256
+ try:
257
+ value = value.get_secret_value()
258
+ except Exception:
259
+ pass
260
+ if isinstance(value, str):
261
+ return value
262
+ return str(value)
263
+
264
+
265
+ def _build_headers_from_settings(settings: Dict[str, Any]) -> Dict[str, str]:
266
+ headers: Dict[str, str] = {}
267
+
268
+ # Legacy structure used by the custom OpenAPI UI
269
+ auth = settings.get('authentication')
270
+ if isinstance(auth, dict) and auth.get('type') == 'api_key':
271
+ auth_settings = auth.get('settings') or {}
272
+ if isinstance(auth_settings, dict):
273
+ auth_type = str(auth_settings.get('auth_type', '')).strip().lower()
274
+ api_key = _secret_to_str(auth_settings.get('api_key'))
275
+ if api_key:
276
+ if auth_type == 'bearer':
277
+ headers['Authorization'] = f'Bearer {api_key}'
278
+ elif auth_type == 'basic':
279
+ headers['Authorization'] = f'Basic {api_key}'
280
+ elif auth_type == 'custom':
281
+ header_name = auth_settings.get('custom_header_name')
282
+ if header_name:
283
+ headers[str(header_name)] = f'{api_key}'
284
+
285
+ # New regular-schema structure (GitHub-style sections) uses flattened fields
286
+ if not headers:
287
+ api_key = _secret_to_str(settings.get('api_key'))
288
+ if api_key:
289
+ auth_type = str(settings.get('auth_type', 'Bearer'))
290
+ auth_type_norm = auth_type.strip().lower()
291
+ if auth_type_norm == 'bearer':
292
+ headers['Authorization'] = f'Bearer {api_key}'
293
+ elif auth_type_norm == 'basic':
294
+ headers['Authorization'] = f'Basic {api_key}'
295
+ elif auth_type_norm == 'custom':
296
+ header_name = settings.get('custom_header_name')
297
+ if header_name:
298
+ headers[str(header_name)] = f'{api_key}'
299
+
300
+ return headers