alita-sdk 0.3.379__py3-none-any.whl → 0.3.627__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 +156 -0
- alita_sdk/cli/agent_loader.py +245 -0
- alita_sdk/cli/agent_ui.py +228 -0
- alita_sdk/cli/agents.py +3113 -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/testcases/__init__.py +94 -0
- alita_sdk/cli/testcases/data_generation.py +119 -0
- alita_sdk/cli/testcases/discovery.py +96 -0
- alita_sdk/cli/testcases/executor.py +84 -0
- alita_sdk/cli/testcases/logger.py +85 -0
- alita_sdk/cli/testcases/parser.py +172 -0
- alita_sdk/cli/testcases/prompts.py +91 -0
- alita_sdk/cli/testcases/reporting.py +125 -0
- alita_sdk/cli/testcases/setup.py +108 -0
- alita_sdk/cli/testcases/test_runner.py +282 -0
- alita_sdk/cli/testcases/utils.py +39 -0
- alita_sdk/cli/testcases/validation.py +90 -0
- alita_sdk/cli/testcases/workflow.py +196 -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 +1 -1
- alita_sdk/configurations/ado.py +141 -20
- alita_sdk/configurations/bitbucket.py +94 -2
- alita_sdk/configurations/confluence.py +130 -1
- alita_sdk/configurations/figma.py +76 -0
- alita_sdk/configurations/gitlab.py +91 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/openapi.py +329 -0
- alita_sdk/configurations/qtest.py +72 -1
- alita_sdk/configurations/report_portal.py +96 -0
- alita_sdk/configurations/sharepoint.py +148 -0
- alita_sdk/configurations/testio.py +83 -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 +3 -3
- alita_sdk/runtime/clients/client.py +388 -46
- 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 +8 -21
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +157 -39
- 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 +103 -60
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -4
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
- alita_sdk/runtime/langchain/document_loaders/constants.py +40 -19
- alita_sdk/runtime/langchain/langraph_agent.py +405 -84
- alita_sdk/runtime/langchain/utils.py +106 -7
- 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 +31 -0
- alita_sdk/runtime/toolkits/application.py +29 -10
- alita_sdk/runtime/toolkits/artifact.py +20 -11
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +783 -0
- alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/skill_router.py +238 -0
- alita_sdk/runtime/toolkits/subgraph.py +251 -6
- alita_sdk/runtime/toolkits/tools.py +356 -69
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +10 -3
- alita_sdk/runtime/tools/application.py +27 -6
- alita_sdk/runtime/tools/artifact.py +511 -28
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +67 -35
- alita_sdk/runtime/tools/graph.py +10 -4
- alita_sdk/runtime/tools/image_generation.py +148 -46
- alita_sdk/runtime/tools/llm.py +1003 -128
- 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 +8 -5
- 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 -4
- alita_sdk/runtime/tools/sandbox.py +65 -48
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +9 -3
- alita_sdk/runtime/tools/vectorstore_base.py +70 -14
- 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/serialization.py +155 -0
- alita_sdk/runtime/utils/streamlit.py +40 -13
- alita_sdk/runtime/utils/toolkit_utils.py +30 -9
- alita_sdk/runtime/utils/utils.py +36 -0
- alita_sdk/tools/__init__.py +134 -35
- alita_sdk/tools/ado/repos/__init__.py +51 -32
- alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
- alita_sdk/tools/ado/test_plan/__init__.py +25 -9
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
- alita_sdk/tools/ado/utils.py +1 -18
- alita_sdk/tools/ado/wiki/__init__.py +25 -12
- alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
- alita_sdk/tools/ado/work_item/__init__.py +26 -13
- alita_sdk/tools/ado/work_item/ado_wrapper.py +73 -11
- alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +11 -8
- alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +271 -84
- alita_sdk/tools/bitbucket/__init__.py +17 -11
- alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
- alita_sdk/tools/browser/__init__.py +5 -4
- alita_sdk/tools/carrier/__init__.py +5 -6
- alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
- alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
- alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
- 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 +10 -7
- alita_sdk/tools/cloud/azure/__init__.py +10 -7
- alita_sdk/tools/cloud/gcp/__init__.py +10 -7
- alita_sdk/tools/cloud/k8s/__init__.py +10 -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 +11 -8
- alita_sdk/tools/code_indexer_toolkit.py +82 -22
- alita_sdk/tools/confluence/__init__.py +22 -16
- alita_sdk/tools/confluence/api_wrapper.py +107 -30
- 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 +493 -30
- alita_sdk/tools/figma/__init__.py +58 -11
- alita_sdk/tools/figma/api_wrapper.py +1235 -143
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +14 -15
- alita_sdk/tools/github/github_client.py +224 -100
- alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
- alita_sdk/tools/github/schemas.py +14 -5
- alita_sdk/tools/github/tool.py +5 -1
- alita_sdk/tools/github/tool_prompts.py +9 -22
- alita_sdk/tools/gitlab/__init__.py +16 -11
- alita_sdk/tools/gitlab/api_wrapper.py +218 -48
- alita_sdk/tools/gitlab_org/__init__.py +10 -9
- alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
- alita_sdk/tools/google/bigquery/__init__.py +13 -12
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +11 -8
- alita_sdk/tools/google_places/api_wrapper.py +1 -1
- alita_sdk/tools/jira/__init__.py +17 -10
- alita_sdk/tools/jira/api_wrapper.py +92 -41
- 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 +12 -4
- alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
- alita_sdk/tools/ocr/__init__.py +11 -8
- alita_sdk/tools/openapi/__init__.py +491 -106
- alita_sdk/tools/openapi/api_wrapper.py +1368 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +20 -12
- alita_sdk/tools/pandas/api_wrapper.py +38 -25
- alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
- alita_sdk/tools/postman/__init__.py +10 -9
- alita_sdk/tools/pptx/__init__.py +11 -10
- alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
- alita_sdk/tools/qtest/__init__.py +31 -11
- alita_sdk/tools/qtest/api_wrapper.py +2135 -86
- alita_sdk/tools/rally/__init__.py +10 -9
- alita_sdk/tools/rally/api_wrapper.py +1 -1
- alita_sdk/tools/report_portal/__init__.py +12 -8
- alita_sdk/tools/salesforce/__init__.py +10 -8
- alita_sdk/tools/servicenow/__init__.py +17 -15
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +10 -7
- alita_sdk/tools/sharepoint/api_wrapper.py +129 -38
- alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
- alita_sdk/tools/sharepoint/utils.py +8 -2
- alita_sdk/tools/slack/__init__.py +10 -7
- alita_sdk/tools/slack/api_wrapper.py +2 -2
- alita_sdk/tools/sql/__init__.py +12 -9
- alita_sdk/tools/testio/__init__.py +10 -7
- alita_sdk/tools/testrail/__init__.py +11 -10
- alita_sdk/tools/testrail/api_wrapper.py +1 -1
- alita_sdk/tools/utils/__init__.py +9 -4
- alita_sdk/tools/utils/content_parser.py +103 -18
- alita_sdk/tools/utils/text_operations.py +410 -0
- alita_sdk/tools/utils/tool_prompts.py +79 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +30 -13
- alita_sdk/tools/xray/__init__.py +13 -9
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +10 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +11 -7
- alita_sdk/tools/zephyr_essential/__init__.py +10 -7
- alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
- alita_sdk/tools/zephyr_essential/client.py +2 -2
- alita_sdk/tools/zephyr_scale/__init__.py +11 -8
- alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
- alita_sdk/tools/zephyr_squad/__init__.py +10 -7
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +154 -8
- alita_sdk-0.3.627.dist-info/RECORD +468 -0
- alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
- alita_sdk-0.3.379.dist-info/RECORD +0 -360
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
4
|
from langchain_core.tools import ToolException
|
|
4
5
|
from langgraph.store.base import BaseStore
|
|
@@ -8,15 +9,23 @@ from alita_sdk.tools import get_tools as alita_tools
|
|
|
8
9
|
from .application import ApplicationToolkit
|
|
9
10
|
from .artifact import ArtifactToolkit
|
|
10
11
|
from .datasource import DatasourcesToolkit
|
|
12
|
+
from .planning import PlanningToolkit
|
|
11
13
|
from .prompt import PromptToolkit
|
|
12
14
|
from .subgraph import SubgraphToolkit
|
|
13
15
|
from .vectorstore import VectorStoreToolkit
|
|
16
|
+
from .mcp import McpToolkit
|
|
17
|
+
from .mcp_config import McpConfigToolkit, get_mcp_config_toolkit_schemas
|
|
18
|
+
from .skill_router import SkillRouterToolkit
|
|
14
19
|
from ..tools.mcp_server_tool import McpServerTool
|
|
15
20
|
from ..tools.sandbox import SandboxToolkit
|
|
21
|
+
from ..tools.image_generation import ImageGenerationToolkit
|
|
22
|
+
from ..tools.data_analysis import DataAnalysisToolkit
|
|
16
23
|
# Import community tools
|
|
17
24
|
from ...community import get_toolkits as community_toolkits, get_tools as community_tools
|
|
18
25
|
from ...tools.memory import MemoryToolkit
|
|
19
|
-
from
|
|
26
|
+
from ..utils.mcp_oauth import canonical_resource, McpAuthorizationRequired
|
|
27
|
+
from ...tools.utils import clean_string
|
|
28
|
+
from alita_sdk.tools import _inject_toolkit_id
|
|
20
29
|
|
|
21
30
|
logger = logging.getLogger(__name__)
|
|
22
31
|
|
|
@@ -25,82 +34,344 @@ def get_toolkits():
|
|
|
25
34
|
core_toolkits = [
|
|
26
35
|
ArtifactToolkit.toolkit_config_schema(),
|
|
27
36
|
MemoryToolkit.toolkit_config_schema(),
|
|
37
|
+
PlanningToolkit.toolkit_config_schema(),
|
|
28
38
|
VectorStoreToolkit.toolkit_config_schema(),
|
|
29
|
-
SandboxToolkit.toolkit_config_schema()
|
|
39
|
+
SandboxToolkit.toolkit_config_schema(),
|
|
40
|
+
ImageGenerationToolkit.toolkit_config_schema(),
|
|
41
|
+
DataAnalysisToolkit.toolkit_config_schema(),
|
|
42
|
+
McpToolkit.toolkit_config_schema(),
|
|
43
|
+
McpConfigToolkit.toolkit_config_schema(),
|
|
44
|
+
SkillRouterToolkit.toolkit_config_schema()
|
|
30
45
|
]
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
# Add configured MCP servers (stdio and http) as available toolkits
|
|
48
|
+
mcp_config_toolkits = get_mcp_config_toolkit_schemas()
|
|
33
49
|
|
|
50
|
+
return core_toolkits + mcp_config_toolkits + community_toolkits() + alita_toolkits()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_tools(tools_list: list, alita_client=None, llm=None, memory_store: BaseStore = None, debug_mode: Optional[bool] = False, mcp_tokens: Optional[dict] = None, conversation_id: Optional[str] = None, ignored_mcp_servers: Optional[list] = None) -> list:
|
|
54
|
+
# Sanitize tools_list to handle corrupted tool configurations
|
|
55
|
+
sanitized_tools = []
|
|
56
|
+
for tool in tools_list:
|
|
57
|
+
if isinstance(tool, dict):
|
|
58
|
+
# Check for corrupted structure where 'type' and 'name' contain the full tool config
|
|
59
|
+
if 'type' in tool and isinstance(tool['type'], dict):
|
|
60
|
+
# This is a corrupted tool - use the inner dict instead
|
|
61
|
+
logger.warning(f"Detected corrupted tool configuration (type=dict), fixing: {tool}")
|
|
62
|
+
actual_tool = tool['type'] # or tool['name'], they should be the same
|
|
63
|
+
sanitized_tools.append(actual_tool)
|
|
64
|
+
elif 'name' in tool and isinstance(tool['name'], dict):
|
|
65
|
+
# Another corruption pattern where name contains the full config
|
|
66
|
+
logger.warning(f"Detected corrupted tool configuration (name=dict), fixing: {tool}")
|
|
67
|
+
actual_tool = tool['name']
|
|
68
|
+
sanitized_tools.append(actual_tool)
|
|
69
|
+
elif 'type' in tool and isinstance(tool['type'], str):
|
|
70
|
+
# Valid tool configuration
|
|
71
|
+
sanitized_tools.append(tool)
|
|
72
|
+
else:
|
|
73
|
+
# Skip invalid/corrupted tools that can't be fixed
|
|
74
|
+
logger.warning(f"Skipping invalid tool configuration: {tool}")
|
|
75
|
+
else:
|
|
76
|
+
logger.warning(f"Skipping non-dict tool: {tool}")
|
|
77
|
+
# Skip non-dict tools
|
|
34
78
|
|
|
35
|
-
def get_tools(tools_list: list, alita_client, llm, memory_store: BaseStore = None) -> list:
|
|
36
79
|
prompts = []
|
|
37
80
|
tools = []
|
|
81
|
+
unhandled_tools = [] # Track tools not handled by main processing
|
|
38
82
|
|
|
39
|
-
for tool in
|
|
40
|
-
if tool
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
for tool in sanitized_tools:
|
|
84
|
+
# Flag to track if this tool was processed by the main loop
|
|
85
|
+
# Used to prevent double processing by fallback systems
|
|
86
|
+
tool_handled = False
|
|
87
|
+
try:
|
|
88
|
+
if tool['type'] == 'datasource':
|
|
89
|
+
tool_handled = True
|
|
90
|
+
tools.extend(DatasourcesToolkit.get_toolkit(
|
|
91
|
+
alita_client,
|
|
92
|
+
datasource_ids=[int(tool['settings']['datasource_id'])],
|
|
93
|
+
selected_tools=tool['settings']['selected_tools'],
|
|
94
|
+
toolkit_name=tool.get('toolkit_name', '') or tool.get('name', '')
|
|
95
|
+
).get_tools())
|
|
96
|
+
elif tool['type'] == 'application':
|
|
97
|
+
tool_handled = True
|
|
98
|
+
# Check if this is a pipeline to enable PrinterNode filtering
|
|
99
|
+
is_pipeline_subgraph = tool.get('agent_type', '') == 'pipeline'
|
|
100
|
+
|
|
101
|
+
tools.extend(ApplicationToolkit.get_toolkit(
|
|
102
|
+
alita_client,
|
|
103
|
+
application_id=int(tool['settings']['application_id']),
|
|
104
|
+
application_version_id=int(tool['settings']['application_version_id']),
|
|
105
|
+
selected_tools=[],
|
|
106
|
+
ignored_mcp_servers=ignored_mcp_servers,
|
|
107
|
+
is_subgraph=is_pipeline_subgraph, # Pass is_subgraph for pipelines
|
|
108
|
+
mcp_tokens=mcp_tokens
|
|
109
|
+
).get_tools())
|
|
110
|
+
# TODO: deprecate next release (1/15/2026)
|
|
111
|
+
# if is_pipeline_subgraph:
|
|
112
|
+
# # static get_toolkit returns a list of CompiledStateGraph stubs
|
|
113
|
+
# # Pass is_subgraph=True to enable PrinterNode filtering
|
|
114
|
+
# logger.info(f"Processing pipeline as subgraph, will filter PrinterNodes")
|
|
115
|
+
# tools.extend(SubgraphToolkit.get_toolkit(
|
|
116
|
+
# alita_client,
|
|
117
|
+
# application_id=int(tool['settings']['application_id']),
|
|
118
|
+
# application_version_id=int(tool['settings']['application_version_id']),
|
|
119
|
+
# app_api_key=alita_client.auth_token,
|
|
120
|
+
# selected_tools=[],
|
|
121
|
+
# llm=llm,
|
|
122
|
+
# is_subgraph=True # Enable PrinterNode filtering for pipelines used as subgraphs
|
|
123
|
+
# ))
|
|
124
|
+
elif tool['type'] == 'memory':
|
|
125
|
+
tool_handled = True
|
|
126
|
+
tools += MemoryToolkit.get_toolkit(
|
|
127
|
+
namespace=tool['settings'].get('namespace', str(tool['id'])),
|
|
128
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
129
|
+
store=memory_store,
|
|
76
130
|
).get_tools()
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
131
|
+
# TODO: update configuration of internal tools
|
|
132
|
+
elif tool['type'] == 'internal_tool':
|
|
133
|
+
tool_handled = True
|
|
134
|
+
if tool['name'] == 'pyodide':
|
|
135
|
+
tools += SandboxToolkit.get_toolkit(
|
|
136
|
+
stateful=False,
|
|
137
|
+
allow_net=True,
|
|
138
|
+
alita_client=alita_client,
|
|
139
|
+
).get_tools()
|
|
140
|
+
elif tool['name'] == 'image_generation':
|
|
141
|
+
if alita_client and alita_client.model_image_generation:
|
|
142
|
+
tools += ImageGenerationToolkit.get_toolkit(
|
|
143
|
+
client=alita_client,
|
|
144
|
+
).get_tools()
|
|
145
|
+
else:
|
|
146
|
+
logger.warning("Image generation internal tool requested "
|
|
147
|
+
"but no image generation model configured")
|
|
148
|
+
elif tool['name'] == 'planner':
|
|
149
|
+
tools += PlanningToolkit.get_toolkit(
|
|
150
|
+
pgvector_configuration=tool.get('settings', {}).get('pgvector_configuration'),
|
|
151
|
+
conversation_id=conversation_id,
|
|
152
|
+
).get_tools()
|
|
153
|
+
elif tool['name'] == 'data_analysis':
|
|
154
|
+
# Data Analysis internal tool - uses conversation attachment bucket
|
|
155
|
+
settings = tool.get('settings', {})
|
|
156
|
+
bucket_name = settings.get('bucket_name')
|
|
157
|
+
if bucket_name:
|
|
158
|
+
tools += DataAnalysisToolkit.get_toolkit(
|
|
159
|
+
alita_client=alita_client,
|
|
160
|
+
llm=llm,
|
|
161
|
+
bucket_name=bucket_name,
|
|
162
|
+
toolkit_name="Data Analyst",
|
|
163
|
+
).get_tools()
|
|
164
|
+
else:
|
|
165
|
+
logger.warning("Data Analysis internal tool requested "
|
|
166
|
+
"but no bucket_name provided in settings")
|
|
167
|
+
elif tool['type'] == 'artifact':
|
|
168
|
+
tool_handled = True
|
|
169
|
+
toolkit_tools = ArtifactToolkit.get_toolkit(
|
|
170
|
+
client=alita_client,
|
|
171
|
+
bucket=tool['settings']['bucket'],
|
|
172
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
173
|
+
selected_tools=tool['settings'].get('selected_tools', []),
|
|
174
|
+
llm=llm,
|
|
175
|
+
# indexer settings
|
|
176
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
177
|
+
embedding_model=tool['settings'].get('embedding_model'),
|
|
178
|
+
collection_name=f"{tool.get('toolkit_name')}",
|
|
179
|
+
collection_schema=str(tool['settings'].get('id', tool.get('id', ''))),
|
|
180
|
+
).get_tools()
|
|
181
|
+
# Inject toolkit_id for artifact tools as well
|
|
182
|
+
# Pass settings as the tool config since that's where the id field is
|
|
183
|
+
_inject_toolkit_id(tool['settings'], toolkit_tools)
|
|
184
|
+
tools.extend(toolkit_tools)
|
|
185
|
+
|
|
186
|
+
elif tool['type'] == 'vectorstore':
|
|
187
|
+
tool_handled = True
|
|
188
|
+
tools.extend(VectorStoreToolkit.get_toolkit(
|
|
189
|
+
llm=llm,
|
|
190
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
191
|
+
**tool['settings']).get_tools())
|
|
192
|
+
elif tool['type'] == 'planning':
|
|
193
|
+
tool_handled = True
|
|
194
|
+
# Planning toolkit for multi-step task tracking
|
|
195
|
+
settings = tool.get('settings', {})
|
|
196
|
+
|
|
197
|
+
# Check if local mode is enabled (uses filesystem storage, ignores pgvector)
|
|
198
|
+
use_local = settings.get('local', False)
|
|
199
|
+
|
|
200
|
+
if use_local:
|
|
201
|
+
# Local mode - use filesystem storage
|
|
202
|
+
logger.info("Planning toolkit using local filesystem storage (local=true)")
|
|
203
|
+
pgvector_config = {}
|
|
204
|
+
else:
|
|
205
|
+
# Check if explicit connection_string is provided in pgvector_configuration
|
|
206
|
+
explicit_pgvector_config = settings.get('pgvector_configuration', {})
|
|
207
|
+
explicit_connstr = explicit_pgvector_config.get('connection_string') if explicit_pgvector_config else None
|
|
208
|
+
|
|
209
|
+
if explicit_connstr:
|
|
210
|
+
# Use explicitly provided connection string (overrides project secrets)
|
|
211
|
+
logger.info("Using explicit connection_string for planning toolkit")
|
|
212
|
+
pgvector_config = explicit_pgvector_config
|
|
213
|
+
else:
|
|
214
|
+
# Try to fetch pgvector_project_connstr from project secrets
|
|
215
|
+
pgvector_connstr = None
|
|
216
|
+
if alita_client:
|
|
217
|
+
try:
|
|
218
|
+
pgvector_connstr = alita_client.unsecret('pgvector_project_connstr')
|
|
219
|
+
if pgvector_connstr:
|
|
220
|
+
logger.info("Using pgvector_project_connstr for planning toolkit")
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.debug(f"pgvector_project_connstr not available: {e}")
|
|
223
|
+
|
|
224
|
+
pgvector_config = {'connection_string': pgvector_connstr} if pgvector_connstr else {}
|
|
225
|
+
|
|
226
|
+
tools.extend(PlanningToolkit.get_toolkit(
|
|
227
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
228
|
+
selected_tools=settings.get('selected_tools', []),
|
|
229
|
+
pgvector_configuration=pgvector_config,
|
|
230
|
+
conversation_id=conversation_id or settings.get('conversation_id'),
|
|
231
|
+
).get_tools())
|
|
232
|
+
elif tool['type'] == 'mcp':
|
|
233
|
+
tool_handled = True
|
|
234
|
+
# remote mcp tool initialization with token injection
|
|
235
|
+
settings = dict(tool['settings'])
|
|
236
|
+
url = settings.get('url')
|
|
237
|
+
|
|
238
|
+
# Check if this MCP server should be ignored (user chose to continue without auth)
|
|
239
|
+
if ignored_mcp_servers and url:
|
|
240
|
+
canonical_url = canonical_resource(url)
|
|
241
|
+
if canonical_url in ignored_mcp_servers or url in ignored_mcp_servers:
|
|
242
|
+
logger.info(f"[MCP Auth] Skipping ignored MCP server: {url}")
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
headers = settings.get('headers')
|
|
246
|
+
token_data = None
|
|
247
|
+
session_id = None
|
|
248
|
+
if mcp_tokens and url:
|
|
249
|
+
canonical_url = canonical_resource(url)
|
|
250
|
+
logger.info(f"[MCP Auth] Looking for token for URL: {url}")
|
|
251
|
+
logger.info(f"[MCP Auth] Canonical URL: {canonical_url}")
|
|
252
|
+
logger.info(f"[MCP Auth] Available tokens: {list(mcp_tokens.keys())}")
|
|
253
|
+
token_data = mcp_tokens.get(canonical_url)
|
|
254
|
+
if token_data:
|
|
255
|
+
logger.info(f"[MCP Auth] Found token data for {canonical_url}")
|
|
256
|
+
# Handle both old format (string) and new format (dict with access_token and session_id)
|
|
257
|
+
if isinstance(token_data, dict):
|
|
258
|
+
access_token = token_data.get('access_token')
|
|
259
|
+
session_id = token_data.get('session_id')
|
|
260
|
+
logger.info(f"[MCP Auth] Token data: access_token={'present' if access_token else 'missing'}, session_id={session_id or 'none'}")
|
|
261
|
+
else:
|
|
262
|
+
# Backward compatibility: treat as plain token string
|
|
263
|
+
access_token = token_data
|
|
264
|
+
logger.info(f"[MCP Auth] Using legacy token format (string)")
|
|
265
|
+
else:
|
|
266
|
+
access_token = None
|
|
267
|
+
logger.warning(f"[MCP Auth] No token found for {canonical_url}")
|
|
268
|
+
else:
|
|
269
|
+
access_token = None
|
|
270
|
+
|
|
271
|
+
if access_token:
|
|
272
|
+
merged_headers = dict(headers) if headers else {}
|
|
273
|
+
merged_headers.setdefault('Authorization', f'Bearer {access_token}')
|
|
274
|
+
settings['headers'] = merged_headers
|
|
275
|
+
logger.info(f"[MCP Auth] Added Authorization header for {url}")
|
|
276
|
+
|
|
277
|
+
# Pass session_id to MCP toolkit if available
|
|
278
|
+
if session_id:
|
|
279
|
+
settings['session_id'] = session_id
|
|
280
|
+
logger.info(f"[MCP Auth] Passing session_id to toolkit: {session_id}")
|
|
281
|
+
tools.extend(McpToolkit.get_toolkit(
|
|
282
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
283
|
+
client=alita_client,
|
|
284
|
+
**settings).get_tools())
|
|
285
|
+
elif tool['type'] == 'skill_router':
|
|
286
|
+
tool_handled = True
|
|
287
|
+
# Skills Registry Router Toolkit
|
|
288
|
+
logger.info(f"Processing skill_router toolkit: {tool}")
|
|
289
|
+
try:
|
|
290
|
+
settings = tool.get('settings', {})
|
|
291
|
+
toolkit_name = tool.get('toolkit_name', '')
|
|
292
|
+
selected_tools = settings.get('selected_tools', [])
|
|
293
|
+
|
|
294
|
+
toolkit_tools = SkillRouterToolkit.get_toolkit(
|
|
295
|
+
client=alita_client,
|
|
296
|
+
llm=llm,
|
|
297
|
+
toolkit_name=toolkit_name,
|
|
298
|
+
selected_tools=selected_tools,
|
|
299
|
+
**settings
|
|
300
|
+
).get_tools()
|
|
301
|
+
|
|
302
|
+
tools.extend(toolkit_tools)
|
|
303
|
+
logger.info(f"✅ Successfully added {len(toolkit_tools)} tools from SkillRouterToolkit")
|
|
304
|
+
except Exception as e:
|
|
305
|
+
logger.error(f"❌ Failed to initialize SkillRouterToolkit: {e}")
|
|
306
|
+
raise
|
|
307
|
+
elif tool['type'] == 'mcp_config' or tool['type'].startswith('mcp_'):
|
|
308
|
+
tool_handled = True
|
|
309
|
+
# MCP Config toolkit - pre-configured MCP servers (stdio or http)
|
|
310
|
+
# Handle both explicit 'mcp_config' type and dynamic names like 'mcp_playwright'
|
|
311
|
+
logger.info(f"Processing mcp_config toolkit: {tool}")
|
|
312
|
+
try:
|
|
313
|
+
settings = tool.get('settings', {})
|
|
314
|
+
|
|
315
|
+
# Server name can come from settings or be extracted from type name
|
|
316
|
+
server_name = settings.get('server_name')
|
|
317
|
+
if not server_name and tool['type'].startswith('mcp_') and tool['type'] != 'mcp_config':
|
|
318
|
+
# Extract server name from type (e.g., 'mcp_playwright' -> 'playwright')
|
|
319
|
+
server_name = tool['type'][4:] # Remove 'mcp_' prefix
|
|
320
|
+
|
|
321
|
+
if not server_name:
|
|
322
|
+
logger.error(f"❌ No server_name found for mcp_config toolkit: {tool}")
|
|
323
|
+
continue
|
|
324
|
+
|
|
325
|
+
toolkit_name = tool.get('toolkit_name', '') or server_name
|
|
326
|
+
selected_tools = settings.get('selected_tools', [])
|
|
327
|
+
excluded_tools = settings.get('excluded_tools', [])
|
|
328
|
+
|
|
329
|
+
# Get server config (may be in settings or from global config)
|
|
330
|
+
server_config = settings.get('server_config')
|
|
331
|
+
|
|
332
|
+
toolkit_tools = McpConfigToolkit.get_toolkit(
|
|
333
|
+
server_name=server_name,
|
|
334
|
+
server_config=server_config,
|
|
335
|
+
user_config=settings,
|
|
336
|
+
selected_tools=selected_tools if selected_tools else None,
|
|
337
|
+
excluded_tools=excluded_tools if excluded_tools else None,
|
|
338
|
+
toolkit_name=toolkit_name,
|
|
339
|
+
client=alita_client,
|
|
340
|
+
).get_tools()
|
|
341
|
+
|
|
342
|
+
tools.extend(toolkit_tools)
|
|
343
|
+
logger.info(f"✅ Successfully added {len(toolkit_tools)} tools from McpConfigToolkit ({server_name})")
|
|
344
|
+
except Exception as e:
|
|
345
|
+
logger.error(f"❌ Failed to initialize McpConfigToolkit: {e}")
|
|
346
|
+
if not debug_mode:
|
|
347
|
+
raise
|
|
348
|
+
except McpAuthorizationRequired:
|
|
349
|
+
# Re-raise auth required exceptions directly
|
|
350
|
+
raise
|
|
351
|
+
except Exception as e:
|
|
352
|
+
logger.error(f"Error initializing toolkit for tool '{tool.get('name', 'unknown')}': {e}", exc_info=True)
|
|
353
|
+
if debug_mode:
|
|
354
|
+
logger.info("Skipping tool initialization error due to debug mode.")
|
|
355
|
+
continue
|
|
356
|
+
else:
|
|
357
|
+
raise ToolException(f"Error initializing toolkit for tool '{tool.get('name', 'unknown')}': {e}")
|
|
358
|
+
|
|
359
|
+
# Track unhandled tools (make a copy to avoid reference issues)
|
|
360
|
+
if not tool_handled:
|
|
361
|
+
# Ensure we only add valid tool configurations to unhandled_tools
|
|
362
|
+
if isinstance(tool, dict) and 'type' in tool and isinstance(tool['type'], str):
|
|
363
|
+
unhandled_tools.append(dict(tool))
|
|
364
|
+
|
|
95
365
|
if len(prompts) > 0:
|
|
96
366
|
tools += PromptToolkit.get_toolkit(alita_client, prompts).get_tools()
|
|
97
|
-
|
|
98
|
-
# Add community tools
|
|
99
|
-
tools += community_tools(
|
|
100
|
-
# Add alita tools
|
|
101
|
-
tools += alita_tools(
|
|
102
|
-
# Add MCP tools
|
|
103
|
-
|
|
367
|
+
|
|
368
|
+
# Add community tools (only for unhandled tools)
|
|
369
|
+
tools += community_tools(unhandled_tools, alita_client, llm)
|
|
370
|
+
# Add alita tools (only for unhandled tools)
|
|
371
|
+
tools += alita_tools(unhandled_tools, alita_client, llm, memory_store)
|
|
372
|
+
# Add MCP tools registered via alita-mcp CLI (static registry)
|
|
373
|
+
# Note: Tools with type='mcp' are already handled in main loop above
|
|
374
|
+
tools += _mcp_tools(unhandled_tools, alita_client)
|
|
104
375
|
|
|
105
376
|
# Sanitize tool names to meet OpenAI's function naming requirements
|
|
106
377
|
# tools = _sanitize_tool_names(tools)
|
|
@@ -154,6 +425,10 @@ def _sanitize_tool_names(tools: list) -> list:
|
|
|
154
425
|
|
|
155
426
|
|
|
156
427
|
def _mcp_tools(tools_list, alita):
|
|
428
|
+
"""
|
|
429
|
+
Handle MCP tools registered via alita-mcp CLI (static registry).
|
|
430
|
+
Skips tools with type='mcp' as those are handled by dynamic discovery.
|
|
431
|
+
"""
|
|
157
432
|
try:
|
|
158
433
|
all_available_toolkits = alita.get_mcp_toolkits()
|
|
159
434
|
toolkit_lookup = {tk["name"]: tk for tk in all_available_toolkits}
|
|
@@ -161,6 +436,11 @@ def _mcp_tools(tools_list, alita):
|
|
|
161
436
|
#
|
|
162
437
|
for selected_toolkit in tools_list:
|
|
163
438
|
server_toolkit_name = selected_toolkit['type']
|
|
439
|
+
|
|
440
|
+
# Skip tools with type='mcp' - they're handled by dynamic discovery
|
|
441
|
+
if server_toolkit_name == 'mcp':
|
|
442
|
+
continue
|
|
443
|
+
|
|
164
444
|
toolkit_conf = toolkit_lookup.get(server_toolkit_name)
|
|
165
445
|
#
|
|
166
446
|
if not toolkit_conf:
|
|
@@ -186,11 +466,18 @@ def _mcp_tools(tools_list, alita):
|
|
|
186
466
|
|
|
187
467
|
def _init_single_mcp_tool(server_toolkit_name, toolkit_name, available_tool, alita, toolkit_settings):
|
|
188
468
|
try:
|
|
189
|
-
|
|
190
|
-
tool_name =
|
|
469
|
+
# Use clean tool name without prefix
|
|
470
|
+
tool_name = available_tool["name"]
|
|
471
|
+
# Add toolkit context to description (max 1000 chars)
|
|
472
|
+
toolkit_context = f" [Toolkit: {clean_string(toolkit_name)}]" if toolkit_name else ''
|
|
473
|
+
base_description = f"MCP for a tool '{tool_name}': {available_tool.get('description', '')}"
|
|
474
|
+
description = base_description
|
|
475
|
+
if toolkit_context and len(base_description + toolkit_context) <= 1000:
|
|
476
|
+
description = base_description + toolkit_context
|
|
477
|
+
|
|
191
478
|
return McpServerTool(
|
|
192
479
|
name=tool_name,
|
|
193
|
-
description=
|
|
480
|
+
description=description,
|
|
194
481
|
args_schema=McpServerTool.create_pydantic_model_from_schema(
|
|
195
482
|
available_tool.get("inputSchema", {})
|
|
196
483
|
),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from logging import getLogger
|
|
2
2
|
from typing import Any, List, Literal, Optional
|
|
3
3
|
|
|
4
|
-
from alita_sdk.tools.utils import clean_string
|
|
4
|
+
from alita_sdk.tools.utils import clean_string
|
|
5
5
|
from pydantic import BaseModel, create_model, Field, ConfigDict
|
|
6
6
|
from langchain_core.tools import BaseToolkit, BaseTool
|
|
7
7
|
from alita_sdk.tools.base.tool import BaseAction
|
|
@@ -31,7 +31,8 @@ class VectorStoreToolkit(BaseToolkit):
|
|
|
31
31
|
toolkit_name: Optional[str] = None,
|
|
32
32
|
selected_tools: list[str] = []):
|
|
33
33
|
logger.info("Selected tools: %s", selected_tools)
|
|
34
|
-
|
|
34
|
+
# Use clean toolkit name for context (max 1000 chars in description)
|
|
35
|
+
toolkit_context = f" [Toolkit: {clean_string(toolkit_name)}]" if toolkit_name else ''
|
|
35
36
|
if selected_tools is None:
|
|
36
37
|
selected_tools = []
|
|
37
38
|
tools = []
|
|
@@ -46,11 +47,16 @@ class VectorStoreToolkit(BaseToolkit):
|
|
|
46
47
|
# if selected_tools:
|
|
47
48
|
# if tool["name"] not in selected_tools:
|
|
48
49
|
# continue
|
|
50
|
+
# Add toolkit context to description with character limit
|
|
51
|
+
description = tool["description"]
|
|
52
|
+
if toolkit_context and len(description + toolkit_context) <= 1000:
|
|
53
|
+
description = description + toolkit_context
|
|
49
54
|
tools.append(BaseAction(
|
|
50
55
|
api_wrapper=vectorstore_wrapper,
|
|
51
|
-
name=
|
|
52
|
-
description=
|
|
53
|
-
args_schema=tool["args_schema"]
|
|
56
|
+
name=tool["name"],
|
|
57
|
+
description=description,
|
|
58
|
+
args_schema=tool["args_schema"],
|
|
59
|
+
metadata={"toolkit_name": toolkit_name, "toolkit_type": "vectorstore"} if toolkit_name else {}
|
|
54
60
|
))
|
|
55
61
|
return cls(tools=tools)
|
|
56
62
|
|
|
@@ -5,7 +5,12 @@ This module provides various tools that can be used within LangGraph agents.
|
|
|
5
5
|
|
|
6
6
|
from .sandbox import PyodideSandboxTool, StatefulPyodideSandboxTool, create_sandbox_tool
|
|
7
7
|
from .echo import EchoTool
|
|
8
|
-
from .image_generation import
|
|
8
|
+
from .image_generation import (
|
|
9
|
+
ImageGenerationTool,
|
|
10
|
+
create_image_generation_tool,
|
|
11
|
+
ImageGenerationToolkit
|
|
12
|
+
)
|
|
13
|
+
from .skill_router import SkillRouterWrapper
|
|
9
14
|
|
|
10
15
|
__all__ = [
|
|
11
16
|
"PyodideSandboxTool",
|
|
@@ -13,5 +18,7 @@ __all__ = [
|
|
|
13
18
|
"create_sandbox_tool",
|
|
14
19
|
"EchoTool",
|
|
15
20
|
"ImageGenerationTool",
|
|
16
|
-
"
|
|
17
|
-
|
|
21
|
+
"ImageGenerationToolkit",
|
|
22
|
+
"create_image_generation_tool",
|
|
23
|
+
"SkillRouterWrapper"
|
|
24
|
+
]
|
|
@@ -4,7 +4,7 @@ from ..utils.utils import clean_string
|
|
|
4
4
|
from langchain_core.tools import BaseTool, ToolException
|
|
5
5
|
from langchain_core.messages import BaseMessage, AIMessage, HumanMessage
|
|
6
6
|
from typing import Any, Type, Optional
|
|
7
|
-
from pydantic import create_model,
|
|
7
|
+
from pydantic import create_model, model_validator, BaseModel
|
|
8
8
|
from pydantic.fields import FieldInfo
|
|
9
9
|
from ..langchain.mixedAgentRenderes import convert_message_to_json
|
|
10
10
|
from logging import getLogger
|
|
@@ -41,8 +41,7 @@ def formulate_query(kwargs):
|
|
|
41
41
|
if key not in ("task", "chat_history"):
|
|
42
42
|
result[key] = value
|
|
43
43
|
return result
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
|
|
47
46
|
class Application(BaseTool):
|
|
48
47
|
name: str
|
|
@@ -50,11 +49,26 @@ class Application(BaseTool):
|
|
|
50
49
|
application: Any
|
|
51
50
|
args_schema: Type[BaseModel] = applicationToolSchema
|
|
52
51
|
return_type: str = "str"
|
|
52
|
+
client: Any
|
|
53
|
+
args_runnable: dict = {}
|
|
54
|
+
metadata: dict = {}
|
|
55
|
+
is_subgraph: Optional[bool] = False
|
|
53
56
|
|
|
54
|
-
@
|
|
57
|
+
@model_validator(mode='before')
|
|
55
58
|
@classmethod
|
|
56
|
-
def
|
|
57
|
-
|
|
59
|
+
def preserve_original_name(cls, data: Any) -> Any:
|
|
60
|
+
"""Preserve the original name in metadata before cleaning."""
|
|
61
|
+
if isinstance(data, dict):
|
|
62
|
+
original_name = data.get('name')
|
|
63
|
+
if original_name:
|
|
64
|
+
# Initialize metadata if not present
|
|
65
|
+
if data.get('metadata') is None:
|
|
66
|
+
data['metadata'] = {}
|
|
67
|
+
# Store original name before cleaning
|
|
68
|
+
data['metadata']['original_name'] = original_name
|
|
69
|
+
# Clean the name
|
|
70
|
+
data['name'] = clean_string(original_name)
|
|
71
|
+
return data
|
|
58
72
|
|
|
59
73
|
def invoke(self, input: Any, config: Optional[dict] = None, **kwargs: Any) -> Any:
|
|
60
74
|
"""Override default invoke to preserve all fields, not just args_schema"""
|
|
@@ -66,7 +80,14 @@ class Application(BaseTool):
|
|
|
66
80
|
return self._run(*config, **all_kwargs)
|
|
67
81
|
|
|
68
82
|
def _run(self, *args, **kwargs):
|
|
83
|
+
if self.client and self.args_runnable:
|
|
84
|
+
# Recreate new LanggraphAgentRunnable in order to reflect the current input_mapping (it can be dynamic for pipelines).
|
|
85
|
+
# Actually, for pipelines agent toolkits LanggraphAgentRunnable is created (for LLMNode) before pipeline's schema parsing.
|
|
86
|
+
application_variables = {k: {"name": k, "value": v} for k, v in kwargs.items()}
|
|
87
|
+
self.application = self.client.application(**self.args_runnable, application_variables=application_variables)
|
|
69
88
|
response = self.application.invoke(formulate_query(kwargs))
|
|
89
|
+
if self.is_subgraph:
|
|
90
|
+
return response
|
|
70
91
|
if self.return_type == "str":
|
|
71
92
|
return response["output"]
|
|
72
93
|
else:
|