alita-sdk 0.3.435__py3-none-any.whl → 0.3.436__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/runtime/toolkits/mcp.py +120 -13
- {alita_sdk-0.3.435.dist-info → alita_sdk-0.3.436.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.435.dist-info → alita_sdk-0.3.436.dist-info}/RECORD +6 -6
- {alita_sdk-0.3.435.dist-info → alita_sdk-0.3.436.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.435.dist-info → alita_sdk-0.3.436.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.435.dist-info → alita_sdk-0.3.436.dist-info}/top_level.txt +0 -0
|
@@ -5,6 +5,7 @@ Following MCP specification: https://modelcontextprotocol.io/specification/2025-
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
+
import re
|
|
8
9
|
import requests
|
|
9
10
|
from typing import List, Optional, Any, Dict, Literal, ClassVar
|
|
10
11
|
|
|
@@ -20,6 +21,119 @@ logger = logging.getLogger(__name__)
|
|
|
20
21
|
|
|
21
22
|
name = "mcp"
|
|
22
23
|
|
|
24
|
+
def safe_int(value, default):
|
|
25
|
+
"""Convert value to int, handling string inputs."""
|
|
26
|
+
if value is None:
|
|
27
|
+
return default
|
|
28
|
+
try:
|
|
29
|
+
return int(value)
|
|
30
|
+
except (ValueError, TypeError):
|
|
31
|
+
logger.warning(f"Invalid integer value '{value}', using default {default}")
|
|
32
|
+
return default
|
|
33
|
+
|
|
34
|
+
def optimize_tool_name(prefix: str, tool_name: str, max_total_length: int = 64) -> str:
|
|
35
|
+
"""
|
|
36
|
+
Optimize tool name to fit within max_total_length while preserving meaning.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
prefix: The toolkit prefix (already cleaned)
|
|
40
|
+
tool_name: The original tool name
|
|
41
|
+
max_total_length: Maximum total length for the full tool name (default: 64)
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Optimized full tool name in format: prefix___tool_name
|
|
45
|
+
"""
|
|
46
|
+
splitter = TOOLKIT_SPLITTER
|
|
47
|
+
splitter_len = len(splitter)
|
|
48
|
+
prefix_len = len(prefix)
|
|
49
|
+
|
|
50
|
+
# Calculate available space for tool name
|
|
51
|
+
available_space = max_total_length - prefix_len - splitter_len
|
|
52
|
+
|
|
53
|
+
if available_space <= 0:
|
|
54
|
+
logger.error(f"Prefix '{prefix}' is too long ({prefix_len} chars), cannot create valid tool name")
|
|
55
|
+
# Fallback: truncate prefix itself
|
|
56
|
+
prefix = prefix[:max_total_length - splitter_len - 10] # Leave 10 chars for tool name
|
|
57
|
+
available_space = max_total_length - len(prefix) - splitter_len
|
|
58
|
+
|
|
59
|
+
# If tool name fits, use it as-is
|
|
60
|
+
if len(tool_name) <= available_space:
|
|
61
|
+
return f'{prefix}{splitter}{tool_name}'
|
|
62
|
+
|
|
63
|
+
# Tool name is too long, need to optimize
|
|
64
|
+
logger.debug(f"Tool name '{tool_name}' is too long ({len(tool_name)} chars), optimizing to fit {available_space} chars")
|
|
65
|
+
|
|
66
|
+
# Split tool name into parts (handle camelCase, snake_case, and mixed)
|
|
67
|
+
# First, split by underscores and hyphens
|
|
68
|
+
parts = re.split(r'[_-]', tool_name)
|
|
69
|
+
|
|
70
|
+
# Further split camelCase within each part
|
|
71
|
+
all_parts = []
|
|
72
|
+
for part in parts:
|
|
73
|
+
# Insert underscore before uppercase letters (camelCase to snake_case)
|
|
74
|
+
snake_case_part = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', part)
|
|
75
|
+
all_parts.extend(snake_case_part.split('_'))
|
|
76
|
+
|
|
77
|
+
# Filter out empty parts
|
|
78
|
+
all_parts = [p for p in all_parts if p]
|
|
79
|
+
|
|
80
|
+
# Remove redundant prefix words (case-insensitive comparison)
|
|
81
|
+
# Only remove if prefix is meaningful (>= 3 chars) to avoid over-filtering
|
|
82
|
+
prefix_lower = prefix.lower()
|
|
83
|
+
filtered_parts = []
|
|
84
|
+
for part in all_parts:
|
|
85
|
+
part_lower = part.lower()
|
|
86
|
+
# Skip if this part contains the prefix or the prefix contains this part
|
|
87
|
+
# But only if both are meaningful (>= 3 chars)
|
|
88
|
+
should_remove = False
|
|
89
|
+
if len(prefix_lower) >= 3 and len(part_lower) >= 3:
|
|
90
|
+
if part_lower in prefix_lower or prefix_lower in part_lower:
|
|
91
|
+
should_remove = True
|
|
92
|
+
logger.debug(f"Removing redundant part '{part}' (matches prefix '{prefix}')")
|
|
93
|
+
|
|
94
|
+
if not should_remove:
|
|
95
|
+
filtered_parts.append(part)
|
|
96
|
+
|
|
97
|
+
# If we removed all parts, keep the original parts
|
|
98
|
+
if not filtered_parts:
|
|
99
|
+
filtered_parts = all_parts
|
|
100
|
+
|
|
101
|
+
# Reconstruct tool name with filtered parts
|
|
102
|
+
optimized_name = '_'.join(filtered_parts)
|
|
103
|
+
|
|
104
|
+
# If still too long, truncate intelligently
|
|
105
|
+
if len(optimized_name) > available_space:
|
|
106
|
+
# Strategy: Keep beginning and end, as they often contain the most important info
|
|
107
|
+
# For example: "projectalita_github_io_list_branches" -> "projectalita_list_branches"
|
|
108
|
+
|
|
109
|
+
# Try removing middle parts first
|
|
110
|
+
if len(filtered_parts) > 2:
|
|
111
|
+
# Keep first and last parts, remove middle
|
|
112
|
+
kept_parts = [filtered_parts[0], filtered_parts[-1]]
|
|
113
|
+
optimized_name = '_'.join(kept_parts)
|
|
114
|
+
|
|
115
|
+
# If still too long, add parts from the end until we run out of space
|
|
116
|
+
if len(optimized_name) <= available_space and len(filtered_parts) > 2:
|
|
117
|
+
for i in range(len(filtered_parts) - 2, 0, -1):
|
|
118
|
+
candidate = '_'.join([filtered_parts[0]] + filtered_parts[i:])
|
|
119
|
+
if len(candidate) <= available_space:
|
|
120
|
+
optimized_name = candidate
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
# If still too long, just truncate
|
|
124
|
+
if len(optimized_name) > available_space:
|
|
125
|
+
# Try to truncate at word boundary
|
|
126
|
+
truncated = optimized_name[:available_space]
|
|
127
|
+
last_underscore = truncated.rfind('_')
|
|
128
|
+
if last_underscore > available_space * 0.7: # Keep if we're not losing too much
|
|
129
|
+
optimized_name = truncated[:last_underscore]
|
|
130
|
+
else:
|
|
131
|
+
optimized_name = truncated
|
|
132
|
+
|
|
133
|
+
full_name = f'{prefix}{splitter}{optimized_name}'
|
|
134
|
+
logger.info(f"Optimized tool name: '{tool_name}' ({len(tool_name)} chars) -> '{optimized_name}' ({len(optimized_name)} chars), full: '{full_name}' ({len(full_name)} chars)")
|
|
135
|
+
|
|
136
|
+
return full_name
|
|
23
137
|
|
|
24
138
|
class McpToolkit(BaseToolkit):
|
|
25
139
|
"""
|
|
@@ -491,7 +605,8 @@ class McpToolkit(BaseToolkit):
|
|
|
491
605
|
# Clean toolkit name for prefixing
|
|
492
606
|
clean_prefix = clean_string(toolkit_name, max_length_value)
|
|
493
607
|
|
|
494
|
-
|
|
608
|
+
# Optimize tool name to fit within 64 character limit
|
|
609
|
+
full_tool_name = optimize_tool_name(clean_prefix, tool_dict.get("name", "unknown"))
|
|
495
610
|
|
|
496
611
|
# Check if this is a prompt (converted to tool)
|
|
497
612
|
is_prompt = tool_dict.get("_mcp_type") == "prompt"
|
|
@@ -596,7 +711,8 @@ class McpToolkit(BaseToolkit):
|
|
|
596
711
|
|
|
597
712
|
# Clean server name for prefixing (use tool_metadata.server instead of toolkit_name)
|
|
598
713
|
clean_prefix = clean_string(tool_metadata.server, max_length_value)
|
|
599
|
-
|
|
714
|
+
# Optimize tool name to fit within 64 character limit
|
|
715
|
+
full_tool_name = optimize_tool_name(clean_prefix, tool_metadata.name)
|
|
600
716
|
|
|
601
717
|
return McpServerTool(
|
|
602
718
|
name=full_tool_name,
|
|
@@ -626,7 +742,8 @@ class McpToolkit(BaseToolkit):
|
|
|
626
742
|
# Clean toolkit name for prefixing
|
|
627
743
|
clean_prefix = clean_string(toolkit_name, max_length_value)
|
|
628
744
|
|
|
629
|
-
|
|
745
|
+
# Optimize tool name to fit within 64 character limit
|
|
746
|
+
full_tool_name = optimize_tool_name(clean_prefix, available_tool["name"])
|
|
630
747
|
|
|
631
748
|
return McpServerTool(
|
|
632
749
|
name=full_tool_name,
|
|
@@ -736,16 +853,6 @@ def get_tools(tool_config: dict, alita_client, llm=None, memory_store=None) -> L
|
|
|
736
853
|
return []
|
|
737
854
|
|
|
738
855
|
# Type conversion for numeric settings that may come as strings from config
|
|
739
|
-
def safe_int(value, default):
|
|
740
|
-
"""Convert value to int, handling string inputs."""
|
|
741
|
-
if value is None:
|
|
742
|
-
return default
|
|
743
|
-
try:
|
|
744
|
-
return int(value)
|
|
745
|
-
except (ValueError, TypeError):
|
|
746
|
-
logger.warning(f"Invalid integer value '{value}', using default {default}")
|
|
747
|
-
return default
|
|
748
|
-
|
|
749
856
|
return McpToolkit.get_toolkit(
|
|
750
857
|
url=url,
|
|
751
858
|
headers=headers,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alita_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.436
|
|
4
4
|
Summary: SDK for building langchain agents using resources from Alita
|
|
5
5
|
Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedj27@gmail.com>, Artem Dubrovskiy <ad13box@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -103,7 +103,7 @@ alita_sdk/runtime/toolkits/application.py,sha256=HHAKgwKOckxc7EQG-AV7rz4POOzQJKF
|
|
|
103
103
|
alita_sdk/runtime/toolkits/artifact.py,sha256=YChNCX4QhVpaQG7Jk4TS-Wl0Aruc4slQ2K21zh9nNO0,3176
|
|
104
104
|
alita_sdk/runtime/toolkits/configurations.py,sha256=kIDAlnryPQfbZyFxV-9SzN2-Vefzx06TX1BBdIIpN90,141
|
|
105
105
|
alita_sdk/runtime/toolkits/datasource.py,sha256=qk78OdPoReYPCWwahfkKLbKc4pfsu-061oXRryFLP6I,2498
|
|
106
|
-
alita_sdk/runtime/toolkits/mcp.py,sha256=
|
|
106
|
+
alita_sdk/runtime/toolkits/mcp.py,sha256=6MRNk8FCFSyPFJJhC-Sr5MRdxnEjW8xhO8c8rtePxOs,36176
|
|
107
107
|
alita_sdk/runtime/toolkits/prompt.py,sha256=WIpTkkVYWqIqOWR_LlSWz3ug8uO9tm5jJ7aZYdiGRn0,1192
|
|
108
108
|
alita_sdk/runtime/toolkits/subgraph.py,sha256=wwUK8JjPXkGzyVZ3tAukmvST6eGbqx_U11rpnmbrvtg,2105
|
|
109
109
|
alita_sdk/runtime/toolkits/tools.py,sha256=YCTjrTJuwj2V2C8ZQqXhFvUbVr7NQcUHZlCQLLvoeGA,10946
|
|
@@ -358,8 +358,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
|
|
|
358
358
|
alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
|
|
359
359
|
alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
|
|
360
360
|
alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
|
|
361
|
-
alita_sdk-0.3.
|
|
362
|
-
alita_sdk-0.3.
|
|
363
|
-
alita_sdk-0.3.
|
|
364
|
-
alita_sdk-0.3.
|
|
365
|
-
alita_sdk-0.3.
|
|
361
|
+
alita_sdk-0.3.436.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
362
|
+
alita_sdk-0.3.436.dist-info/METADATA,sha256=2cPfEOfx6pSH8_ITPeRoYsrJ7kNp0X5Z0h7F0UXhUE0,19071
|
|
363
|
+
alita_sdk-0.3.436.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
364
|
+
alita_sdk-0.3.436.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
|
|
365
|
+
alita_sdk-0.3.436.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|