alita-sdk 0.3.257__py3-none-any.whl → 0.3.584__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.
Potentially problematic release.
This version of alita-sdk might be problematic. Click here for more details.
- alita_sdk/cli/__init__.py +10 -0
- alita_sdk/cli/__main__.py +17 -0
- alita_sdk/cli/agent/__init__.py +5 -0
- alita_sdk/cli/agent/default.py +258 -0
- alita_sdk/cli/agent_executor.py +155 -0
- alita_sdk/cli/agent_loader.py +215 -0
- alita_sdk/cli/agent_ui.py +228 -0
- alita_sdk/cli/agents.py +3794 -0
- alita_sdk/cli/callbacks.py +647 -0
- alita_sdk/cli/cli.py +168 -0
- alita_sdk/cli/config.py +306 -0
- alita_sdk/cli/context/__init__.py +30 -0
- alita_sdk/cli/context/cleanup.py +198 -0
- alita_sdk/cli/context/manager.py +731 -0
- alita_sdk/cli/context/message.py +285 -0
- alita_sdk/cli/context/strategies.py +289 -0
- alita_sdk/cli/context/token_estimation.py +127 -0
- alita_sdk/cli/formatting.py +182 -0
- alita_sdk/cli/input_handler.py +419 -0
- alita_sdk/cli/inventory.py +1073 -0
- alita_sdk/cli/mcp_loader.py +315 -0
- alita_sdk/cli/toolkit.py +327 -0
- alita_sdk/cli/toolkit_loader.py +85 -0
- alita_sdk/cli/tools/__init__.py +43 -0
- alita_sdk/cli/tools/approval.py +224 -0
- alita_sdk/cli/tools/filesystem.py +1751 -0
- alita_sdk/cli/tools/planning.py +389 -0
- alita_sdk/cli/tools/terminal.py +414 -0
- alita_sdk/community/__init__.py +72 -12
- alita_sdk/community/inventory/__init__.py +236 -0
- alita_sdk/community/inventory/config.py +257 -0
- alita_sdk/community/inventory/enrichment.py +2137 -0
- alita_sdk/community/inventory/extractors.py +1469 -0
- alita_sdk/community/inventory/ingestion.py +3172 -0
- alita_sdk/community/inventory/knowledge_graph.py +1457 -0
- alita_sdk/community/inventory/parsers/__init__.py +218 -0
- alita_sdk/community/inventory/parsers/base.py +295 -0
- alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
- alita_sdk/community/inventory/parsers/go_parser.py +851 -0
- alita_sdk/community/inventory/parsers/html_parser.py +389 -0
- alita_sdk/community/inventory/parsers/java_parser.py +593 -0
- alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
- alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
- alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
- alita_sdk/community/inventory/parsers/python_parser.py +604 -0
- alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
- alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
- alita_sdk/community/inventory/parsers/text_parser.py +322 -0
- alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
- alita_sdk/community/inventory/patterns/__init__.py +61 -0
- alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
- alita_sdk/community/inventory/patterns/loader.py +348 -0
- alita_sdk/community/inventory/patterns/registry.py +198 -0
- alita_sdk/community/inventory/presets.py +535 -0
- alita_sdk/community/inventory/retrieval.py +1403 -0
- alita_sdk/community/inventory/toolkit.py +173 -0
- alita_sdk/community/inventory/toolkit_utils.py +176 -0
- alita_sdk/community/inventory/visualize.py +1370 -0
- alita_sdk/configurations/__init__.py +11 -0
- alita_sdk/configurations/ado.py +148 -2
- alita_sdk/configurations/azure_search.py +1 -1
- alita_sdk/configurations/bigquery.py +1 -1
- alita_sdk/configurations/bitbucket.py +94 -2
- alita_sdk/configurations/browser.py +18 -0
- alita_sdk/configurations/carrier.py +19 -0
- alita_sdk/configurations/confluence.py +130 -1
- alita_sdk/configurations/delta_lake.py +1 -1
- alita_sdk/configurations/figma.py +76 -5
- alita_sdk/configurations/github.py +65 -1
- alita_sdk/configurations/gitlab.py +81 -0
- alita_sdk/configurations/google_places.py +17 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/openapi.py +323 -0
- alita_sdk/configurations/postman.py +1 -1
- alita_sdk/configurations/qtest.py +72 -3
- alita_sdk/configurations/report_portal.py +115 -0
- alita_sdk/configurations/salesforce.py +19 -0
- alita_sdk/configurations/service_now.py +1 -12
- alita_sdk/configurations/sharepoint.py +167 -0
- alita_sdk/configurations/sonar.py +18 -0
- alita_sdk/configurations/sql.py +20 -0
- alita_sdk/configurations/testio.py +101 -0
- alita_sdk/configurations/testrail.py +88 -0
- alita_sdk/configurations/xray.py +94 -1
- alita_sdk/configurations/zephyr_enterprise.py +94 -1
- alita_sdk/configurations/zephyr_essential.py +95 -0
- alita_sdk/runtime/clients/artifact.py +21 -4
- alita_sdk/runtime/clients/client.py +458 -67
- alita_sdk/runtime/clients/mcp_discovery.py +342 -0
- alita_sdk/runtime/clients/mcp_manager.py +262 -0
- alita_sdk/runtime/clients/sandbox_client.py +352 -0
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +183 -43
- alita_sdk/runtime/langchain/constants.py +647 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
- alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
- alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
- alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
- alita_sdk/runtime/langchain/document_loaders/constants.py +189 -41
- alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
- alita_sdk/runtime/langchain/langraph_agent.py +493 -105
- alita_sdk/runtime/langchain/utils.py +118 -8
- alita_sdk/runtime/llms/preloaded.py +2 -6
- alita_sdk/runtime/models/mcp_models.py +61 -0
- alita_sdk/runtime/skills/__init__.py +91 -0
- alita_sdk/runtime/skills/callbacks.py +498 -0
- alita_sdk/runtime/skills/discovery.py +540 -0
- alita_sdk/runtime/skills/executor.py +610 -0
- alita_sdk/runtime/skills/input_builder.py +371 -0
- alita_sdk/runtime/skills/models.py +330 -0
- alita_sdk/runtime/skills/registry.py +355 -0
- alita_sdk/runtime/skills/skill_runner.py +330 -0
- alita_sdk/runtime/toolkits/__init__.py +28 -0
- alita_sdk/runtime/toolkits/application.py +14 -4
- alita_sdk/runtime/toolkits/artifact.py +25 -9
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +782 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/skill_router.py +238 -0
- alita_sdk/runtime/toolkits/subgraph.py +11 -6
- alita_sdk/runtime/toolkits/tools.py +314 -70
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +24 -0
- alita_sdk/runtime/tools/application.py +16 -4
- alita_sdk/runtime/tools/artifact.py +367 -33
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +100 -4
- alita_sdk/runtime/tools/graph.py +81 -0
- alita_sdk/runtime/tools/image_generation.py +218 -0
- alita_sdk/runtime/tools/llm.py +1032 -177
- alita_sdk/runtime/tools/loop.py +3 -1
- alita_sdk/runtime/tools/loop_output.py +3 -1
- alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
- alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
- alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
- alita_sdk/runtime/tools/planning/__init__.py +36 -0
- alita_sdk/runtime/tools/planning/models.py +246 -0
- alita_sdk/runtime/tools/planning/wrapper.py +607 -0
- alita_sdk/runtime/tools/router.py +2 -1
- alita_sdk/runtime/tools/sandbox.py +375 -0
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +69 -65
- alita_sdk/runtime/tools/vectorstore_base.py +163 -90
- alita_sdk/runtime/utils/AlitaCallback.py +137 -21
- alita_sdk/runtime/utils/constants.py +5 -1
- alita_sdk/runtime/utils/mcp_client.py +492 -0
- alita_sdk/runtime/utils/mcp_oauth.py +361 -0
- alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
- alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
- alita_sdk/runtime/utils/streamlit.py +41 -14
- alita_sdk/runtime/utils/toolkit_utils.py +28 -9
- alita_sdk/runtime/utils/utils.py +48 -0
- alita_sdk/tools/__init__.py +135 -37
- alita_sdk/tools/ado/__init__.py +2 -2
- alita_sdk/tools/ado/repos/__init__.py +16 -19
- alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
- alita_sdk/tools/ado/test_plan/__init__.py +27 -8
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
- alita_sdk/tools/ado/wiki/__init__.py +28 -12
- alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
- alita_sdk/tools/ado/work_item/__init__.py +28 -12
- alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
- alita_sdk/tools/advanced_jira_mining/__init__.py +13 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +15 -11
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +14 -8
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +454 -110
- alita_sdk/tools/bitbucket/__init__.py +28 -19
- alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
- alita_sdk/tools/browser/__init__.py +41 -16
- alita_sdk/tools/browser/crawler.py +3 -1
- alita_sdk/tools/browser/utils.py +15 -6
- alita_sdk/tools/carrier/__init__.py +18 -17
- alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
- alita_sdk/tools/carrier/excel_reporter.py +8 -4
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/code/codeparser.py +1 -1
- alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
- alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
- alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
- alita_sdk/tools/chunkers/universal_chunker.py +270 -0
- alita_sdk/tools/cloud/aws/__init__.py +12 -7
- alita_sdk/tools/cloud/azure/__init__.py +12 -7
- alita_sdk/tools/cloud/gcp/__init__.py +12 -7
- alita_sdk/tools/cloud/k8s/__init__.py +12 -7
- alita_sdk/tools/code/linter/__init__.py +10 -8
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +21 -13
- alita_sdk/tools/code_indexer_toolkit.py +199 -0
- alita_sdk/tools/confluence/__init__.py +22 -14
- alita_sdk/tools/confluence/api_wrapper.py +197 -58
- alita_sdk/tools/confluence/loader.py +14 -2
- alita_sdk/tools/custom_open_api/__init__.py +12 -5
- alita_sdk/tools/elastic/__init__.py +11 -8
- alita_sdk/tools/elitea_base.py +546 -64
- alita_sdk/tools/figma/__init__.py +60 -11
- alita_sdk/tools/figma/api_wrapper.py +1400 -167
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +18 -17
- alita_sdk/tools/github/api_wrapper.py +9 -26
- alita_sdk/tools/github/github_client.py +81 -12
- alita_sdk/tools/github/schemas.py +2 -1
- alita_sdk/tools/github/tool.py +5 -1
- alita_sdk/tools/gitlab/__init__.py +19 -13
- alita_sdk/tools/gitlab/api_wrapper.py +256 -80
- alita_sdk/tools/gitlab_org/__init__.py +14 -10
- alita_sdk/tools/google/bigquery/__init__.py +14 -13
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +21 -11
- alita_sdk/tools/jira/__init__.py +22 -11
- alita_sdk/tools/jira/api_wrapper.py +315 -168
- alita_sdk/tools/keycloak/__init__.py +11 -8
- alita_sdk/tools/localgit/__init__.py +9 -3
- alita_sdk/tools/localgit/local_git.py +62 -54
- alita_sdk/tools/localgit/tool.py +5 -1
- alita_sdk/tools/memory/__init__.py +38 -14
- alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
- alita_sdk/tools/ocr/__init__.py +11 -8
- alita_sdk/tools/openapi/__init__.py +491 -106
- alita_sdk/tools/openapi/api_wrapper.py +1357 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +20 -12
- alita_sdk/tools/pandas/api_wrapper.py +40 -45
- alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
- alita_sdk/tools/postman/__init__.py +11 -11
- alita_sdk/tools/postman/api_wrapper.py +19 -8
- alita_sdk/tools/postman/postman_analysis.py +8 -1
- alita_sdk/tools/pptx/__init__.py +11 -10
- alita_sdk/tools/qtest/__init__.py +22 -14
- alita_sdk/tools/qtest/api_wrapper.py +1784 -88
- alita_sdk/tools/rally/__init__.py +13 -10
- alita_sdk/tools/report_portal/__init__.py +23 -16
- alita_sdk/tools/salesforce/__init__.py +22 -16
- alita_sdk/tools/servicenow/__init__.py +21 -16
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +17 -14
- alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
- alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
- alita_sdk/tools/sharepoint/utils.py +8 -2
- alita_sdk/tools/slack/__init__.py +13 -8
- alita_sdk/tools/sql/__init__.py +22 -19
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- alita_sdk/tools/testio/__init__.py +21 -13
- alita_sdk/tools/testrail/__init__.py +13 -11
- alita_sdk/tools/testrail/api_wrapper.py +214 -46
- alita_sdk/tools/utils/__init__.py +28 -4
- alita_sdk/tools/utils/content_parser.py +241 -55
- alita_sdk/tools/utils/text_operations.py +254 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
- alita_sdk/tools/xray/__init__.py +18 -14
- alita_sdk/tools/xray/api_wrapper.py +58 -113
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +12 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +16 -9
- alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
- alita_sdk/tools/zephyr_essential/__init__.py +16 -10
- alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
- alita_sdk/tools/zephyr_essential/client.py +6 -4
- alita_sdk/tools/zephyr_scale/__init__.py +13 -8
- alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
- alita_sdk/tools/zephyr_squad/__init__.py +12 -7
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/METADATA +184 -37
- alita_sdk-0.3.584.dist-info/RECORD +452 -0
- alita_sdk-0.3.584.dist-info/entry_points.txt +2 -0
- alita_sdk/tools/bitbucket/tools.py +0 -304
- alita_sdk-0.3.257.dist-info/RECORD +0 -343
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/top_level.txt +0 -0
|
@@ -1,127 +1,512 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
1
4
|
import json
|
|
2
|
-
import re
|
|
3
5
|
import logging
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
from
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
9
|
+
from urllib.parse import urlparse
|
|
10
|
+
|
|
11
|
+
from langchain_core.tools import BaseTool, BaseToolkit
|
|
12
|
+
from pydantic import BaseModel, ConfigDict, Field, create_model
|
|
13
|
+
import requests
|
|
14
|
+
import yaml
|
|
7
15
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
16
|
+
from .api_wrapper import _get_base_url_from_spec, build_wrapper
|
|
17
|
+
from .tool import OpenApiAction
|
|
18
|
+
from ..elitea_base import filter_missconfigured_index_tools
|
|
19
|
+
from ...configurations.openapi import OpenApiConfiguration
|
|
20
|
+
from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
10
21
|
|
|
11
22
|
logger = logging.getLogger(__name__)
|
|
12
23
|
|
|
13
|
-
name =
|
|
24
|
+
name = 'openapi'
|
|
14
25
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
# Module-level token cache: {cache_key: (access_token, expires_at_timestamp)}
|
|
27
|
+
# Protected by _oauth_token_cache_lock for thread-safe access
|
|
28
|
+
_oauth_token_cache: Dict[str, Tuple[str, float]] = {}
|
|
29
|
+
_oauth_token_cache_lock = threading.Lock()
|
|
30
|
+
|
|
31
|
+
# Token expiry buffer in seconds (refresh 60 seconds before actual expiry)
|
|
32
|
+
_TOKEN_EXPIRY_BUFFER = 60
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _get_oauth_cache_key(client_id: str, token_url: str, scope: Optional[str]) -> str:
|
|
36
|
+
"""Generate a cache key for OAuth tokens."""
|
|
37
|
+
return f"{client_id}:{token_url}:{scope or ''}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _get_cached_token(cache_key: str) -> Optional[str]:
|
|
41
|
+
"""Get a cached token if it exists and is not expired. Thread-safe."""
|
|
42
|
+
with _oauth_token_cache_lock:
|
|
43
|
+
if cache_key not in _oauth_token_cache:
|
|
44
|
+
return None
|
|
45
|
+
token, expires_at = _oauth_token_cache[cache_key]
|
|
46
|
+
if time.time() >= expires_at - _TOKEN_EXPIRY_BUFFER:
|
|
47
|
+
# Token expired or about to expire
|
|
48
|
+
del _oauth_token_cache[cache_key]
|
|
49
|
+
return None
|
|
50
|
+
return token
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _cache_token(cache_key: str, token: str, expires_in: Optional[int]) -> None:
|
|
54
|
+
"""Cache a token with its expiry time. Thread-safe."""
|
|
55
|
+
# Default to 1 hour if expires_in not provided
|
|
56
|
+
expires_in = expires_in or 3600
|
|
57
|
+
expires_at = time.time() + expires_in
|
|
58
|
+
with _oauth_token_cache_lock:
|
|
59
|
+
_oauth_token_cache[cache_key] = (token, expires_at)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _obtain_oauth_token(
|
|
63
|
+
client_id: str,
|
|
64
|
+
client_secret: str,
|
|
65
|
+
token_url: str,
|
|
66
|
+
scope: Optional[str] = None,
|
|
67
|
+
method: str = 'default',
|
|
68
|
+
timeout: int = 30,
|
|
69
|
+
) -> Tuple[str, Optional[str]]:
|
|
70
|
+
"""
|
|
71
|
+
Obtain an OAuth2 access token using client credentials flow.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
client_id: OAuth client ID
|
|
75
|
+
client_secret: OAuth client secret
|
|
76
|
+
token_url: OAuth token endpoint URL
|
|
77
|
+
scope: Optional OAuth scope(s), space-separated if multiple
|
|
78
|
+
method: Token exchange method - 'default' (POST body) or 'Basic' (Basic auth header)
|
|
79
|
+
timeout: Request timeout in seconds
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Tuple of (access_token, error_message)
|
|
83
|
+
On success: (token, None)
|
|
84
|
+
On failure: (None, error_message)
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
headers = {
|
|
88
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
89
|
+
'Accept': 'application/json',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Build form data
|
|
93
|
+
data: Dict[str, str] = {
|
|
94
|
+
'grant_type': 'client_credentials',
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if method == 'Basic':
|
|
98
|
+
# Use Basic auth header for client credentials
|
|
99
|
+
credentials = f"{client_id}:{client_secret}"
|
|
100
|
+
encoded_credentials = base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
|
|
101
|
+
headers['Authorization'] = f'Basic {encoded_credentials}'
|
|
102
|
+
else:
|
|
103
|
+
# Default: include credentials in POST body
|
|
104
|
+
data['client_id'] = client_id
|
|
105
|
+
data['client_secret'] = client_secret
|
|
106
|
+
|
|
107
|
+
if scope:
|
|
108
|
+
data['scope'] = scope
|
|
109
|
+
|
|
110
|
+
# Log only the domain to avoid exposing sensitive path parameters (e.g., tenant IDs)
|
|
111
|
+
token_domain = urlparse(token_url).netloc or 'unknown'
|
|
112
|
+
logger.debug(f"OAuth token request to {token_domain} using method '{method}'")
|
|
113
|
+
|
|
114
|
+
response = requests.post(
|
|
115
|
+
token_url,
|
|
116
|
+
headers=headers,
|
|
117
|
+
data=data,
|
|
118
|
+
timeout=timeout,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if response.status_code == 200:
|
|
122
|
+
try:
|
|
123
|
+
token_data = response.json()
|
|
124
|
+
access_token = token_data.get('access_token')
|
|
125
|
+
if not access_token:
|
|
126
|
+
return None, "OAuth response did not contain 'access_token'"
|
|
127
|
+
|
|
128
|
+
# Cache the token
|
|
129
|
+
cache_key = _get_oauth_cache_key(client_id, token_url, scope)
|
|
130
|
+
expires_in = token_data.get('expires_in')
|
|
131
|
+
_cache_token(cache_key, access_token, expires_in)
|
|
132
|
+
|
|
133
|
+
logger.debug(f"OAuth token obtained successfully (expires_in: {expires_in})")
|
|
134
|
+
return access_token, None
|
|
135
|
+
except json.JSONDecodeError as e:
|
|
136
|
+
return None, f"Failed to parse OAuth token response as JSON: {e}"
|
|
137
|
+
|
|
138
|
+
# Handle error responses
|
|
139
|
+
error_msg = f"OAuth token request failed with status {response.status_code}"
|
|
140
|
+
try:
|
|
141
|
+
error_data = response.json()
|
|
142
|
+
if 'error' in error_data:
|
|
143
|
+
error_msg = f"{error_msg}: {error_data.get('error')}"
|
|
144
|
+
if 'error_description' in error_data:
|
|
145
|
+
error_msg = f"{error_msg} - {error_data.get('error_description')}"
|
|
146
|
+
except Exception:
|
|
147
|
+
if response.text:
|
|
148
|
+
error_msg = f"{error_msg}: {response.text[:500]}"
|
|
149
|
+
|
|
150
|
+
return None, error_msg
|
|
151
|
+
|
|
152
|
+
except requests.exceptions.Timeout:
|
|
153
|
+
return None, f"OAuth token request to {token_url} timed out"
|
|
154
|
+
except requests.exceptions.ConnectionError as e:
|
|
155
|
+
return None, f"Failed to connect to OAuth token endpoint {token_url}: {e}"
|
|
156
|
+
except requests.exceptions.RequestException as e:
|
|
157
|
+
return None, f"OAuth token request failed: {e}"
|
|
158
|
+
except Exception as e:
|
|
159
|
+
return None, f"Unexpected error during OAuth token exchange: {e}"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _secret_to_str(value: Any) -> Optional[str]:
|
|
163
|
+
"""Convert a secret value to string, handling SecretStr and other types."""
|
|
164
|
+
if value is None:
|
|
165
|
+
return None
|
|
166
|
+
if hasattr(value, 'get_secret_value'):
|
|
167
|
+
try:
|
|
168
|
+
value = value.get_secret_value()
|
|
169
|
+
except Exception:
|
|
170
|
+
pass
|
|
171
|
+
if isinstance(value, str):
|
|
172
|
+
return value
|
|
173
|
+
return str(value)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _get_oauth_access_token(settings: Dict[str, Any]) -> Tuple[Optional[str], Optional[str]]:
|
|
177
|
+
"""
|
|
178
|
+
Get an OAuth access token from settings, using cache if available.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
settings: Dictionary containing OAuth configuration
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Tuple of (access_token, error_message)
|
|
185
|
+
On success: (token, None)
|
|
186
|
+
On failure: (None, error_message)
|
|
187
|
+
If OAuth not configured: (None, None)
|
|
188
|
+
"""
|
|
189
|
+
client_id = settings.get('client_id')
|
|
190
|
+
client_secret = _secret_to_str(settings.get('client_secret'))
|
|
191
|
+
token_url = settings.get('token_url')
|
|
192
|
+
|
|
193
|
+
# Check if OAuth is configured
|
|
194
|
+
if not client_id or not client_secret or not token_url:
|
|
195
|
+
return None, None # OAuth not configured
|
|
196
|
+
|
|
197
|
+
scope = settings.get('scope')
|
|
198
|
+
method = settings.get('method', 'default') or 'default'
|
|
199
|
+
|
|
200
|
+
# Try to get cached token
|
|
201
|
+
cache_key = _get_oauth_cache_key(client_id, token_url, scope)
|
|
202
|
+
cached_token = _get_cached_token(cache_key)
|
|
203
|
+
if cached_token:
|
|
204
|
+
logger.debug("Using cached OAuth token")
|
|
205
|
+
return cached_token, None
|
|
206
|
+
|
|
207
|
+
# Obtain new token
|
|
208
|
+
return _obtain_oauth_token(
|
|
209
|
+
client_id=client_id,
|
|
210
|
+
client_secret=client_secret,
|
|
211
|
+
token_url=token_url,
|
|
212
|
+
scope=scope,
|
|
213
|
+
method=method,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def get_toolkit(tool) -> BaseToolkit:
|
|
218
|
+
settings = tool.get('settings', {}) or {}
|
|
219
|
+
# Extract selected_tools separately to avoid duplicate keyword argument when unpacking **settings
|
|
220
|
+
selected_tools = settings.get('selected_tools', [])
|
|
221
|
+
# Filter out selected_tools from settings to prevent "got multiple values for keyword argument"
|
|
222
|
+
filtered_settings = {k: v for k, v in settings.items() if k != 'selected_tools'}
|
|
28
223
|
return AlitaOpenAPIToolkit.get_toolkit(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
224
|
+
selected_tools=selected_tools,
|
|
225
|
+
toolkit_name=tool.get('toolkit_name'),
|
|
226
|
+
**filtered_settings,
|
|
65
227
|
)
|
|
66
228
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
229
|
+
|
|
230
|
+
def get_tools(tool):
|
|
231
|
+
return get_toolkit(tool).get_tools()
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def get_toolkit_available_tools(settings: dict) -> dict:
|
|
235
|
+
"""Return instance-dependent tool list + per-tool args JSON schemas.
|
|
236
|
+
|
|
237
|
+
This is used by backend services when the UI needs spec-derived tool names
|
|
238
|
+
and input schemas (one tool per operationId). It must be JSON-serializable.
|
|
239
|
+
"""
|
|
240
|
+
if not isinstance(settings, dict):
|
|
241
|
+
settings = {}
|
|
242
|
+
|
|
243
|
+
# Extract and merge openapi_configuration if present (same pattern as get_toolkit)
|
|
244
|
+
openapi_configuration = settings.get('openapi_configuration') or {}
|
|
245
|
+
if hasattr(openapi_configuration, 'model_dump'):
|
|
246
|
+
openapi_configuration = openapi_configuration.model_dump(mode='json')
|
|
247
|
+
if not isinstance(openapi_configuration, dict):
|
|
248
|
+
openapi_configuration = {}
|
|
249
|
+
|
|
250
|
+
# Merge settings with openapi_configuration so api_key, auth_type etc. are at root level
|
|
251
|
+
merged_settings: Dict[str, Any] = {
|
|
252
|
+
**settings,
|
|
253
|
+
**openapi_configuration,
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
spec = merged_settings.get('spec') or merged_settings.get('schema_settings') or merged_settings.get('openapi_spec')
|
|
257
|
+
base_url_override = merged_settings.get('base_url') or merged_settings.get('base_url_override')
|
|
258
|
+
|
|
259
|
+
if not spec or not isinstance(spec, (str, dict)):
|
|
260
|
+
return {"tools": [], "args_schemas": {}, "error": "OpenAPI spec is missing"}
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
headers = _build_headers_from_settings(merged_settings)
|
|
264
|
+
api_wrapper = build_wrapper(
|
|
265
|
+
openapi_spec=spec,
|
|
266
|
+
base_headers=headers,
|
|
267
|
+
base_url_override=base_url_override,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
tool_defs = api_wrapper.get_available_tools(selected_tools=None)
|
|
271
|
+
|
|
272
|
+
tools = []
|
|
273
|
+
args_schemas = {}
|
|
274
|
+
|
|
275
|
+
for tool_def in tool_defs:
|
|
276
|
+
name_val = tool_def.get('name')
|
|
277
|
+
if not isinstance(name_val, str) or not name_val:
|
|
278
|
+
continue
|
|
279
|
+
|
|
280
|
+
desc_val = tool_def.get('description')
|
|
281
|
+
if not isinstance(desc_val, str):
|
|
282
|
+
desc_val = ''
|
|
283
|
+
|
|
284
|
+
tools.append({"name": name_val, "description": desc_val})
|
|
285
|
+
|
|
286
|
+
args_schema = tool_def.get('args_schema')
|
|
287
|
+
if args_schema is None:
|
|
288
|
+
args_schemas[name_val] = {"type": "object", "properties": {}, "required": []}
|
|
289
|
+
continue
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
if hasattr(args_schema, 'model_json_schema'):
|
|
293
|
+
args_schemas[name_val] = args_schema.model_json_schema()
|
|
294
|
+
elif hasattr(args_schema, 'schema'):
|
|
295
|
+
args_schemas[name_val] = args_schema.schema()
|
|
296
|
+
else:
|
|
297
|
+
args_schemas[name_val] = {"type": "object", "properties": {}, "required": []}
|
|
298
|
+
except Exception:
|
|
299
|
+
args_schemas[name_val] = {"type": "object", "properties": {}, "required": []}
|
|
300
|
+
|
|
301
|
+
# Ensure stable JSON-serializability.
|
|
85
302
|
try:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
303
|
+
json.dumps({"tools": tools, "args_schemas": args_schemas})
|
|
304
|
+
except Exception:
|
|
305
|
+
return {"tools": tools, "args_schemas": {}}
|
|
306
|
+
|
|
307
|
+
return {"tools": tools, "args_schemas": args_schemas}
|
|
308
|
+
|
|
309
|
+
except Exception as e: # pylint: disable=W0718
|
|
310
|
+
return {"tools": [], "args_schemas": {}, "error": str(e)}
|
|
90
311
|
|
|
91
312
|
class AlitaOpenAPIToolkit(BaseToolkit):
|
|
92
313
|
request_session: Any #: :meta private:
|
|
93
314
|
tools: List[BaseTool] = []
|
|
94
315
|
|
|
316
|
+
@staticmethod
|
|
317
|
+
def toolkit_config_schema() -> BaseModel:
|
|
318
|
+
# OpenAPI tool names + per-tool args schemas depend on the user-provided spec,
|
|
319
|
+
# so `selected_tools` cannot be an enum here (unlike most toolkits).
|
|
320
|
+
|
|
321
|
+
model = create_model(
|
|
322
|
+
name,
|
|
323
|
+
__config__=ConfigDict(
|
|
324
|
+
extra='ignore',
|
|
325
|
+
json_schema_extra={
|
|
326
|
+
'metadata': {
|
|
327
|
+
'label': 'OpenAPI',
|
|
328
|
+
'icon_url': 'openapi.svg',
|
|
329
|
+
'categories': ['integrations'],
|
|
330
|
+
'extra_categories': ['api', 'openapi', 'swagger'],
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
),
|
|
334
|
+
openapi_configuration=(
|
|
335
|
+
OpenApiConfiguration,
|
|
336
|
+
Field(
|
|
337
|
+
description='OpenAPI credentials configuration',
|
|
338
|
+
json_schema_extra={'configuration_types': ['openapi']},
|
|
339
|
+
),
|
|
340
|
+
),
|
|
341
|
+
base_url=(
|
|
342
|
+
Optional[str],
|
|
343
|
+
Field(
|
|
344
|
+
default=None,
|
|
345
|
+
description=(
|
|
346
|
+
"Optional base URL override (absolute, starting with http:// or https://). "
|
|
347
|
+
"Use this when your OpenAPI spec has no `servers` entry, or when `servers[0].url` "
|
|
348
|
+
"is not absolute (e.g. '/api/v3'). Example: 'https://petstore3.swagger.io'."
|
|
349
|
+
),
|
|
350
|
+
),
|
|
351
|
+
),
|
|
352
|
+
spec=(
|
|
353
|
+
str,
|
|
354
|
+
Field(
|
|
355
|
+
description=(
|
|
356
|
+
'OpenAPI specification (URL or raw JSON/YAML text). '
|
|
357
|
+
'Used to generate per-operation tools (one tool per operationId).'
|
|
358
|
+
),
|
|
359
|
+
json_schema_extra={'ui_component': 'openapi_spec'},
|
|
360
|
+
),
|
|
361
|
+
),
|
|
362
|
+
selected_tools=(
|
|
363
|
+
List[str],
|
|
364
|
+
Field(
|
|
365
|
+
default=[],
|
|
366
|
+
description='Optional list of operationIds to enable. If empty, all operations are enabled.',
|
|
367
|
+
json_schema_extra={'args_schemas': {}},
|
|
368
|
+
),
|
|
369
|
+
),
|
|
370
|
+
)
|
|
371
|
+
return model
|
|
372
|
+
|
|
95
373
|
@classmethod
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if
|
|
104
|
-
|
|
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:
|
|
374
|
+
@filter_missconfigured_index_tools
|
|
375
|
+
def get_toolkit(
|
|
376
|
+
cls,
|
|
377
|
+
selected_tools: list[str] | None = None,
|
|
378
|
+
toolkit_name: Optional[str] = None,
|
|
379
|
+
**kwargs,
|
|
380
|
+
):
|
|
381
|
+
if selected_tools is None:
|
|
382
|
+
selected_tools = []
|
|
111
383
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
384
|
+
tool_names = _coerce_selected_tool_names(selected_tools)
|
|
385
|
+
|
|
386
|
+
openapi_configuration = kwargs.get('openapi_configuration') or {}
|
|
387
|
+
if hasattr(openapi_configuration, 'model_dump'):
|
|
388
|
+
openapi_configuration = openapi_configuration.model_dump(mode='json')
|
|
389
|
+
if not isinstance(openapi_configuration, dict):
|
|
390
|
+
openapi_configuration = {}
|
|
391
|
+
|
|
392
|
+
merged_settings: Dict[str, Any] = {
|
|
393
|
+
**kwargs,
|
|
394
|
+
**openapi_configuration,
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
openapi_spec = merged_settings.get('spec') or merged_settings.get('schema_settings') or merged_settings.get('openapi_spec')
|
|
398
|
+
base_url_override = merged_settings.get('base_url') or merged_settings.get('base_url_override')
|
|
399
|
+
headers = _build_headers_from_settings(merged_settings)
|
|
400
|
+
|
|
401
|
+
api_wrapper = build_wrapper(
|
|
402
|
+
openapi_spec=openapi_spec,
|
|
403
|
+
base_headers=headers,
|
|
404
|
+
base_url_override=base_url_override,
|
|
405
|
+
)
|
|
406
|
+
base_url = _get_base_url_from_spec(api_wrapper.spec)
|
|
407
|
+
|
|
408
|
+
tools: List[BaseTool] = []
|
|
409
|
+
for tool_def in api_wrapper.get_available_tools(selected_tools=tool_names):
|
|
410
|
+
description = tool_def.get('description') or ''
|
|
411
|
+
if toolkit_name:
|
|
412
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
413
|
+
if base_url:
|
|
414
|
+
description = f"{description}\nBase URL: {base_url}"
|
|
415
|
+
description = description[:1000]
|
|
416
|
+
|
|
417
|
+
tools.append(
|
|
418
|
+
OpenApiAction(
|
|
419
|
+
api_wrapper=api_wrapper,
|
|
420
|
+
name=tool_def['name'],
|
|
421
|
+
description=description,
|
|
422
|
+
args_schema=tool_def.get('args_schema'),
|
|
423
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool_def["name"]} if toolkit_name else {TOOL_NAME_META: tool_def["name"]},
|
|
424
|
+
)
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
return cls(request_session=api_wrapper, tools=tools)
|
|
125
428
|
|
|
126
429
|
def get_tools(self):
|
|
127
430
|
return self.tools
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def _coerce_selected_tool_names(selected_tools: Any) -> list[str]:
|
|
434
|
+
if not selected_tools:
|
|
435
|
+
return []
|
|
436
|
+
|
|
437
|
+
if isinstance(selected_tools, list):
|
|
438
|
+
tool_names: List[str] = []
|
|
439
|
+
for item in selected_tools:
|
|
440
|
+
if isinstance(item, str):
|
|
441
|
+
tool_names.append(item)
|
|
442
|
+
elif isinstance(item, dict):
|
|
443
|
+
name_val = item.get('name')
|
|
444
|
+
if isinstance(name_val, str) and name_val.strip():
|
|
445
|
+
tool_names.append(name_val)
|
|
446
|
+
return [t for t in tool_names if t]
|
|
447
|
+
|
|
448
|
+
return []
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def _build_headers_from_settings(settings: Dict[str, Any]) -> Dict[str, str]:
|
|
452
|
+
"""
|
|
453
|
+
Build HTTP headers from settings, supporting API key and OAuth authentication.
|
|
454
|
+
|
|
455
|
+
Authentication priority:
|
|
456
|
+
1. OAuth (client credentials flow) - if client_id, client_secret, and token_url are provided
|
|
457
|
+
2. API Key - if api_key is provided
|
|
458
|
+
3. Legacy authentication structure (for backward compatibility)
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
settings: Dictionary containing authentication settings
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
Dictionary of HTTP headers to include in requests
|
|
465
|
+
"""
|
|
466
|
+
headers: Dict[str, str] = {}
|
|
467
|
+
|
|
468
|
+
# First, try OAuth authentication (client credentials flow)
|
|
469
|
+
# This takes priority because it's more secure and commonly used with modern APIs
|
|
470
|
+
oauth_token, oauth_error = _get_oauth_access_token(settings)
|
|
471
|
+
if oauth_token:
|
|
472
|
+
headers['Authorization'] = f'Bearer {oauth_token}'
|
|
473
|
+
logger.debug("Using OAuth Bearer token for authentication")
|
|
474
|
+
return headers
|
|
475
|
+
elif oauth_error:
|
|
476
|
+
# OAuth was configured but failed - log the error
|
|
477
|
+
# We'll still try API key auth as fallback
|
|
478
|
+
logger.warning(f"OAuth token exchange failed: {oauth_error}")
|
|
479
|
+
|
|
480
|
+
# Legacy structure used by the custom OpenAPI UI
|
|
481
|
+
auth = settings.get('authentication')
|
|
482
|
+
if isinstance(auth, dict) and auth.get('type') == 'api_key':
|
|
483
|
+
auth_settings = auth.get('settings') or {}
|
|
484
|
+
if isinstance(auth_settings, dict):
|
|
485
|
+
auth_type = str(auth_settings.get('auth_type', '')).strip().lower()
|
|
486
|
+
api_key = _secret_to_str(auth_settings.get('api_key'))
|
|
487
|
+
if api_key:
|
|
488
|
+
if auth_type == 'bearer':
|
|
489
|
+
headers['Authorization'] = f'Bearer {api_key}'
|
|
490
|
+
elif auth_type == 'basic':
|
|
491
|
+
headers['Authorization'] = f'Basic {api_key}'
|
|
492
|
+
elif auth_type == 'custom':
|
|
493
|
+
header_name = auth_settings.get('custom_header_name')
|
|
494
|
+
if header_name:
|
|
495
|
+
headers[str(header_name)] = f'{api_key}'
|
|
496
|
+
|
|
497
|
+
# New regular-schema structure (GitHub-style sections) uses flattened fields
|
|
498
|
+
if not headers:
|
|
499
|
+
api_key = _secret_to_str(settings.get('api_key'))
|
|
500
|
+
if api_key:
|
|
501
|
+
auth_type = str(settings.get('auth_type', 'Bearer'))
|
|
502
|
+
auth_type_norm = auth_type.strip().lower()
|
|
503
|
+
if auth_type_norm == 'bearer':
|
|
504
|
+
headers['Authorization'] = f'Bearer {api_key}'
|
|
505
|
+
elif auth_type_norm == 'basic':
|
|
506
|
+
headers['Authorization'] = f'Basic {api_key}'
|
|
507
|
+
elif auth_type_norm == 'custom':
|
|
508
|
+
header_name = settings.get('custom_header_name')
|
|
509
|
+
if header_name:
|
|
510
|
+
headers[str(header_name)] = f'{api_key}'
|
|
511
|
+
|
|
512
|
+
return headers
|