alita-sdk 0.3.554__py3-none-any.whl → 0.3.602__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/agent_executor.py +2 -1
- alita_sdk/cli/agent_loader.py +34 -4
- alita_sdk/cli/agents.py +433 -203
- alita_sdk/configurations/openapi.py +227 -15
- alita_sdk/runtime/clients/client.py +4 -2
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +61 -11
- alita_sdk/runtime/langchain/constants.py +419 -171
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +4 -2
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
- alita_sdk/runtime/langchain/langraph_agent.py +106 -21
- alita_sdk/runtime/langchain/utils.py +30 -14
- alita_sdk/runtime/toolkits/__init__.py +3 -0
- alita_sdk/runtime/toolkits/artifact.py +2 -1
- alita_sdk/runtime/toolkits/mcp.py +6 -3
- alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
- alita_sdk/runtime/toolkits/skill_router.py +2 -2
- alita_sdk/runtime/toolkits/tools.py +64 -2
- alita_sdk/runtime/toolkits/vectorstore.py +1 -1
- alita_sdk/runtime/tools/artifact.py +15 -0
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/llm.py +30 -11
- alita_sdk/runtime/tools/mcp_server_tool.py +6 -3
- alita_sdk/runtime/tools/router.py +2 -4
- alita_sdk/runtime/tools/sandbox.py +9 -6
- alita_sdk/runtime/utils/constants.py +5 -1
- alita_sdk/runtime/utils/mcp_client.py +1 -1
- alita_sdk/runtime/utils/mcp_sse_client.py +1 -1
- alita_sdk/runtime/utils/toolkit_utils.py +2 -0
- alita_sdk/tools/__init__.py +3 -1
- alita_sdk/tools/ado/repos/__init__.py +26 -8
- alita_sdk/tools/ado/repos/repos_wrapper.py +78 -52
- alita_sdk/tools/ado/test_plan/__init__.py +3 -2
- 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 +2 -1
- alita_sdk/tools/ado/wiki/ado_wrapper.py +23 -1
- alita_sdk/tools/ado/work_item/__init__.py +3 -2
- alita_sdk/tools/ado/work_item/ado_wrapper.py +23 -1
- alita_sdk/tools/advanced_jira_mining/__init__.py +2 -1
- alita_sdk/tools/aws/delta_lake/__init__.py +2 -1
- alita_sdk/tools/azure_ai/search/__init__.py +2 -1
- alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
- alita_sdk/tools/base_indexer_toolkit.py +15 -6
- alita_sdk/tools/bitbucket/__init__.py +2 -1
- alita_sdk/tools/bitbucket/api_wrapper.py +1 -1
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +3 -3
- alita_sdk/tools/browser/__init__.py +1 -1
- alita_sdk/tools/carrier/__init__.py +1 -1
- alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
- alita_sdk/tools/cloud/aws/__init__.py +2 -1
- alita_sdk/tools/cloud/azure/__init__.py +2 -1
- alita_sdk/tools/cloud/gcp/__init__.py +2 -1
- alita_sdk/tools/cloud/k8s/__init__.py +2 -1
- alita_sdk/tools/code/linter/__init__.py +2 -1
- alita_sdk/tools/code/sonar/__init__.py +2 -1
- alita_sdk/tools/code_indexer_toolkit.py +19 -2
- alita_sdk/tools/confluence/__init__.py +7 -6
- alita_sdk/tools/confluence/api_wrapper.py +2 -2
- alita_sdk/tools/custom_open_api/__init__.py +2 -1
- alita_sdk/tools/elastic/__init__.py +2 -1
- alita_sdk/tools/elitea_base.py +28 -9
- alita_sdk/tools/figma/__init__.py +52 -6
- alita_sdk/tools/figma/api_wrapper.py +1158 -123
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +2 -1
- alita_sdk/tools/github/github_client.py +56 -92
- alita_sdk/tools/github/schemas.py +4 -4
- alita_sdk/tools/gitlab/__init__.py +2 -1
- alita_sdk/tools/gitlab/api_wrapper.py +118 -38
- alita_sdk/tools/gitlab_org/__init__.py +2 -1
- alita_sdk/tools/gitlab_org/api_wrapper.py +60 -62
- alita_sdk/tools/google/bigquery/__init__.py +2 -1
- alita_sdk/tools/google_places/__init__.py +2 -1
- alita_sdk/tools/jira/__init__.py +2 -1
- alita_sdk/tools/keycloak/__init__.py +2 -1
- alita_sdk/tools/localgit/__init__.py +2 -1
- alita_sdk/tools/memory/__init__.py +1 -1
- alita_sdk/tools/ocr/__init__.py +2 -1
- alita_sdk/tools/openapi/__init__.py +227 -15
- alita_sdk/tools/openapi/api_wrapper.py +1287 -802
- alita_sdk/tools/pandas/__init__.py +11 -5
- alita_sdk/tools/pandas/api_wrapper.py +38 -25
- alita_sdk/tools/postman/__init__.py +2 -1
- alita_sdk/tools/pptx/__init__.py +2 -1
- alita_sdk/tools/qtest/__init__.py +21 -2
- alita_sdk/tools/qtest/api_wrapper.py +430 -13
- alita_sdk/tools/rally/__init__.py +2 -1
- alita_sdk/tools/rally/api_wrapper.py +1 -1
- alita_sdk/tools/report_portal/__init__.py +2 -1
- alita_sdk/tools/salesforce/__init__.py +2 -1
- alita_sdk/tools/servicenow/__init__.py +2 -1
- alita_sdk/tools/sharepoint/__init__.py +2 -1
- alita_sdk/tools/sharepoint/api_wrapper.py +2 -2
- alita_sdk/tools/slack/__init__.py +3 -2
- alita_sdk/tools/slack/api_wrapper.py +2 -2
- alita_sdk/tools/sql/__init__.py +3 -2
- alita_sdk/tools/testio/__init__.py +2 -1
- alita_sdk/tools/testrail/__init__.py +2 -1
- alita_sdk/tools/utils/content_parser.py +77 -3
- alita_sdk/tools/utils/text_operations.py +163 -71
- alita_sdk/tools/xray/__init__.py +3 -2
- alita_sdk/tools/yagmail/__init__.py +2 -1
- alita_sdk/tools/zephyr/__init__.py +2 -1
- alita_sdk/tools/zephyr_enterprise/__init__.py +2 -1
- alita_sdk/tools/zephyr_essential/__init__.py +2 -1
- alita_sdk/tools/zephyr_scale/__init__.py +3 -2
- alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
- alita_sdk/tools/zephyr_squad/__init__.py +2 -1
- {alita_sdk-0.3.554.dist-info → alita_sdk-0.3.602.dist-info}/METADATA +7 -6
- {alita_sdk-0.3.554.dist-info → alita_sdk-0.3.602.dist-info}/RECORD +116 -111
- {alita_sdk-0.3.554.dist-info → alita_sdk-0.3.602.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.554.dist-info → alita_sdk-0.3.602.dist-info}/entry_points.txt +0 -0
- {alita_sdk-0.3.554.dist-info → alita_sdk-0.3.602.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.554.dist-info → alita_sdk-0.3.602.dist-info}/top_level.txt +0 -0
|
@@ -72,7 +72,7 @@ class SkillRouterToolkit(BaseToolkit):
|
|
|
72
72
|
default=list(selected_tools_options.keys()),
|
|
73
73
|
json_schema_extra={'args_schemas': selected_tools_options}
|
|
74
74
|
)),
|
|
75
|
-
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Skill Router", "icon_url": None}})
|
|
75
|
+
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Skill Router", "icon_url": None, "hidden": True}})
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
@classmethod
|
|
@@ -147,7 +147,7 @@ class SkillRouterToolkit(BaseToolkit):
|
|
|
147
147
|
name=tool["name"],
|
|
148
148
|
description=description,
|
|
149
149
|
args_schema=tool["args_schema"],
|
|
150
|
-
metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
|
|
150
|
+
metadata={"toolkit_name": toolkit_name, "toolkit_type": "skill_router"} if toolkit_name else {}
|
|
151
151
|
))
|
|
152
152
|
|
|
153
153
|
return cls(tools=tools)
|
|
@@ -14,10 +14,12 @@ from .prompt import PromptToolkit
|
|
|
14
14
|
from .subgraph import SubgraphToolkit
|
|
15
15
|
from .vectorstore import VectorStoreToolkit
|
|
16
16
|
from .mcp import McpToolkit
|
|
17
|
+
from .mcp_config import McpConfigToolkit, get_mcp_config_toolkit_schemas
|
|
17
18
|
from .skill_router import SkillRouterToolkit
|
|
18
19
|
from ..tools.mcp_server_tool import McpServerTool
|
|
19
20
|
from ..tools.sandbox import SandboxToolkit
|
|
20
21
|
from ..tools.image_generation import ImageGenerationToolkit
|
|
22
|
+
from ..tools.data_analysis import DataAnalysisToolkit
|
|
21
23
|
# Import community tools
|
|
22
24
|
from ...community import get_toolkits as community_toolkits, get_tools as community_tools
|
|
23
25
|
from ...tools.memory import MemoryToolkit
|
|
@@ -36,11 +38,16 @@ def get_toolkits():
|
|
|
36
38
|
VectorStoreToolkit.toolkit_config_schema(),
|
|
37
39
|
SandboxToolkit.toolkit_config_schema(),
|
|
38
40
|
ImageGenerationToolkit.toolkit_config_schema(),
|
|
41
|
+
DataAnalysisToolkit.toolkit_config_schema(),
|
|
39
42
|
McpToolkit.toolkit_config_schema(),
|
|
43
|
+
McpConfigToolkit.toolkit_config_schema(),
|
|
40
44
|
SkillRouterToolkit.toolkit_config_schema()
|
|
41
45
|
]
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
# Add configured MCP servers (stdio and http) as available toolkits
|
|
48
|
+
mcp_config_toolkits = get_mcp_config_toolkit_schemas()
|
|
49
|
+
|
|
50
|
+
return core_toolkits + mcp_config_toolkits + community_toolkits() + alita_toolkits()
|
|
44
51
|
|
|
45
52
|
|
|
46
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:
|
|
@@ -135,6 +142,20 @@ def get_tools(tools_list: list, alita_client=None, llm=None, memory_store: BaseS
|
|
|
135
142
|
pgvector_configuration=tool.get('settings', {}).get('pgvector_configuration'),
|
|
136
143
|
conversation_id=conversation_id,
|
|
137
144
|
).get_tools()
|
|
145
|
+
elif tool['name'] == 'data_analysis':
|
|
146
|
+
# Data Analysis internal tool - uses conversation attachment bucket
|
|
147
|
+
settings = tool.get('settings', {})
|
|
148
|
+
bucket_name = settings.get('bucket_name')
|
|
149
|
+
if bucket_name:
|
|
150
|
+
tools += DataAnalysisToolkit.get_toolkit(
|
|
151
|
+
alita_client=alita_client,
|
|
152
|
+
llm=llm,
|
|
153
|
+
bucket_name=bucket_name,
|
|
154
|
+
toolkit_name="Data Analyst",
|
|
155
|
+
).get_tools()
|
|
156
|
+
else:
|
|
157
|
+
logger.warning("Data Analysis internal tool requested "
|
|
158
|
+
"but no bucket_name provided in settings")
|
|
138
159
|
elif tool['type'] == 'artifact':
|
|
139
160
|
tool_handled = True
|
|
140
161
|
toolkit_tools = ArtifactToolkit.get_toolkit(
|
|
@@ -261,7 +282,7 @@ def get_tools(tools_list: list, alita_client=None, llm=None, memory_store: BaseS
|
|
|
261
282
|
settings = tool.get('settings', {})
|
|
262
283
|
toolkit_name = tool.get('toolkit_name', '')
|
|
263
284
|
selected_tools = settings.get('selected_tools', [])
|
|
264
|
-
|
|
285
|
+
|
|
265
286
|
toolkit_tools = SkillRouterToolkit.get_toolkit(
|
|
266
287
|
client=alita_client,
|
|
267
288
|
llm=llm,
|
|
@@ -275,6 +296,47 @@ def get_tools(tools_list: list, alita_client=None, llm=None, memory_store: BaseS
|
|
|
275
296
|
except Exception as e:
|
|
276
297
|
logger.error(f"❌ Failed to initialize SkillRouterToolkit: {e}")
|
|
277
298
|
raise
|
|
299
|
+
elif tool['type'] == 'mcp_config' or tool['type'].startswith('mcp_'):
|
|
300
|
+
tool_handled = True
|
|
301
|
+
# MCP Config toolkit - pre-configured MCP servers (stdio or http)
|
|
302
|
+
# Handle both explicit 'mcp_config' type and dynamic names like 'mcp_playwright'
|
|
303
|
+
logger.info(f"Processing mcp_config toolkit: {tool}")
|
|
304
|
+
try:
|
|
305
|
+
settings = tool.get('settings', {})
|
|
306
|
+
|
|
307
|
+
# Server name can come from settings or be extracted from type name
|
|
308
|
+
server_name = settings.get('server_name')
|
|
309
|
+
if not server_name and tool['type'].startswith('mcp_') and tool['type'] != 'mcp_config':
|
|
310
|
+
# Extract server name from type (e.g., 'mcp_playwright' -> 'playwright')
|
|
311
|
+
server_name = tool['type'][4:] # Remove 'mcp_' prefix
|
|
312
|
+
|
|
313
|
+
if not server_name:
|
|
314
|
+
logger.error(f"❌ No server_name found for mcp_config toolkit: {tool}")
|
|
315
|
+
continue
|
|
316
|
+
|
|
317
|
+
toolkit_name = tool.get('toolkit_name', '') or server_name
|
|
318
|
+
selected_tools = settings.get('selected_tools', [])
|
|
319
|
+
excluded_tools = settings.get('excluded_tools', [])
|
|
320
|
+
|
|
321
|
+
# Get server config (may be in settings or from global config)
|
|
322
|
+
server_config = settings.get('server_config')
|
|
323
|
+
|
|
324
|
+
toolkit_tools = McpConfigToolkit.get_toolkit(
|
|
325
|
+
server_name=server_name,
|
|
326
|
+
server_config=server_config,
|
|
327
|
+
user_config=settings,
|
|
328
|
+
selected_tools=selected_tools if selected_tools else None,
|
|
329
|
+
excluded_tools=excluded_tools if excluded_tools else None,
|
|
330
|
+
toolkit_name=toolkit_name,
|
|
331
|
+
client=alita_client,
|
|
332
|
+
).get_tools()
|
|
333
|
+
|
|
334
|
+
tools.extend(toolkit_tools)
|
|
335
|
+
logger.info(f"✅ Successfully added {len(toolkit_tools)} tools from McpConfigToolkit ({server_name})")
|
|
336
|
+
except Exception as e:
|
|
337
|
+
logger.error(f"❌ Failed to initialize McpConfigToolkit: {e}")
|
|
338
|
+
if not debug_mode:
|
|
339
|
+
raise
|
|
278
340
|
except McpAuthorizationRequired:
|
|
279
341
|
# Re-raise auth required exceptions directly
|
|
280
342
|
raise
|
|
@@ -56,7 +56,7 @@ class VectorStoreToolkit(BaseToolkit):
|
|
|
56
56
|
name=tool["name"],
|
|
57
57
|
description=description,
|
|
58
58
|
args_schema=tool["args_schema"],
|
|
59
|
-
metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
|
|
59
|
+
metadata={"toolkit_name": toolkit_name, "toolkit_type": "vectorstore"} if toolkit_name else {}
|
|
60
60
|
))
|
|
61
61
|
return cls(tools=tools)
|
|
62
62
|
|
|
@@ -350,6 +350,21 @@ class ArtifactWrapper(NonCodeIndexerToolkit):
|
|
|
350
350
|
|
|
351
351
|
include_extensions = kwargs.get('include_extensions', [])
|
|
352
352
|
skip_extensions = kwargs.get('skip_extensions', [])
|
|
353
|
+
chunking_config = kwargs.get('chunking_config', {})
|
|
354
|
+
|
|
355
|
+
# Auto-include extensions from chunking_config if include_extensions is specified
|
|
356
|
+
# This allows chunking config to work without manually adding extensions to include_extensions
|
|
357
|
+
if chunking_config and include_extensions:
|
|
358
|
+
for ext_pattern in chunking_config.keys():
|
|
359
|
+
# Normalize extension pattern (both ".cbl" and "*.cbl" should work)
|
|
360
|
+
normalized = ext_pattern if ext_pattern.startswith('*') else f'*{ext_pattern}'
|
|
361
|
+
if normalized not in include_extensions:
|
|
362
|
+
include_extensions.append(normalized)
|
|
363
|
+
self._log_tool_event(
|
|
364
|
+
message=f"Auto-included extension '{normalized}' from chunking_config",
|
|
365
|
+
tool_name="loader"
|
|
366
|
+
)
|
|
367
|
+
|
|
353
368
|
self._log_tool_event(message=f"Files filtering started. Include extensions: {include_extensions}. "
|
|
354
369
|
f"Skip extensions: {skip_extensions}", tool_name="loader")
|
|
355
370
|
# show the progress of filtering
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data Analysis internal tool for Alita SDK.
|
|
3
|
+
|
|
4
|
+
This tool provides Pandas-based data analysis capabilities as an internal tool,
|
|
5
|
+
accessible through the "Enable internal tools" dropdown menu.
|
|
6
|
+
|
|
7
|
+
It uses the conversation attachment bucket for file storage, providing seamless
|
|
8
|
+
integration with drag-and-drop file uploads in chat.
|
|
9
|
+
"""
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any, List, Literal, Optional, Type
|
|
12
|
+
|
|
13
|
+
from langchain_core.tools import BaseTool, BaseToolkit
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, create_model, Field
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
name = "data_analysis"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_tools(tools_list: list, alita_client=None, llm=None, memory_store=None):
|
|
22
|
+
"""
|
|
23
|
+
Get data analysis tools for the provided tool configurations.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
tools_list: List of tool configurations
|
|
27
|
+
alita_client: Alita client instance (required for data analysis)
|
|
28
|
+
llm: LLM client instance (required for code generation)
|
|
29
|
+
memory_store: Optional memory store instance (unused)
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
List of data analysis tools
|
|
33
|
+
"""
|
|
34
|
+
all_tools = []
|
|
35
|
+
|
|
36
|
+
for tool in tools_list:
|
|
37
|
+
if (tool.get('type') == 'data_analysis' or
|
|
38
|
+
tool.get('toolkit_name') == 'data_analysis'):
|
|
39
|
+
try:
|
|
40
|
+
if not alita_client:
|
|
41
|
+
logger.error("Alita client is required for data analysis tools")
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
settings = tool.get('settings', {})
|
|
45
|
+
bucket_name = settings.get('bucket_name')
|
|
46
|
+
|
|
47
|
+
if not bucket_name:
|
|
48
|
+
logger.error("bucket_name is required for data analysis tools")
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
toolkit_instance = DataAnalysisToolkit.get_toolkit(
|
|
52
|
+
alita_client=alita_client,
|
|
53
|
+
llm=llm,
|
|
54
|
+
bucket_name=bucket_name,
|
|
55
|
+
toolkit_name=tool.get('toolkit_name', '')
|
|
56
|
+
)
|
|
57
|
+
all_tools.extend(toolkit_instance.get_tools())
|
|
58
|
+
except Exception as e:
|
|
59
|
+
logger.error(f"Error in data analysis toolkit get_tools: {e}")
|
|
60
|
+
logger.error(f"Tool config: {tool}")
|
|
61
|
+
raise
|
|
62
|
+
|
|
63
|
+
return all_tools
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class DataAnalysisToolkit(BaseToolkit):
|
|
67
|
+
"""
|
|
68
|
+
Data Analysis toolkit providing Pandas-based data analysis capabilities.
|
|
69
|
+
|
|
70
|
+
This is an internal tool that uses the conversation attachment bucket
|
|
71
|
+
for file storage, enabling seamless integration with chat file uploads.
|
|
72
|
+
"""
|
|
73
|
+
tools: List[BaseTool] = []
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def toolkit_config_schema() -> Type[BaseModel]:
|
|
77
|
+
"""Get the configuration schema for the data analysis toolkit."""
|
|
78
|
+
# Import PandasWrapper to get available tools schema
|
|
79
|
+
from alita_sdk.tools.pandas.api_wrapper import PandasWrapper
|
|
80
|
+
|
|
81
|
+
selected_tools = {
|
|
82
|
+
x['name']: x['args_schema'].model_json_schema()
|
|
83
|
+
for x in PandasWrapper.model_construct().get_available_tools()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return create_model(
|
|
87
|
+
'data_analysis',
|
|
88
|
+
bucket_name=(
|
|
89
|
+
Optional[str],
|
|
90
|
+
Field(
|
|
91
|
+
default=None,
|
|
92
|
+
title="Bucket name",
|
|
93
|
+
description="Bucket where files are stored (auto-injected from conversation)"
|
|
94
|
+
)
|
|
95
|
+
),
|
|
96
|
+
selected_tools=(
|
|
97
|
+
List[Literal[tuple(selected_tools)]],
|
|
98
|
+
Field(
|
|
99
|
+
default=[],
|
|
100
|
+
json_schema_extra={'args_schemas': selected_tools}
|
|
101
|
+
)
|
|
102
|
+
),
|
|
103
|
+
__config__=ConfigDict(json_schema_extra={
|
|
104
|
+
'metadata': {
|
|
105
|
+
"label": "Data Analysis",
|
|
106
|
+
"icon_url": "data-analysis.svg",
|
|
107
|
+
"hidden": True, # Hidden from regular toolkit menu
|
|
108
|
+
"categories": ["internal_tool"],
|
|
109
|
+
"extra_categories": ["data analysis", "pandas", "dataframes", "data science"],
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def get_toolkit(
|
|
116
|
+
cls,
|
|
117
|
+
alita_client=None,
|
|
118
|
+
llm=None,
|
|
119
|
+
bucket_name: str = None,
|
|
120
|
+
toolkit_name: Optional[str] = None,
|
|
121
|
+
selected_tools: Optional[List[str]] = None,
|
|
122
|
+
**kwargs
|
|
123
|
+
):
|
|
124
|
+
"""
|
|
125
|
+
Get toolkit with data analysis tools.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
alita_client: Alita client instance (required)
|
|
129
|
+
llm: LLM for code generation (optional, uses alita_client.llm if not provided)
|
|
130
|
+
bucket_name: Conversation attachment bucket (required)
|
|
131
|
+
toolkit_name: Optional name prefix for tools
|
|
132
|
+
selected_tools: Optional list of tool names to include (default: all)
|
|
133
|
+
**kwargs: Additional arguments
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
DataAnalysisToolkit instance with configured tools
|
|
137
|
+
|
|
138
|
+
Raises:
|
|
139
|
+
ValueError: If alita_client or bucket_name is not provided
|
|
140
|
+
"""
|
|
141
|
+
if not alita_client:
|
|
142
|
+
raise ValueError("Alita client is required for data analysis")
|
|
143
|
+
|
|
144
|
+
if not bucket_name:
|
|
145
|
+
raise ValueError("bucket_name is required for data analysis (should be conversation attachment bucket)")
|
|
146
|
+
|
|
147
|
+
# Import the PandasWrapper from existing toolkit
|
|
148
|
+
from alita_sdk.tools.pandas.api_wrapper import PandasWrapper
|
|
149
|
+
from alita_sdk.tools.base.tool import BaseAction
|
|
150
|
+
|
|
151
|
+
# Create wrapper with conversation bucket
|
|
152
|
+
wrapper = PandasWrapper(
|
|
153
|
+
alita=alita_client,
|
|
154
|
+
llm=llm,
|
|
155
|
+
bucket_name=bucket_name
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Get tools from wrapper
|
|
159
|
+
available_tools = wrapper.get_available_tools()
|
|
160
|
+
tools = []
|
|
161
|
+
|
|
162
|
+
for tool in available_tools:
|
|
163
|
+
# Filter by selected_tools if provided
|
|
164
|
+
if selected_tools and tool["name"] not in selected_tools:
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
description = tool["description"]
|
|
168
|
+
if toolkit_name:
|
|
169
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
170
|
+
description = description[:1000]
|
|
171
|
+
|
|
172
|
+
tools.append(BaseAction(
|
|
173
|
+
api_wrapper=wrapper,
|
|
174
|
+
name=tool["name"],
|
|
175
|
+
description=description,
|
|
176
|
+
args_schema=tool["args_schema"],
|
|
177
|
+
metadata={"toolkit_name": toolkit_name, "toolkit_type": name} if toolkit_name else {}
|
|
178
|
+
))
|
|
179
|
+
|
|
180
|
+
return cls(tools=tools)
|
|
181
|
+
|
|
182
|
+
def get_tools(self):
|
|
183
|
+
return self.tools
|
alita_sdk/runtime/tools/llm.py
CHANGED
|
@@ -81,22 +81,41 @@ class LLMNode(BaseTool):
|
|
|
81
81
|
"""
|
|
82
82
|
Prepare structured output parameters from structured_output_dict.
|
|
83
83
|
|
|
84
|
+
Expected self.structured_output_dict formats:
|
|
85
|
+
- {"field": "str"} / {"field": "list"} / {"field": "list[str]"} / {"field": "any"} ...
|
|
86
|
+
- OR {"field": {"type": "...", "description": "...", "default": ...}} (optional)
|
|
87
|
+
|
|
84
88
|
Returns:
|
|
85
|
-
|
|
89
|
+
Dict[str, Dict] suitable for create_pydantic_model(...)
|
|
86
90
|
"""
|
|
87
|
-
struct_params = {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
struct_params: dict[str, dict] = {}
|
|
92
|
+
|
|
93
|
+
for key, value in (self.structured_output_dict or {}).items():
|
|
94
|
+
# Allow either a plain type string or a dict with details
|
|
95
|
+
if isinstance(value, dict):
|
|
96
|
+
type_str = (value.get("type") or "any")
|
|
97
|
+
desc = value.get("description", "") or ""
|
|
98
|
+
entry: dict = {"type": type_str, "description": desc}
|
|
99
|
+
if "default" in value:
|
|
100
|
+
entry["default"] = value["default"]
|
|
101
|
+
else:
|
|
102
|
+
type_str = (value or "any") if isinstance(value, str) else "any"
|
|
103
|
+
entry = {"type": type_str, "description": ""}
|
|
104
|
+
|
|
105
|
+
# Normalize: only convert the *exact* "list" into "list[str]"
|
|
106
|
+
# (avoid the old bug where "if 'list' in value" also hits "blacklist", etc.)
|
|
107
|
+
if isinstance(entry.get("type"), str) and entry["type"].strip().lower() == "list":
|
|
108
|
+
entry["type"] = "list[str]"
|
|
109
|
+
|
|
110
|
+
struct_params[key] = entry
|
|
111
|
+
|
|
94
112
|
# Add default output field for proper response to user
|
|
95
113
|
struct_params[ELITEA_RS] = {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"default": None
|
|
114
|
+
"description": "final output to user (summarized output from LLM)",
|
|
115
|
+
"type": "str",
|
|
116
|
+
"default": None,
|
|
99
117
|
}
|
|
118
|
+
|
|
100
119
|
return struct_params
|
|
101
120
|
|
|
102
121
|
def _invoke_with_structured_output(self, llm_client: Any, messages: List, struct_model: Any, config: RunnableConfig):
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import uuid
|
|
2
2
|
from logging import getLogger
|
|
3
|
-
from typing import Any, Type, Literal, Optional, Union, List
|
|
3
|
+
from typing import Any, Type, Literal, Optional, Union, List, Annotated
|
|
4
4
|
|
|
5
5
|
from langchain_core.tools import BaseTool
|
|
6
|
-
from pydantic import BaseModel, Field, create_model,
|
|
6
|
+
from pydantic import BaseModel, Field, create_model, ConfigDict, StringConstraints
|
|
7
|
+
|
|
8
|
+
# EmailStr moved to pydantic_extra_types in pydantic v2, use str for simplicity
|
|
9
|
+
EmailStr = str
|
|
7
10
|
|
|
8
11
|
logger = getLogger(__name__)
|
|
9
12
|
|
|
@@ -59,7 +62,7 @@ class McpServerTool(BaseTool):
|
|
|
59
62
|
if field.get("format") == "email":
|
|
60
63
|
return EmailStr
|
|
61
64
|
if "pattern" in field:
|
|
62
|
-
return
|
|
65
|
+
return Annotated[str, StringConstraints(pattern=field["pattern"])]
|
|
63
66
|
return str
|
|
64
67
|
if t == "integer":
|
|
65
68
|
return int
|
|
@@ -27,10 +27,8 @@ class RouterNode(BaseTool):
|
|
|
27
27
|
if result in [clean_string(formatted_result) for formatted_result in self.routes]:
|
|
28
28
|
# If the result is one of the routes, return it
|
|
29
29
|
return {"router_output": result}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return {"router_output": clean_string(self.default_output)}
|
|
33
|
-
return {"router_output": 'END'}
|
|
30
|
+
# For any unmatched condition (including empty string), use the configured default_output
|
|
31
|
+
return {"router_output": clean_string(self.default_output)}
|
|
34
32
|
|
|
35
33
|
def _run(self, *args, **kwargs):
|
|
36
34
|
return self.invoke(**kwargs)
|
|
@@ -326,12 +326,15 @@ class SandboxToolkit(BaseToolkit):
|
|
|
326
326
|
|
|
327
327
|
@staticmethod
|
|
328
328
|
def toolkit_config_schema() -> Type[BaseModel]:
|
|
329
|
-
#
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
329
|
+
# Get tool schemas without instantiating the tools (avoids Deno requirement)
|
|
330
|
+
try:
|
|
331
|
+
selected_tools = {
|
|
332
|
+
"pyodide_sandbox": sandbox_tool_input.model_json_schema(),
|
|
333
|
+
"stateful_pyodide_sandbox": sandbox_tool_input.model_json_schema(),
|
|
334
|
+
}
|
|
335
|
+
except Exception as e:
|
|
336
|
+
logger.warning(f"Could not generate sandbox tool schemas: {e}")
|
|
337
|
+
selected_tools = {}
|
|
335
338
|
|
|
336
339
|
return create_model(
|
|
337
340
|
'sandbox',
|
|
@@ -59,10 +59,12 @@ def instantiate_toolkit_with_client(toolkit_config: Dict[str, Any],
|
|
|
59
59
|
|
|
60
60
|
# Create a tool configuration dict with required fields
|
|
61
61
|
# Note: MCP toolkit always requires toolkit_name, other toolkits respect use_prefix flag
|
|
62
|
+
# Note: 'name' is always set for provider-based toolkits (used by provider_worker.utils.tools)
|
|
62
63
|
tool_config = {
|
|
63
64
|
'id': toolkit_config.get('id', random.randint(1, 1000000)),
|
|
64
65
|
'type': toolkit_config.get('type', toolkit_type),
|
|
65
66
|
'settings': settings,
|
|
67
|
+
'name': toolkit_name, # Always pass name for provider toolkits
|
|
66
68
|
'toolkit_name': toolkit_name if (use_prefix or toolkit_type == 'mcp') else None
|
|
67
69
|
}
|
|
68
70
|
|
alita_sdk/tools/__init__.py
CHANGED
|
@@ -102,7 +102,7 @@ _safe_import_tool('k8s', 'cloud.k8s', None, 'KubernetesToolkit')
|
|
|
102
102
|
_safe_import_tool('elastic', 'elastic', None, 'ElasticToolkit')
|
|
103
103
|
_safe_import_tool('keycloak', 'keycloak', None, 'KeycloakToolkit')
|
|
104
104
|
_safe_import_tool('localgit', 'localgit', None, 'AlitaLocalGitToolkit')
|
|
105
|
-
|
|
105
|
+
# pandas toolkit removed - use Data Analysis internal tool instead
|
|
106
106
|
_safe_import_tool('azure_search', 'azure_ai.search', 'get_tools', 'AzureSearchToolkit')
|
|
107
107
|
_safe_import_tool('figma', 'figma', 'get_tools', 'FigmaToolkit')
|
|
108
108
|
_safe_import_tool('salesforce', 'salesforce', 'get_tools', 'SalesforceToolkit')
|
|
@@ -186,7 +186,9 @@ def get_tools(tools_list, alita, llm, store: Optional[BaseStore] = None, *args,
|
|
|
186
186
|
toolkit = tkitclass.get_toolkit(**get_toolkit_params)
|
|
187
187
|
toolkit_tools.extend(toolkit.get_tools())
|
|
188
188
|
except Exception as e:
|
|
189
|
+
import traceback
|
|
189
190
|
logger.error(f"Error in getting custom toolkit: {e}")
|
|
191
|
+
logger.error(f"Traceback:\n{traceback.format_exc()}")
|
|
190
192
|
else:
|
|
191
193
|
if tool_type in FAILED_IMPORTS:
|
|
192
194
|
logger.warning(f"Tool '{tool_type}' is not available: {FAILED_IMPORTS[tool_type]}")
|
|
@@ -11,6 +11,7 @@ from ....configurations.pgvector import PgVectorConfiguration
|
|
|
11
11
|
from ...base.tool import BaseAction
|
|
12
12
|
from .repos_wrapper import ReposApiWrapper
|
|
13
13
|
from ...utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
14
|
+
from ....runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
14
15
|
|
|
15
16
|
name = "ado_repos"
|
|
16
17
|
|
|
@@ -52,13 +53,30 @@ class AzureDevOpsReposToolkit(BaseToolkit):
|
|
|
52
53
|
embedding_model=(Optional[str], Field(default=None, description="Embedding configuration.", json_schema_extra={'configuration_model': 'embedding'})),
|
|
53
54
|
|
|
54
55
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
55
|
-
__config__={
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
__config__={
|
|
57
|
+
'json_schema_extra': {
|
|
58
|
+
'metadata': {
|
|
59
|
+
"label": "ADO repos",
|
|
60
|
+
"icon_url": "ado-repos-icon.svg",
|
|
61
|
+
"categories": ["code repositories"],
|
|
62
|
+
"extra_categories": ["code", "repository", "version control"],
|
|
63
|
+
"sections": {
|
|
64
|
+
"auth": {
|
|
65
|
+
"required": True,
|
|
66
|
+
"subsections": [
|
|
67
|
+
{
|
|
68
|
+
"name": "Token",
|
|
69
|
+
"fields": ["token"]
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"configuration_group": {
|
|
75
|
+
"name": "ado",
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
62
80
|
)
|
|
63
81
|
|
|
64
82
|
@check_connection_response
|
|
@@ -107,7 +125,7 @@ class AzureDevOpsReposToolkit(BaseToolkit):
|
|
|
107
125
|
name=tool["name"],
|
|
108
126
|
description=description,
|
|
109
127
|
args_schema=tool["args_schema"],
|
|
110
|
-
metadata={
|
|
128
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
111
129
|
)
|
|
112
130
|
)
|
|
113
131
|
return cls(tools=tools)
|