alita-sdk 0.3.351__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.
- 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 +3601 -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 +1256 -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 +64 -8
- alita_sdk/community/inventory/__init__.py +224 -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/visualize.py +1370 -0
- alita_sdk/configurations/bitbucket.py +94 -2
- alita_sdk/configurations/confluence.py +96 -1
- alita_sdk/configurations/gitlab.py +79 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/testrail.py +88 -0
- alita_sdk/configurations/xray.py +93 -0
- alita_sdk/configurations/zephyr_enterprise.py +93 -0
- alita_sdk/configurations/zephyr_essential.py +75 -0
- alita_sdk/runtime/clients/artifact.py +1 -1
- alita_sdk/runtime/clients/client.py +214 -42
- 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 +373 -0
- alita_sdk/runtime/langchain/assistant.py +118 -30
- alita_sdk/runtime/langchain/constants.py +8 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +4 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +41 -12
- alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -1
- alita_sdk/runtime/langchain/document_loaders/constants.py +116 -99
- alita_sdk/runtime/langchain/interfaces/llm_processor.py +2 -2
- alita_sdk/runtime/langchain/langraph_agent.py +307 -71
- alita_sdk/runtime/langchain/utils.py +48 -8
- alita_sdk/runtime/llms/preloaded.py +2 -6
- alita_sdk/runtime/models/mcp_models.py +61 -0
- alita_sdk/runtime/toolkits/__init__.py +26 -0
- alita_sdk/runtime/toolkits/application.py +9 -2
- alita_sdk/runtime/toolkits/artifact.py +18 -6
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +780 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/tools.py +205 -55
- alita_sdk/runtime/toolkits/vectorstore.py +9 -4
- alita_sdk/runtime/tools/__init__.py +11 -3
- alita_sdk/runtime/tools/application.py +7 -0
- alita_sdk/runtime/tools/artifact.py +225 -12
- alita_sdk/runtime/tools/function.py +95 -5
- alita_sdk/runtime/tools/graph.py +10 -4
- alita_sdk/runtime/tools/image_generation.py +212 -0
- alita_sdk/runtime/tools/llm.py +494 -102
- 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 +4 -4
- 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 +180 -79
- alita_sdk/runtime/tools/vectorstore.py +22 -21
- alita_sdk/runtime/tools/vectorstore_base.py +125 -52
- alita_sdk/runtime/utils/AlitaCallback.py +106 -20
- alita_sdk/runtime/utils/mcp_client.py +465 -0
- alita_sdk/runtime/utils/mcp_oauth.py +244 -0
- alita_sdk/runtime/utils/mcp_sse_client.py +405 -0
- alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
- alita_sdk/runtime/utils/streamlit.py +40 -13
- alita_sdk/runtime/utils/toolkit_utils.py +28 -9
- alita_sdk/runtime/utils/utils.py +12 -0
- alita_sdk/tools/__init__.py +77 -33
- alita_sdk/tools/ado/repos/__init__.py +7 -6
- alita_sdk/tools/ado/repos/repos_wrapper.py +11 -11
- alita_sdk/tools/ado/test_plan/__init__.py +7 -7
- alita_sdk/tools/ado/wiki/__init__.py +7 -11
- alita_sdk/tools/ado/wiki/ado_wrapper.py +89 -15
- alita_sdk/tools/ado/work_item/__init__.py +7 -11
- alita_sdk/tools/ado/work_item/ado_wrapper.py +17 -8
- alita_sdk/tools/advanced_jira_mining/__init__.py +8 -7
- alita_sdk/tools/aws/delta_lake/__init__.py +11 -9
- alita_sdk/tools/azure_ai/search/__init__.py +7 -6
- alita_sdk/tools/base_indexer_toolkit.py +345 -70
- alita_sdk/tools/bitbucket/__init__.py +9 -8
- alita_sdk/tools/bitbucket/api_wrapper.py +50 -6
- alita_sdk/tools/browser/__init__.py +4 -4
- alita_sdk/tools/carrier/__init__.py +4 -6
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
- 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 +7 -6
- alita_sdk/tools/cloud/azure/__init__.py +7 -6
- alita_sdk/tools/cloud/gcp/__init__.py +7 -6
- alita_sdk/tools/cloud/k8s/__init__.py +7 -6
- alita_sdk/tools/code/linter/__init__.py +7 -7
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +8 -7
- alita_sdk/tools/code_indexer_toolkit.py +199 -0
- alita_sdk/tools/confluence/__init__.py +9 -8
- alita_sdk/tools/confluence/api_wrapper.py +171 -75
- alita_sdk/tools/confluence/loader.py +10 -0
- alita_sdk/tools/custom_open_api/__init__.py +9 -4
- alita_sdk/tools/elastic/__init__.py +8 -7
- alita_sdk/tools/elitea_base.py +492 -52
- alita_sdk/tools/figma/__init__.py +7 -7
- alita_sdk/tools/figma/api_wrapper.py +2 -1
- alita_sdk/tools/github/__init__.py +9 -9
- alita_sdk/tools/github/api_wrapper.py +9 -26
- alita_sdk/tools/github/github_client.py +62 -2
- alita_sdk/tools/gitlab/__init__.py +8 -8
- alita_sdk/tools/gitlab/api_wrapper.py +135 -33
- alita_sdk/tools/gitlab_org/__init__.py +7 -8
- alita_sdk/tools/google/bigquery/__init__.py +11 -12
- alita_sdk/tools/google_places/__init__.py +8 -7
- alita_sdk/tools/jira/__init__.py +9 -7
- alita_sdk/tools/jira/api_wrapper.py +100 -52
- alita_sdk/tools/keycloak/__init__.py +8 -7
- alita_sdk/tools/localgit/local_git.py +56 -54
- alita_sdk/tools/memory/__init__.py +1 -1
- alita_sdk/tools/non_code_indexer_toolkit.py +3 -2
- alita_sdk/tools/ocr/__init__.py +8 -7
- alita_sdk/tools/openapi/__init__.py +10 -1
- alita_sdk/tools/pandas/__init__.py +8 -7
- alita_sdk/tools/postman/__init__.py +7 -8
- alita_sdk/tools/postman/api_wrapper.py +19 -8
- alita_sdk/tools/postman/postman_analysis.py +8 -1
- alita_sdk/tools/pptx/__init__.py +8 -9
- alita_sdk/tools/qtest/__init__.py +16 -11
- alita_sdk/tools/qtest/api_wrapper.py +1784 -88
- alita_sdk/tools/rally/__init__.py +7 -8
- alita_sdk/tools/report_portal/__init__.py +9 -7
- alita_sdk/tools/salesforce/__init__.py +7 -7
- alita_sdk/tools/servicenow/__init__.py +10 -10
- alita_sdk/tools/sharepoint/__init__.py +7 -6
- alita_sdk/tools/sharepoint/api_wrapper.py +127 -36
- alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
- alita_sdk/tools/sharepoint/utils.py +8 -2
- alita_sdk/tools/slack/__init__.py +7 -6
- alita_sdk/tools/sql/__init__.py +8 -7
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- alita_sdk/tools/testio/__init__.py +7 -6
- alita_sdk/tools/testrail/__init__.py +8 -9
- alita_sdk/tools/utils/__init__.py +26 -4
- alita_sdk/tools/utils/content_parser.py +88 -60
- alita_sdk/tools/utils/text_operations.py +254 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +76 -26
- alita_sdk/tools/xray/__init__.py +9 -7
- alita_sdk/tools/zephyr/__init__.py +7 -6
- alita_sdk/tools/zephyr_enterprise/__init__.py +8 -6
- alita_sdk/tools/zephyr_essential/__init__.py +7 -6
- alita_sdk/tools/zephyr_essential/api_wrapper.py +12 -13
- alita_sdk/tools/zephyr_scale/__init__.py +7 -6
- alita_sdk/tools/zephyr_squad/__init__.py +7 -6
- {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/METADATA +147 -2
- {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/RECORD +206 -130
- alita_sdk-0.3.499.dist-info/entry_points.txt +2 -0
- {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.351.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
|
|
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
|
|
|
@@ -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
|
-
|
|
1360
|
-
"
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
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
|
-
'
|
|
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
|
|
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
|
-
|
|
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
|
|
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',
|
|
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
|
|
alita_sdk/runtime/utils/utils.py
CHANGED
|
@@ -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):
|
|
@@ -11,6 +13,10 @@ class IndexerKeywords(Enum):
|
|
|
11
13
|
UPDATED_ON = 'updated_on'
|
|
12
14
|
CONTENT_IN_BYTES = 'loader_content'
|
|
13
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'
|
|
14
20
|
|
|
15
21
|
# This pattern matches characters that are NOT alphanumeric, underscores, or hyphens
|
|
16
22
|
clean_string_pattern = re.compile(r'[^a-zA-Z0-9_.-]')
|
|
@@ -20,3 +26,9 @@ def clean_string(s: str) -> str:
|
|
|
20
26
|
# Replace these characters with an empty string
|
|
21
27
|
cleaned_string = re.sub(clean_string_pattern, '', s)
|
|
22
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
|
alita_sdk/tools/__init__.py
CHANGED
|
@@ -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')
|
|
@@ -90,62 +115,81 @@ available_count = len(AVAILABLE_TOOLS)
|
|
|
90
115
|
total_attempted = len(AVAILABLE_TOOLS) + len(FAILED_IMPORTS)
|
|
91
116
|
logger.info(f"Tool imports completed: {available_count}/{total_attempted} successful")
|
|
92
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
|
+
|
|
93
126
|
def get_tools(tools_list, alita, llm, store: Optional[BaseStore] = None, *args, **kwargs):
|
|
94
127
|
tools = []
|
|
128
|
+
|
|
95
129
|
for tool in tools_list:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if isinstance(tool_name, str) and tool_name.startswith('_'):
|
|
99
|
-
raise ValueError(f"Tool name '{tool_name}' from toolkit '{tool.get('type', '')}' cannot start with '_'")
|
|
100
|
-
|
|
101
|
-
tool['settings']['alita'] = alita
|
|
102
|
-
tool['settings']['llm'] = llm
|
|
103
|
-
tool['settings']['store'] = store
|
|
104
|
-
tool_type = tool['type']
|
|
130
|
+
toolkit_tools = []
|
|
131
|
+
settings = tool.get('settings')
|
|
105
132
|
|
|
106
|
-
#
|
|
107
|
-
if
|
|
108
|
-
|
|
133
|
+
# Skip tools without settings early
|
|
134
|
+
if not settings:
|
|
135
|
+
logger.warning(f"Tool '{tool.get('type', '')}' has no settings, skipping...")
|
|
136
|
+
continue
|
|
109
137
|
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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 '_'")
|
|
115
143
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
119
149
|
|
|
120
|
-
#
|
|
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))
|
|
121
159
|
elif tool_type in ['ado_repos', 'azure_devops_repos'] and 'ado_repos' in AVAILABLE_TOOLS:
|
|
122
160
|
try:
|
|
123
|
-
|
|
124
|
-
tools.extend(get_tools_func(tool))
|
|
161
|
+
toolkit_tools.extend(AVAILABLE_TOOLS['ado_repos']['get_tools'](tool))
|
|
125
162
|
except Exception as e:
|
|
126
163
|
logger.error(f"Error getting ADO repos tools: {e}")
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
elif
|
|
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"):
|
|
130
175
|
try:
|
|
131
|
-
settings = tool.get("settings", {})
|
|
132
176
|
mod = import_module(settings.pop("module"))
|
|
133
177
|
tkitclass = getattr(mod, settings.pop("class"))
|
|
134
|
-
|
|
135
|
-
get_toolkit_params = tool["settings"].copy()
|
|
178
|
+
get_toolkit_params = settings.copy()
|
|
136
179
|
get_toolkit_params["name"] = tool.get("name")
|
|
137
|
-
#
|
|
138
180
|
toolkit = tkitclass.get_toolkit(**get_toolkit_params)
|
|
139
|
-
|
|
181
|
+
toolkit_tools.extend(toolkit.get_tools())
|
|
140
182
|
except Exception as e:
|
|
141
183
|
logger.error(f"Error in getting custom toolkit: {e}")
|
|
142
|
-
|
|
143
184
|
else:
|
|
144
|
-
# Tool not available or not found
|
|
145
185
|
if tool_type in FAILED_IMPORTS:
|
|
146
186
|
logger.warning(f"Tool '{tool_type}' is not available: {FAILED_IMPORTS[tool_type]}")
|
|
147
187
|
else:
|
|
148
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)
|
|
149
193
|
|
|
150
194
|
return tools
|
|
151
195
|
|
|
@@ -10,7 +10,7 @@ from ....configurations.ado import AdoReposConfiguration
|
|
|
10
10
|
from ....configurations.pgvector import PgVectorConfiguration
|
|
11
11
|
from ...base.tool import BaseAction
|
|
12
12
|
from .repos_wrapper import ReposApiWrapper
|
|
13
|
-
from ...utils import clean_string,
|
|
13
|
+
from ...utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
14
14
|
|
|
15
15
|
name = "ado_repos"
|
|
16
16
|
|
|
@@ -38,12 +38,10 @@ def get_tools(tool):
|
|
|
38
38
|
|
|
39
39
|
class AzureDevOpsReposToolkit(BaseToolkit):
|
|
40
40
|
tools: List[BaseTool] = []
|
|
41
|
-
toolkit_max_length: int = 0
|
|
42
41
|
|
|
43
42
|
@staticmethod
|
|
44
43
|
def toolkit_config_schema() -> BaseModel:
|
|
45
44
|
selected_tools = {x['name']: x['args_schema'].schema() for x in ReposApiWrapper.model_construct().get_available_tools()}
|
|
46
|
-
AzureDevOpsReposToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
47
45
|
m = create_model(
|
|
48
46
|
name,
|
|
49
47
|
ado_repos_configuration=(AdoReposConfiguration, Field(description="Ado Repos configuration", default=None,
|
|
@@ -98,16 +96,19 @@ class AzureDevOpsReposToolkit(BaseToolkit):
|
|
|
98
96
|
azure_devops_repos_wrapper = ReposApiWrapper(**wrapper_payload)
|
|
99
97
|
available_tools = azure_devops_repos_wrapper.get_available_tools()
|
|
100
98
|
tools = []
|
|
101
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
102
99
|
for tool in available_tools:
|
|
103
100
|
if selected_tools:
|
|
104
101
|
if tool["name"] not in selected_tools:
|
|
105
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]
|
|
106
107
|
tools.append(
|
|
107
108
|
BaseAction(
|
|
108
109
|
api_wrapper=azure_devops_repos_wrapper,
|
|
109
|
-
name=
|
|
110
|
-
description=
|
|
110
|
+
name=tool["name"],
|
|
111
|
+
description=description,
|
|
111
112
|
args_schema=tool["args_schema"],
|
|
112
113
|
)
|
|
113
114
|
)
|
|
@@ -24,7 +24,8 @@ from msrest.authentication import BasicAuthentication
|
|
|
24
24
|
from pydantic import Field, PrivateAttr, create_model, model_validator, SecretStr
|
|
25
25
|
|
|
26
26
|
from ..utils import extract_old_new_pairs, generate_diff, get_content_from_generator
|
|
27
|
-
from ...
|
|
27
|
+
from ...code_indexer_toolkit import CodeIndexerToolkit
|
|
28
|
+
from ...utils.available_tools_decorator import extend_with_parent_available_tools
|
|
28
29
|
|
|
29
30
|
logger = logging.getLogger(__name__)
|
|
30
31
|
|
|
@@ -110,8 +111,7 @@ class ArgsSchema(Enum):
|
|
|
110
111
|
Field(
|
|
111
112
|
description=(
|
|
112
113
|
"Branch to be used for read file operation."
|
|
113
|
-
)
|
|
114
|
-
default=None
|
|
114
|
+
)
|
|
115
115
|
),
|
|
116
116
|
)
|
|
117
117
|
)
|
|
@@ -242,7 +242,7 @@ class ArgsSchema(Enum):
|
|
|
242
242
|
)
|
|
243
243
|
|
|
244
244
|
|
|
245
|
-
class ReposApiWrapper(
|
|
245
|
+
class ReposApiWrapper(CodeIndexerToolkit):
|
|
246
246
|
# TODO use ado_repos_configuration fields
|
|
247
247
|
organization_url: Optional[str]
|
|
248
248
|
project: Optional[str]
|
|
@@ -293,7 +293,7 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
|
|
|
293
293
|
if not branch_exists(active_branch):
|
|
294
294
|
raise ToolException(f"The active branch '{active_branch}' does not exist.")
|
|
295
295
|
|
|
296
|
-
return values
|
|
296
|
+
return super().validate_toolkit(values)
|
|
297
297
|
|
|
298
298
|
def _get_commits(self, file_path: str, branch: str, top: int = None) -> List[GitCommitRef]:
|
|
299
299
|
"""
|
|
@@ -644,6 +644,9 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
|
|
|
644
644
|
|
|
645
645
|
return dumps(data)
|
|
646
646
|
|
|
647
|
+
def download_file(self, path):
|
|
648
|
+
return b"".join(self._client.get_item_content(self.repository_id, path=path, project=self.project, download=True))
|
|
649
|
+
|
|
647
650
|
def get_file_content(self, commit_id, path):
|
|
648
651
|
version_descriptor = GitVersionDescriptor(
|
|
649
652
|
version=commit_id, version_type="commit"
|
|
@@ -1171,9 +1174,10 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
|
|
|
1171
1174
|
except Exception as e:
|
|
1172
1175
|
return ToolException(f"Unable to retrieve commits due to error:\n{str(e)}")
|
|
1173
1176
|
|
|
1177
|
+
@extend_with_parent_available_tools
|
|
1174
1178
|
def get_available_tools(self):
|
|
1175
1179
|
"""Return a list of available tools."""
|
|
1176
|
-
|
|
1180
|
+
return [
|
|
1177
1181
|
{
|
|
1178
1182
|
"ref": self.list_branches_in_repo,
|
|
1179
1183
|
"name": "list_branches_in_repo",
|
|
@@ -1264,8 +1268,4 @@ class ReposApiWrapper(BaseCodeToolApiWrapper):
|
|
|
1264
1268
|
"description": self.get_commits.__doc__,
|
|
1265
1269
|
"args_schema": ArgsSchema.GetCommits.value,
|
|
1266
1270
|
},
|
|
1267
|
-
]
|
|
1268
|
-
vector_search_tools = self._get_vector_search_tools()
|
|
1269
|
-
tools.extend(vector_search_tools)
|
|
1270
|
-
|
|
1271
|
-
return tools
|
|
1271
|
+
]
|
|
@@ -10,7 +10,7 @@ from ....configurations.ado import AdoConfiguration
|
|
|
10
10
|
from ....configurations.pgvector import PgVectorConfiguration
|
|
11
11
|
from .test_plan_wrapper import TestPlanApiWrapper
|
|
12
12
|
from ...base.tool import BaseAction
|
|
13
|
-
from ...utils import clean_string,
|
|
13
|
+
from ...utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
name = "azure_devops_plans"
|
|
@@ -19,15 +19,12 @@ name_alias = "ado_plans"
|
|
|
19
19
|
|
|
20
20
|
class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
21
21
|
tools: List[BaseTool] = []
|
|
22
|
-
toolkit_max_length: int = 0
|
|
23
22
|
|
|
24
23
|
@staticmethod
|
|
25
24
|
def toolkit_config_schema() -> BaseModel:
|
|
26
25
|
selected_tools = {x['name']: x['args_schema'].schema() for x in TestPlanApiWrapper.model_construct().get_available_tools()}
|
|
27
|
-
AzureDevOpsPlansToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
28
26
|
m = create_model(
|
|
29
27
|
name_alias,
|
|
30
|
-
name=(str, Field(description="Toolkit name", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': AzureDevOpsPlansToolkit.toolkit_max_length})),
|
|
31
28
|
ado_configuration=(AdoConfiguration, Field(description="Ado configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
32
29
|
limit=(Optional[int], Field(description="ADO plans limit used for limitation of the list with results", default=5)),
|
|
33
30
|
# indexer settings
|
|
@@ -97,16 +94,19 @@ class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
|
97
94
|
azure_devops_api_wrapper = TestPlanApiWrapper(**wrapper_payload)
|
|
98
95
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
99
96
|
tools = []
|
|
100
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
101
97
|
for tool in available_tools:
|
|
102
98
|
if selected_tools:
|
|
103
99
|
if tool["name"] not in selected_tools:
|
|
104
100
|
continue
|
|
105
101
|
print(tool)
|
|
102
|
+
description = tool["description"] + f"\nADO instance: {azure_devops_api_wrapper.organization_url}"
|
|
103
|
+
if toolkit_name:
|
|
104
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
105
|
+
description = description[:1000]
|
|
106
106
|
tools.append(BaseAction(
|
|
107
107
|
api_wrapper=azure_devops_api_wrapper,
|
|
108
|
-
name=
|
|
109
|
-
description=
|
|
108
|
+
name=tool["name"],
|
|
109
|
+
description=description,
|
|
110
110
|
args_schema=tool["args_schema"]
|
|
111
111
|
))
|
|
112
112
|
return cls(tools=tools)
|