nc1709 1.15.4__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.
- nc1709/__init__.py +13 -0
- nc1709/agent/__init__.py +36 -0
- nc1709/agent/core.py +505 -0
- nc1709/agent/mcp_bridge.py +245 -0
- nc1709/agent/permissions.py +298 -0
- nc1709/agent/tools/__init__.py +21 -0
- nc1709/agent/tools/base.py +440 -0
- nc1709/agent/tools/bash_tool.py +367 -0
- nc1709/agent/tools/file_tools.py +454 -0
- nc1709/agent/tools/notebook_tools.py +516 -0
- nc1709/agent/tools/search_tools.py +322 -0
- nc1709/agent/tools/task_tool.py +284 -0
- nc1709/agent/tools/web_tools.py +555 -0
- nc1709/agents/__init__.py +17 -0
- nc1709/agents/auto_fix.py +506 -0
- nc1709/agents/test_generator.py +507 -0
- nc1709/checkpoints.py +372 -0
- nc1709/cli.py +3380 -0
- nc1709/cli_ui.py +1080 -0
- nc1709/cognitive/__init__.py +149 -0
- nc1709/cognitive/anticipation.py +594 -0
- nc1709/cognitive/context_engine.py +1046 -0
- nc1709/cognitive/council.py +824 -0
- nc1709/cognitive/learning.py +761 -0
- nc1709/cognitive/router.py +583 -0
- nc1709/cognitive/system.py +519 -0
- nc1709/config.py +155 -0
- nc1709/custom_commands.py +300 -0
- nc1709/executor.py +333 -0
- nc1709/file_controller.py +354 -0
- nc1709/git_integration.py +308 -0
- nc1709/github_integration.py +477 -0
- nc1709/image_input.py +446 -0
- nc1709/linting.py +519 -0
- nc1709/llm_adapter.py +667 -0
- nc1709/logger.py +192 -0
- nc1709/mcp/__init__.py +18 -0
- nc1709/mcp/client.py +370 -0
- nc1709/mcp/manager.py +407 -0
- nc1709/mcp/protocol.py +210 -0
- nc1709/mcp/server.py +473 -0
- nc1709/memory/__init__.py +20 -0
- nc1709/memory/embeddings.py +325 -0
- nc1709/memory/indexer.py +474 -0
- nc1709/memory/sessions.py +432 -0
- nc1709/memory/vector_store.py +451 -0
- nc1709/models/__init__.py +86 -0
- nc1709/models/detector.py +377 -0
- nc1709/models/formats.py +315 -0
- nc1709/models/manager.py +438 -0
- nc1709/models/registry.py +497 -0
- nc1709/performance/__init__.py +343 -0
- nc1709/performance/cache.py +705 -0
- nc1709/performance/pipeline.py +611 -0
- nc1709/performance/tiering.py +543 -0
- nc1709/plan_mode.py +362 -0
- nc1709/plugins/__init__.py +17 -0
- nc1709/plugins/agents/__init__.py +18 -0
- nc1709/plugins/agents/django_agent.py +912 -0
- nc1709/plugins/agents/docker_agent.py +623 -0
- nc1709/plugins/agents/fastapi_agent.py +887 -0
- nc1709/plugins/agents/git_agent.py +731 -0
- nc1709/plugins/agents/nextjs_agent.py +867 -0
- nc1709/plugins/base.py +359 -0
- nc1709/plugins/manager.py +411 -0
- nc1709/plugins/registry.py +337 -0
- nc1709/progress.py +443 -0
- nc1709/prompts/__init__.py +22 -0
- nc1709/prompts/agent_system.py +180 -0
- nc1709/prompts/task_prompts.py +340 -0
- nc1709/prompts/unified_prompt.py +133 -0
- nc1709/reasoning_engine.py +541 -0
- nc1709/remote_client.py +266 -0
- nc1709/shell_completions.py +349 -0
- nc1709/slash_commands.py +649 -0
- nc1709/task_classifier.py +408 -0
- nc1709/version_check.py +177 -0
- nc1709/web/__init__.py +8 -0
- nc1709/web/server.py +950 -0
- nc1709/web/templates/index.html +1127 -0
- nc1709-1.15.4.dist-info/METADATA +858 -0
- nc1709-1.15.4.dist-info/RECORD +86 -0
- nc1709-1.15.4.dist-info/WHEEL +5 -0
- nc1709-1.15.4.dist-info/entry_points.txt +2 -0
- nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
- nc1709-1.15.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool Base Classes and Registry
|
|
3
|
+
|
|
4
|
+
Provides the foundation for the agentic tool system:
|
|
5
|
+
- Tool: Base class for all tools
|
|
6
|
+
- ToolResult: Standard result format
|
|
7
|
+
- ToolRegistry: Central tool management
|
|
8
|
+
- ToolPermission: Permission levels for tools
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from enum import Enum
|
|
15
|
+
from typing import Any, Callable, Dict, List, Optional, Type, Union
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ToolPermission(Enum):
|
|
20
|
+
"""Permission levels for tool execution"""
|
|
21
|
+
AUTO = "auto" # Execute without asking
|
|
22
|
+
ASK = "ask" # Ask user before executing
|
|
23
|
+
DENY = "deny" # Never allow execution
|
|
24
|
+
ASK_ONCE = "ask_once" # Ask once per session, then auto
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ToolParameter:
|
|
29
|
+
"""Definition of a tool parameter"""
|
|
30
|
+
name: str
|
|
31
|
+
description: str
|
|
32
|
+
type: str = "string" # string, integer, number, boolean, array, object
|
|
33
|
+
required: bool = True
|
|
34
|
+
default: Any = None
|
|
35
|
+
enum: Optional[List[str]] = None
|
|
36
|
+
|
|
37
|
+
def to_json_schema(self) -> Dict[str, Any]:
|
|
38
|
+
"""Convert to JSON Schema format for LLM tool calling"""
|
|
39
|
+
schema = {
|
|
40
|
+
"type": self.type,
|
|
41
|
+
"description": self.description,
|
|
42
|
+
}
|
|
43
|
+
if self.enum:
|
|
44
|
+
schema["enum"] = self.enum
|
|
45
|
+
if self.default is not None:
|
|
46
|
+
schema["default"] = self.default
|
|
47
|
+
return schema
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class ToolResult:
|
|
52
|
+
"""Standard result format for tool execution"""
|
|
53
|
+
success: bool
|
|
54
|
+
output: str
|
|
55
|
+
error: Optional[str] = None
|
|
56
|
+
data: Any = None
|
|
57
|
+
duration_ms: float = 0
|
|
58
|
+
tool_name: str = ""
|
|
59
|
+
target: str = ""
|
|
60
|
+
|
|
61
|
+
def to_message(self) -> str:
|
|
62
|
+
"""Convert to a message suitable for LLM context"""
|
|
63
|
+
if self.success:
|
|
64
|
+
return self.output
|
|
65
|
+
else:
|
|
66
|
+
return f"Error: {self.error or 'Unknown error'}\n{self.output}"
|
|
67
|
+
|
|
68
|
+
def __str__(self) -> str:
|
|
69
|
+
if self.success:
|
|
70
|
+
return f"✓ {self.tool_name}({self.target}) - {len(self.output)} chars"
|
|
71
|
+
else:
|
|
72
|
+
return f"✗ {self.tool_name}({self.target}) - {self.error}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class Tool(ABC):
|
|
76
|
+
"""
|
|
77
|
+
Base class for all agent tools.
|
|
78
|
+
|
|
79
|
+
To create a new tool:
|
|
80
|
+
1. Inherit from Tool
|
|
81
|
+
2. Set name, description, parameters
|
|
82
|
+
3. Implement execute() method
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
class ReadTool(Tool):
|
|
86
|
+
name = "Read"
|
|
87
|
+
description = "Read contents of a file"
|
|
88
|
+
parameters = [
|
|
89
|
+
ToolParameter("file_path", "Path to file", required=True),
|
|
90
|
+
ToolParameter("limit", "Max lines to read", type="integer", required=False),
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
def execute(self, file_path: str, limit: int = None) -> ToolResult:
|
|
94
|
+
# Implementation here
|
|
95
|
+
pass
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# Class attributes to be overridden by subclasses
|
|
99
|
+
name: str = "BaseTool"
|
|
100
|
+
description: str = "Base tool class"
|
|
101
|
+
parameters: List[ToolParameter] = []
|
|
102
|
+
permission: ToolPermission = ToolPermission.ASK
|
|
103
|
+
category: str = "general"
|
|
104
|
+
|
|
105
|
+
def __init__(self):
|
|
106
|
+
"""Initialize the tool"""
|
|
107
|
+
self._approved_once = False
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
110
|
+
def execute(self, **kwargs) -> ToolResult:
|
|
111
|
+
"""
|
|
112
|
+
Execute the tool with given parameters.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
**kwargs: Tool-specific parameters
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
ToolResult with success status and output
|
|
119
|
+
"""
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
def validate_params(self, **kwargs) -> Optional[str]:
|
|
123
|
+
"""
|
|
124
|
+
Validate parameters before execution.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
**kwargs: Parameters to validate
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Error message if validation fails, None if OK
|
|
131
|
+
"""
|
|
132
|
+
for param in self.parameters:
|
|
133
|
+
if param.required and param.name not in kwargs:
|
|
134
|
+
return f"Missing required parameter: {param.name}"
|
|
135
|
+
|
|
136
|
+
if param.name in kwargs:
|
|
137
|
+
value = kwargs[param.name]
|
|
138
|
+
# Type validation
|
|
139
|
+
if param.type == "integer" and not isinstance(value, int):
|
|
140
|
+
try:
|
|
141
|
+
int(value)
|
|
142
|
+
except (ValueError, TypeError):
|
|
143
|
+
return f"Parameter '{param.name}' must be an integer"
|
|
144
|
+
elif param.type == "number" and not isinstance(value, (int, float)):
|
|
145
|
+
try:
|
|
146
|
+
float(value)
|
|
147
|
+
except (ValueError, TypeError):
|
|
148
|
+
return f"Parameter '{param.name}' must be a number"
|
|
149
|
+
elif param.type == "boolean" and not isinstance(value, bool):
|
|
150
|
+
return f"Parameter '{param.name}' must be a boolean"
|
|
151
|
+
|
|
152
|
+
# Enum validation
|
|
153
|
+
if param.enum and value not in param.enum:
|
|
154
|
+
return f"Parameter '{param.name}' must be one of: {param.enum}"
|
|
155
|
+
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
def run(self, **kwargs) -> ToolResult:
|
|
159
|
+
"""
|
|
160
|
+
Run the tool with validation and timing.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
**kwargs: Tool parameters
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
ToolResult with timing information
|
|
167
|
+
"""
|
|
168
|
+
# Validate parameters
|
|
169
|
+
error = self.validate_params(**kwargs)
|
|
170
|
+
if error:
|
|
171
|
+
return ToolResult(
|
|
172
|
+
success=False,
|
|
173
|
+
output="",
|
|
174
|
+
error=error,
|
|
175
|
+
tool_name=self.name,
|
|
176
|
+
target=self._get_target(**kwargs),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Execute with timing
|
|
180
|
+
start_time = time.time()
|
|
181
|
+
try:
|
|
182
|
+
result = self.execute(**kwargs)
|
|
183
|
+
result.duration_ms = (time.time() - start_time) * 1000
|
|
184
|
+
result.tool_name = self.name
|
|
185
|
+
result.target = result.target or self._get_target(**kwargs)
|
|
186
|
+
return result
|
|
187
|
+
except Exception as e:
|
|
188
|
+
return ToolResult(
|
|
189
|
+
success=False,
|
|
190
|
+
output="",
|
|
191
|
+
error=str(e),
|
|
192
|
+
duration_ms=(time.time() - start_time) * 1000,
|
|
193
|
+
tool_name=self.name,
|
|
194
|
+
target=self._get_target(**kwargs),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def _get_target(self, **kwargs) -> str:
|
|
198
|
+
"""Get a short target description for display"""
|
|
199
|
+
# Use first required parameter as target
|
|
200
|
+
for param in self.parameters:
|
|
201
|
+
if param.required and param.name in kwargs:
|
|
202
|
+
value = str(kwargs[param.name])
|
|
203
|
+
if len(value) > 40:
|
|
204
|
+
value = value[:37] + "..."
|
|
205
|
+
return value
|
|
206
|
+
return ""
|
|
207
|
+
|
|
208
|
+
def to_function_schema(self) -> Dict[str, Any]:
|
|
209
|
+
"""
|
|
210
|
+
Convert tool to OpenAI-style function schema for LLM tool calling.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Dict suitable for LLM function calling API
|
|
214
|
+
"""
|
|
215
|
+
properties = {}
|
|
216
|
+
required = []
|
|
217
|
+
|
|
218
|
+
for param in self.parameters:
|
|
219
|
+
properties[param.name] = param.to_json_schema()
|
|
220
|
+
if param.required:
|
|
221
|
+
required.append(param.name)
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
"type": "function",
|
|
225
|
+
"function": {
|
|
226
|
+
"name": self.name,
|
|
227
|
+
"description": self.description,
|
|
228
|
+
"parameters": {
|
|
229
|
+
"type": "object",
|
|
230
|
+
"properties": properties,
|
|
231
|
+
"required": required,
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
def get_help(self) -> str:
|
|
237
|
+
"""Get help text for this tool"""
|
|
238
|
+
lines = [
|
|
239
|
+
f"Tool: {self.name}",
|
|
240
|
+
f"Description: {self.description}",
|
|
241
|
+
f"Permission: {self.permission.value}",
|
|
242
|
+
"",
|
|
243
|
+
"Parameters:",
|
|
244
|
+
]
|
|
245
|
+
for param in self.parameters:
|
|
246
|
+
req = "(required)" if param.required else "(optional)"
|
|
247
|
+
lines.append(f" {param.name} [{param.type}] {req}")
|
|
248
|
+
lines.append(f" {param.description}")
|
|
249
|
+
if param.default is not None:
|
|
250
|
+
lines.append(f" Default: {param.default}")
|
|
251
|
+
if param.enum:
|
|
252
|
+
lines.append(f" Options: {', '.join(param.enum)}")
|
|
253
|
+
|
|
254
|
+
return "\n".join(lines)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class ToolRegistry:
|
|
258
|
+
"""
|
|
259
|
+
Central registry for all available tools.
|
|
260
|
+
|
|
261
|
+
Manages tool registration, lookup, and permission checking.
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
def __init__(self):
|
|
265
|
+
"""Initialize the registry"""
|
|
266
|
+
self._tools: Dict[str, Tool] = {}
|
|
267
|
+
self._permission_overrides: Dict[str, ToolPermission] = {}
|
|
268
|
+
self._session_approvals: set = set() # Tools approved for this session
|
|
269
|
+
|
|
270
|
+
def register(self, tool: Tool) -> None:
|
|
271
|
+
"""
|
|
272
|
+
Register a tool.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
tool: Tool instance to register
|
|
276
|
+
"""
|
|
277
|
+
self._tools[tool.name] = tool
|
|
278
|
+
|
|
279
|
+
def register_class(self, tool_class: Type[Tool]) -> None:
|
|
280
|
+
"""
|
|
281
|
+
Register a tool class (will be instantiated).
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
tool_class: Tool class to register
|
|
285
|
+
"""
|
|
286
|
+
tool = tool_class()
|
|
287
|
+
self.register(tool)
|
|
288
|
+
|
|
289
|
+
def unregister(self, name: str) -> bool:
|
|
290
|
+
"""
|
|
291
|
+
Unregister a tool by name.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
name: Tool name
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
True if tool was removed, False if not found
|
|
298
|
+
"""
|
|
299
|
+
if name in self._tools:
|
|
300
|
+
del self._tools[name]
|
|
301
|
+
return True
|
|
302
|
+
return False
|
|
303
|
+
|
|
304
|
+
def get(self, name: str) -> Optional[Tool]:
|
|
305
|
+
"""
|
|
306
|
+
Get a tool by name.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
name: Tool name
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
Tool instance or None
|
|
313
|
+
"""
|
|
314
|
+
return self._tools.get(name)
|
|
315
|
+
|
|
316
|
+
def get_all(self) -> List[Tool]:
|
|
317
|
+
"""Get all registered tools"""
|
|
318
|
+
return list(self._tools.values())
|
|
319
|
+
|
|
320
|
+
def get_by_category(self, category: str) -> List[Tool]:
|
|
321
|
+
"""Get all tools in a category"""
|
|
322
|
+
return [t for t in self._tools.values() if t.category == category]
|
|
323
|
+
|
|
324
|
+
def list_names(self) -> List[str]:
|
|
325
|
+
"""Get list of all tool names"""
|
|
326
|
+
return list(self._tools.keys())
|
|
327
|
+
|
|
328
|
+
def set_permission(self, tool_name: str, permission: ToolPermission) -> None:
|
|
329
|
+
"""
|
|
330
|
+
Override permission for a specific tool.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
tool_name: Name of tool
|
|
334
|
+
permission: New permission level
|
|
335
|
+
"""
|
|
336
|
+
self._permission_overrides[tool_name] = permission
|
|
337
|
+
|
|
338
|
+
def get_permission(self, tool_name: str) -> ToolPermission:
|
|
339
|
+
"""
|
|
340
|
+
Get effective permission for a tool.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
tool_name: Name of tool
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
Effective permission level
|
|
347
|
+
"""
|
|
348
|
+
# Check overrides first
|
|
349
|
+
if tool_name in self._permission_overrides:
|
|
350
|
+
return self._permission_overrides[tool_name]
|
|
351
|
+
|
|
352
|
+
# Check tool's default
|
|
353
|
+
tool = self.get(tool_name)
|
|
354
|
+
if tool:
|
|
355
|
+
return tool.permission
|
|
356
|
+
|
|
357
|
+
return ToolPermission.DENY
|
|
358
|
+
|
|
359
|
+
def needs_approval(self, tool_name: str) -> bool:
|
|
360
|
+
"""
|
|
361
|
+
Check if a tool needs user approval to run.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
tool_name: Name of tool
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
True if approval is needed
|
|
368
|
+
"""
|
|
369
|
+
permission = self.get_permission(tool_name)
|
|
370
|
+
|
|
371
|
+
if permission == ToolPermission.AUTO:
|
|
372
|
+
return False
|
|
373
|
+
elif permission == ToolPermission.DENY:
|
|
374
|
+
return True # Will be denied anyway
|
|
375
|
+
elif permission == ToolPermission.ASK_ONCE:
|
|
376
|
+
return tool_name not in self._session_approvals
|
|
377
|
+
else: # ASK
|
|
378
|
+
return True
|
|
379
|
+
|
|
380
|
+
def approve_for_session(self, tool_name: str) -> None:
|
|
381
|
+
"""Mark a tool as approved for this session"""
|
|
382
|
+
self._session_approvals.add(tool_name)
|
|
383
|
+
|
|
384
|
+
def clear_session_approvals(self) -> None:
|
|
385
|
+
"""Clear all session approvals"""
|
|
386
|
+
self._session_approvals.clear()
|
|
387
|
+
|
|
388
|
+
def get_function_schemas(self) -> List[Dict[str, Any]]:
|
|
389
|
+
"""
|
|
390
|
+
Get all tools as OpenAI-style function schemas.
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
List of function schemas for LLM tool calling
|
|
394
|
+
"""
|
|
395
|
+
return [tool.to_function_schema() for tool in self._tools.values()]
|
|
396
|
+
|
|
397
|
+
def get_tools_prompt(self) -> str:
|
|
398
|
+
"""
|
|
399
|
+
Generate a tools description for LLMs that don't support function calling.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Text description of available tools
|
|
403
|
+
"""
|
|
404
|
+
lines = ["Available tools:"]
|
|
405
|
+
for tool in self._tools.values():
|
|
406
|
+
lines.append(f"\n## {tool.name}")
|
|
407
|
+
lines.append(f"{tool.description}")
|
|
408
|
+
lines.append("Parameters:")
|
|
409
|
+
for param in tool.parameters:
|
|
410
|
+
req = "(required)" if param.required else "(optional)"
|
|
411
|
+
lines.append(f" - {param.name}: {param.description} {req}")
|
|
412
|
+
|
|
413
|
+
lines.append("\n\nTo use a tool, respond with:")
|
|
414
|
+
lines.append("```tool")
|
|
415
|
+
lines.append('{"tool": "ToolName", "parameters": {"param1": "value1"}}')
|
|
416
|
+
lines.append("```")
|
|
417
|
+
|
|
418
|
+
return "\n".join(lines)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# Global default registry
|
|
422
|
+
_default_registry: Optional[ToolRegistry] = None
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def get_default_registry() -> ToolRegistry:
|
|
426
|
+
"""Get or create the default tool registry"""
|
|
427
|
+
global _default_registry
|
|
428
|
+
if _default_registry is None:
|
|
429
|
+
_default_registry = ToolRegistry()
|
|
430
|
+
return _default_registry
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def register_tool(tool: Tool) -> None:
|
|
434
|
+
"""Register a tool in the default registry"""
|
|
435
|
+
get_default_registry().register(tool)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def register_tool_class(tool_class: Type[Tool]) -> None:
|
|
439
|
+
"""Register a tool class in the default registry"""
|
|
440
|
+
get_default_registry().register_class(tool_class)
|