toolplane-python-client 0.1.0__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.
- toolplane/__init__.py +106 -0
- toolplane/common/__init__.py +93 -0
- toolplane/common/base_config.py +129 -0
- toolplane/common/base_connection_manager.py +171 -0
- toolplane/common/base_session_manager.py +321 -0
- toolplane/common/base_tool_manager.py +347 -0
- toolplane/common/constants.py +47 -0
- toolplane/common/utils.py +310 -0
- toolplane/core/__init__.py +67 -0
- toolplane/core/config.py +107 -0
- toolplane/core/connection.py +285 -0
- toolplane/core/errors.py +298 -0
- toolplane/core/machine.py +480 -0
- toolplane/core/request.py +775 -0
- toolplane/core/session.py +332 -0
- toolplane/core/session_context.py +514 -0
- toolplane/core/task.py +130 -0
- toolplane/core/tool.py +329 -0
- toolplane/http_core/__init__.py +37 -0
- toolplane/http_core/http_config.py +97 -0
- toolplane/http_core/http_connection.py +409 -0
- toolplane/http_core/http_machine.py +298 -0
- toolplane/http_core/http_request.py +748 -0
- toolplane/http_core/http_session.py +348 -0
- toolplane/http_core/http_session_context.py +491 -0
- toolplane/http_core/http_task.py +101 -0
- toolplane/http_core/http_tool.py +400 -0
- toolplane/interfaces/__init__.py +27 -0
- toolplane/interfaces/client_interface.py +122 -0
- toolplane/interfaces/connection_interface.py +193 -0
- toolplane/interfaces/event_interface.py +290 -0
- toolplane/interfaces/request_interface.py +439 -0
- toolplane/interfaces/session_interface.py +288 -0
- toolplane/interfaces/tool_interface.py +441 -0
- toolplane/proto/__init__.py +0 -0
- toolplane/proto/service_pb2.py +315 -0
- toolplane/proto/service_pb2_grpc.py +2240 -0
- toolplane/provider_cli.py +268 -0
- toolplane/provider_registry.py +77 -0
- toolplane/provider_runtime.py +302 -0
- toolplane/toolkits/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/create_directory.py +94 -0
- toolplane/toolkits/standalone_tools/create_file.py +124 -0
- toolplane/toolkits/standalone_tools/file_search.py +229 -0
- toolplane/toolkits/standalone_tools/grep_search.py +372 -0
- toolplane/toolkits/standalone_tools/launcher.py +146 -0
- toolplane/toolkits/standalone_tools/list_dir.py +395 -0
- toolplane/toolkits/standalone_tools/read_file.py +346 -0
- toolplane/toolkits/standalone_tools/replace_string_in_file.py +407 -0
- toolplane/toolkits/standalone_tools/run_tests.py +66 -0
- toolplane/toolkits/standalone_tools/semantic_search.py +485 -0
- toolplane/toolkits/standalone_tools/standalone_toolkit.py +979 -0
- toolplane/toolkits/standalone_tools/test_failure_analysis.py +618 -0
- toolplane/toolkits/standalone_tools/test_standalone_toolkit.py +517 -0
- toolplane/toolkits/swe/__init__.py +35 -0
- toolplane/toolkits/swe/create_directory.py +15 -0
- toolplane/toolkits/swe/create_file.py +15 -0
- toolplane/toolkits/swe/descriptions.py +273 -0
- toolplane/toolkits/swe/execute_bash.py +93 -0
- toolplane/toolkits/swe/file_editor.py +775 -0
- toolplane/toolkits/swe/file_search.py +16 -0
- toolplane/toolkits/swe/finish.py +50 -0
- toolplane/toolkits/swe/grep_search.py +19 -0
- toolplane/toolkits/swe/list_dir.py +407 -0
- toolplane/toolkits/swe/read_file.py +18 -0
- toolplane/toolkits/swe/replace_string_in_file.py +17 -0
- toolplane/toolkits/swe/search.py +260 -0
- toolplane/toolkits/swe/semantic_search.py +20 -0
- toolplane/toolkits/swe/str_replace_editor.py +647 -0
- toolplane/toolkits/swe/submit.py +29 -0
- toolplane/toolkits/swe/swe_toolkit.py +1296 -0
- toolplane/toolplane_client.py +686 -0
- toolplane/toolplane_http_client.py +681 -0
- toolplane/utils/__init__.py +3 -0
- toolplane/utils/schema.py +146 -0
- toolplane_python_client-0.1.0.dist-info/METADATA +543 -0
- toolplane_python_client-0.1.0.dist-info/RECORD +81 -0
- toolplane_python_client-0.1.0.dist-info/WHEEL +5 -0
- toolplane_python_client-0.1.0.dist-info/entry_points.txt +2 -0
- toolplane_python_client-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"""Tool management interface definitions."""
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import (
|
|
8
|
+
Any,
|
|
9
|
+
Callable,
|
|
10
|
+
Dict,
|
|
11
|
+
Iterator,
|
|
12
|
+
List,
|
|
13
|
+
Optional,
|
|
14
|
+
Protocol,
|
|
15
|
+
Tuple,
|
|
16
|
+
runtime_checkable,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ToolExecutionStatus(Enum):
|
|
21
|
+
"""Tool execution status."""
|
|
22
|
+
|
|
23
|
+
PENDING = "pending"
|
|
24
|
+
RUNNING = "running"
|
|
25
|
+
DONE = "done"
|
|
26
|
+
FAILURE = "failure"
|
|
27
|
+
COMPLETED = "done"
|
|
28
|
+
FAILED = "failure"
|
|
29
|
+
TIMEOUT = "timeout"
|
|
30
|
+
CANCELLED = "cancelled"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class ToolDefinition:
|
|
35
|
+
"""Tool definition with metadata."""
|
|
36
|
+
|
|
37
|
+
name: str
|
|
38
|
+
func: Callable
|
|
39
|
+
schema: Optional[Dict[str, Any]] = None
|
|
40
|
+
description: Optional[str] = None
|
|
41
|
+
stream: bool = False
|
|
42
|
+
tags: List[str] = None
|
|
43
|
+
timeout: Optional[int] = None
|
|
44
|
+
|
|
45
|
+
def __post_init__(self):
|
|
46
|
+
if self.tags is None:
|
|
47
|
+
self.tags = []
|
|
48
|
+
|
|
49
|
+
# Auto-generate description if not provided
|
|
50
|
+
if not self.description and self.func.__doc__:
|
|
51
|
+
self.description = self.func.__doc__.strip()
|
|
52
|
+
|
|
53
|
+
# Auto-generate schema if not provided
|
|
54
|
+
if not self.schema:
|
|
55
|
+
self.schema = self._generate_schema()
|
|
56
|
+
|
|
57
|
+
def _generate_schema(self) -> Dict[str, Any]:
|
|
58
|
+
"""Generate schema from function signature."""
|
|
59
|
+
try:
|
|
60
|
+
sig = inspect.signature(self.func)
|
|
61
|
+
properties = {}
|
|
62
|
+
required = []
|
|
63
|
+
|
|
64
|
+
for param_name, param in sig.parameters.items():
|
|
65
|
+
if param_name == "self": # Skip self parameter
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
prop = {"type": "string"} # Default type
|
|
69
|
+
|
|
70
|
+
# Try to infer type from annotation
|
|
71
|
+
if param.annotation != param.empty:
|
|
72
|
+
annotation = param.annotation
|
|
73
|
+
if annotation == int:
|
|
74
|
+
prop["type"] = "integer"
|
|
75
|
+
elif annotation == float:
|
|
76
|
+
prop["type"] = "number"
|
|
77
|
+
elif annotation == bool:
|
|
78
|
+
prop["type"] = "boolean"
|
|
79
|
+
elif annotation == list:
|
|
80
|
+
prop["type"] = "array"
|
|
81
|
+
elif annotation == dict:
|
|
82
|
+
prop["type"] = "object"
|
|
83
|
+
|
|
84
|
+
# Handle optional parameters
|
|
85
|
+
if param.default == param.empty:
|
|
86
|
+
required.append(param_name)
|
|
87
|
+
else:
|
|
88
|
+
prop["default"] = param.default
|
|
89
|
+
|
|
90
|
+
properties[param_name] = prop
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
"type": "object",
|
|
94
|
+
"properties": properties,
|
|
95
|
+
"required": required,
|
|
96
|
+
}
|
|
97
|
+
except Exception:
|
|
98
|
+
return {"type": "object", "properties": {}}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@dataclass
|
|
102
|
+
class ToolExecutionResult:
|
|
103
|
+
"""Result of tool execution."""
|
|
104
|
+
|
|
105
|
+
tool_name: str
|
|
106
|
+
session_id: str
|
|
107
|
+
request_id: str
|
|
108
|
+
status: ToolExecutionStatus
|
|
109
|
+
result: Any = None
|
|
110
|
+
error: Optional[str] = None
|
|
111
|
+
execution_time: Optional[float] = None
|
|
112
|
+
metadata: Dict[str, Any] = None
|
|
113
|
+
|
|
114
|
+
def __post_init__(self):
|
|
115
|
+
if self.metadata is None:
|
|
116
|
+
self.metadata = {}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@runtime_checkable
|
|
120
|
+
class IToolExecutor(Protocol):
|
|
121
|
+
"""Protocol interface for tool execution."""
|
|
122
|
+
|
|
123
|
+
def execute(
|
|
124
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any], context: Dict[str, Any]
|
|
125
|
+
) -> ToolExecutionResult:
|
|
126
|
+
"""Execute a tool synchronously."""
|
|
127
|
+
...
|
|
128
|
+
|
|
129
|
+
def execute_async(
|
|
130
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any], context: Dict[str, Any]
|
|
131
|
+
) -> str:
|
|
132
|
+
"""Execute a tool asynchronously, return request ID."""
|
|
133
|
+
...
|
|
134
|
+
|
|
135
|
+
def stream_execute(
|
|
136
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any], context: Dict[str, Any]
|
|
137
|
+
) -> Iterator[Any]:
|
|
138
|
+
"""Execute a tool with streaming results."""
|
|
139
|
+
...
|
|
140
|
+
|
|
141
|
+
def cancel_execution(self, request_id: str) -> bool:
|
|
142
|
+
"""Cancel tool execution."""
|
|
143
|
+
...
|
|
144
|
+
|
|
145
|
+
def get_execution_status(self, request_id: str) -> Optional[ToolExecutionResult]:
|
|
146
|
+
"""Get execution status."""
|
|
147
|
+
...
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@runtime_checkable
|
|
151
|
+
class IToolManager(Protocol):
|
|
152
|
+
"""Protocol interface for tool management."""
|
|
153
|
+
|
|
154
|
+
def register_tool(
|
|
155
|
+
self,
|
|
156
|
+
session_id: str,
|
|
157
|
+
name: str,
|
|
158
|
+
func: Callable,
|
|
159
|
+
schema: Optional[Dict] = None,
|
|
160
|
+
description: Optional[str] = None,
|
|
161
|
+
stream: bool = False,
|
|
162
|
+
tags: Optional[List[str]] = None,
|
|
163
|
+
) -> None:
|
|
164
|
+
"""Register a tool for a session."""
|
|
165
|
+
...
|
|
166
|
+
|
|
167
|
+
def unregister_tool(self, session_id: str, name: str) -> bool:
|
|
168
|
+
"""Unregister a tool from a session."""
|
|
169
|
+
...
|
|
170
|
+
|
|
171
|
+
def get_tool(self, session_id: str, name: str) -> Optional[ToolDefinition]:
|
|
172
|
+
"""Get tool definition."""
|
|
173
|
+
...
|
|
174
|
+
|
|
175
|
+
def list_tools(self, session_id: str) -> List[ToolDefinition]:
|
|
176
|
+
"""List tools for a session."""
|
|
177
|
+
...
|
|
178
|
+
|
|
179
|
+
def execute_tool(
|
|
180
|
+
self,
|
|
181
|
+
session_id: str,
|
|
182
|
+
tool_name: str,
|
|
183
|
+
params: Dict[str, Any],
|
|
184
|
+
idempotency_key: str = "",
|
|
185
|
+
timeout_seconds: int = 0,
|
|
186
|
+
wait_timeout_seconds: int = 0,
|
|
187
|
+
) -> Tuple[str, Optional[str], Optional[Any]]:
|
|
188
|
+
"""Execute a tool.
|
|
189
|
+
|
|
190
|
+
Returns ``(request_id, terminal_status, result)``:
|
|
191
|
+
``terminal_status`` is the normalized status name when the
|
|
192
|
+
server-side long-poll observed a terminal state (``result`` holds
|
|
193
|
+
the parsed result for a successful run); both are ``None`` when the
|
|
194
|
+
request is still in flight.
|
|
195
|
+
"""
|
|
196
|
+
...
|
|
197
|
+
|
|
198
|
+
def stream_tool(
|
|
199
|
+
self, session_id: str, tool_name: str, params: Dict[str, Any]
|
|
200
|
+
) -> Iterator[Any]:
|
|
201
|
+
"""Stream tool execution."""
|
|
202
|
+
...
|
|
203
|
+
|
|
204
|
+
def get_session_tools(self, session_id: str) -> Dict[str, ToolDefinition]:
|
|
205
|
+
"""Get all tools for a session."""
|
|
206
|
+
...
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class IToolValidator(ABC):
|
|
210
|
+
"""Abstract interface for tool validation."""
|
|
211
|
+
|
|
212
|
+
@abstractmethod
|
|
213
|
+
def validate_tool_definition(self, tool_def: ToolDefinition) -> List[str]:
|
|
214
|
+
"""Validate tool definition, return list of errors."""
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
@abstractmethod
|
|
218
|
+
def validate_tool_parameters(
|
|
219
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any]
|
|
220
|
+
) -> List[str]:
|
|
221
|
+
"""Validate tool parameters, return list of errors."""
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
@abstractmethod
|
|
225
|
+
def sanitize_parameters(
|
|
226
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any]
|
|
227
|
+
) -> Dict[str, Any]:
|
|
228
|
+
"""Sanitize tool parameters."""
|
|
229
|
+
pass
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class DefaultToolValidator(IToolValidator):
|
|
233
|
+
"""Default implementation of tool validator."""
|
|
234
|
+
|
|
235
|
+
def validate_tool_definition(self, tool_def: ToolDefinition) -> List[str]:
|
|
236
|
+
"""Validate tool definition."""
|
|
237
|
+
errors = []
|
|
238
|
+
|
|
239
|
+
if not tool_def.name:
|
|
240
|
+
errors.append("Tool name is required")
|
|
241
|
+
elif not isinstance(tool_def.name, str):
|
|
242
|
+
errors.append("Tool name must be a string")
|
|
243
|
+
elif not tool_def.name.replace("_", "").replace("-", "").isalnum():
|
|
244
|
+
errors.append("Tool name must be alphanumeric with underscores/hyphens")
|
|
245
|
+
|
|
246
|
+
if not callable(tool_def.func):
|
|
247
|
+
errors.append("Tool function must be callable")
|
|
248
|
+
|
|
249
|
+
if tool_def.schema and not isinstance(tool_def.schema, dict):
|
|
250
|
+
errors.append("Tool schema must be a dictionary")
|
|
251
|
+
|
|
252
|
+
if tool_def.description and len(tool_def.description) > 1000:
|
|
253
|
+
errors.append("Tool description is too long (max 1000 characters)")
|
|
254
|
+
|
|
255
|
+
if tool_def.tags and not isinstance(tool_def.tags, list):
|
|
256
|
+
errors.append("Tool tags must be a list")
|
|
257
|
+
|
|
258
|
+
return errors
|
|
259
|
+
|
|
260
|
+
def validate_tool_parameters(
|
|
261
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any]
|
|
262
|
+
) -> List[str]:
|
|
263
|
+
"""Validate tool parameters against schema."""
|
|
264
|
+
errors = []
|
|
265
|
+
|
|
266
|
+
if not tool_def.schema:
|
|
267
|
+
return errors # No schema to validate against
|
|
268
|
+
|
|
269
|
+
schema = tool_def.schema
|
|
270
|
+
if "properties" not in schema:
|
|
271
|
+
return errors
|
|
272
|
+
|
|
273
|
+
properties = schema["properties"]
|
|
274
|
+
required = schema.get("required", [])
|
|
275
|
+
|
|
276
|
+
# Check required parameters
|
|
277
|
+
for req_param in required:
|
|
278
|
+
if req_param not in params:
|
|
279
|
+
errors.append(f"Required parameter '{req_param}' is missing")
|
|
280
|
+
|
|
281
|
+
# Validate parameter types
|
|
282
|
+
for param_name, param_value in params.items():
|
|
283
|
+
if param_name not in properties:
|
|
284
|
+
errors.append(f"Unknown parameter '{param_name}'")
|
|
285
|
+
continue
|
|
286
|
+
|
|
287
|
+
prop = properties[param_name]
|
|
288
|
+
expected_type = prop.get("type", "string")
|
|
289
|
+
|
|
290
|
+
if not self._validate_type(param_value, expected_type):
|
|
291
|
+
errors.append(
|
|
292
|
+
f"Parameter '{param_name}' has invalid type. "
|
|
293
|
+
f"Expected {expected_type}, got {type(param_value).__name__}"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
return errors
|
|
297
|
+
|
|
298
|
+
def sanitize_parameters(
|
|
299
|
+
self, tool_def: ToolDefinition, params: Dict[str, Any]
|
|
300
|
+
) -> Dict[str, Any]:
|
|
301
|
+
"""Sanitize tool parameters."""
|
|
302
|
+
if not tool_def.schema or "properties" not in tool_def.schema:
|
|
303
|
+
return params
|
|
304
|
+
|
|
305
|
+
sanitized = {}
|
|
306
|
+
properties = tool_def.schema["properties"]
|
|
307
|
+
|
|
308
|
+
for param_name, param_value in params.items():
|
|
309
|
+
if param_name not in properties:
|
|
310
|
+
continue # Skip unknown parameters
|
|
311
|
+
|
|
312
|
+
prop = properties[param_name]
|
|
313
|
+
expected_type = prop.get("type", "string")
|
|
314
|
+
|
|
315
|
+
# Try to convert to expected type
|
|
316
|
+
try:
|
|
317
|
+
sanitized[param_name] = self._convert_type(param_value, expected_type)
|
|
318
|
+
except (ValueError, TypeError):
|
|
319
|
+
sanitized[param_name] = param_value # Keep original if conversion fails
|
|
320
|
+
|
|
321
|
+
return sanitized
|
|
322
|
+
|
|
323
|
+
def _validate_type(self, value: Any, expected_type: str) -> bool:
|
|
324
|
+
"""Validate if value matches expected type."""
|
|
325
|
+
type_map = {
|
|
326
|
+
"string": str,
|
|
327
|
+
"integer": int,
|
|
328
|
+
"number": (int, float),
|
|
329
|
+
"boolean": bool,
|
|
330
|
+
"array": list,
|
|
331
|
+
"object": dict,
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
expected_python_type = type_map.get(expected_type)
|
|
335
|
+
if not expected_python_type:
|
|
336
|
+
return True # Unknown type, assume valid
|
|
337
|
+
|
|
338
|
+
return isinstance(value, expected_python_type)
|
|
339
|
+
|
|
340
|
+
def _convert_type(self, value: Any, expected_type: str) -> Any:
|
|
341
|
+
"""Convert value to expected type."""
|
|
342
|
+
if expected_type == "string":
|
|
343
|
+
return str(value)
|
|
344
|
+
elif expected_type == "integer":
|
|
345
|
+
return int(value)
|
|
346
|
+
elif expected_type == "number":
|
|
347
|
+
return float(value)
|
|
348
|
+
elif expected_type == "boolean":
|
|
349
|
+
if isinstance(value, str):
|
|
350
|
+
return value.lower() in ("true", "1", "yes", "on")
|
|
351
|
+
return bool(value)
|
|
352
|
+
elif expected_type == "array":
|
|
353
|
+
if isinstance(value, str):
|
|
354
|
+
import json
|
|
355
|
+
|
|
356
|
+
return json.loads(value)
|
|
357
|
+
return list(value)
|
|
358
|
+
elif expected_type == "object":
|
|
359
|
+
if isinstance(value, str):
|
|
360
|
+
import json
|
|
361
|
+
|
|
362
|
+
return json.loads(value)
|
|
363
|
+
return dict(value)
|
|
364
|
+
|
|
365
|
+
return value
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class ToolRegistry:
|
|
369
|
+
"""Registry for managing tool definitions with validation."""
|
|
370
|
+
|
|
371
|
+
def __init__(self, validator: Optional[IToolValidator] = None):
|
|
372
|
+
self._tools: Dict[str, Dict[str, ToolDefinition]] = (
|
|
373
|
+
{}
|
|
374
|
+
) # session_id -> tool_name -> tool_def
|
|
375
|
+
self._validator = validator or DefaultToolValidator()
|
|
376
|
+
|
|
377
|
+
def register_tool(self, session_id: str, tool_def: ToolDefinition) -> None:
|
|
378
|
+
"""Register a tool definition."""
|
|
379
|
+
# Validate tool definition
|
|
380
|
+
errors = self._validator.validate_tool_definition(tool_def)
|
|
381
|
+
if errors:
|
|
382
|
+
raise ValueError(f"Invalid tool definition: {'; '.join(errors)}")
|
|
383
|
+
|
|
384
|
+
if session_id not in self._tools:
|
|
385
|
+
self._tools[session_id] = {}
|
|
386
|
+
|
|
387
|
+
self._tools[session_id][tool_def.name] = tool_def
|
|
388
|
+
|
|
389
|
+
def unregister_tool(self, session_id: str, tool_name: str) -> bool:
|
|
390
|
+
"""Unregister a tool."""
|
|
391
|
+
if session_id in self._tools and tool_name in self._tools[session_id]:
|
|
392
|
+
del self._tools[session_id][tool_name]
|
|
393
|
+
return True
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
def get_tool(self, session_id: str, tool_name: str) -> Optional[ToolDefinition]:
|
|
397
|
+
"""Get tool definition."""
|
|
398
|
+
return self._tools.get(session_id, {}).get(tool_name)
|
|
399
|
+
|
|
400
|
+
def list_tools(self, session_id: str) -> List[ToolDefinition]:
|
|
401
|
+
"""List tools for a session."""
|
|
402
|
+
return list(self._tools.get(session_id, {}).values())
|
|
403
|
+
|
|
404
|
+
def get_session_tools(self, session_id: str) -> Dict[str, ToolDefinition]:
|
|
405
|
+
"""Get all tools for a session."""
|
|
406
|
+
return self._tools.get(session_id, {}).copy()
|
|
407
|
+
|
|
408
|
+
def validate_execution_params(
|
|
409
|
+
self, session_id: str, tool_name: str, params: Dict[str, Any]
|
|
410
|
+
) -> Dict[str, Any]:
|
|
411
|
+
"""Validate and sanitize execution parameters."""
|
|
412
|
+
tool_def = self.get_tool(session_id, tool_name)
|
|
413
|
+
if not tool_def:
|
|
414
|
+
raise ValueError(f"Tool '{tool_name}' not found in session '{session_id}'")
|
|
415
|
+
|
|
416
|
+
# Validate parameters
|
|
417
|
+
errors = self._validator.validate_tool_parameters(tool_def, params)
|
|
418
|
+
if errors:
|
|
419
|
+
raise ValueError(f"Invalid parameters: {'; '.join(errors)}")
|
|
420
|
+
|
|
421
|
+
# Sanitize parameters
|
|
422
|
+
return self._validator.sanitize_parameters(tool_def, params)
|
|
423
|
+
|
|
424
|
+
def clear_session_tools(self, session_id: str) -> None:
|
|
425
|
+
"""Clear all tools for a session."""
|
|
426
|
+
if session_id in self._tools:
|
|
427
|
+
del self._tools[session_id]
|
|
428
|
+
|
|
429
|
+
def get_tool_stats(self) -> Dict[str, Any]:
|
|
430
|
+
"""Get tool registry statistics."""
|
|
431
|
+
total_tools = sum(len(tools) for tools in self._tools.values())
|
|
432
|
+
sessions_with_tools = len([s for s in self._tools.values() if s])
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
"total_sessions": len(self._tools),
|
|
436
|
+
"sessions_with_tools": sessions_with_tools,
|
|
437
|
+
"total_tools": total_tools,
|
|
438
|
+
"tools_per_session": {
|
|
439
|
+
session_id: len(tools) for session_id, tools in self._tools.items()
|
|
440
|
+
},
|
|
441
|
+
}
|
|
File without changes
|