Files
JARVIS/backend/app/agents/tools/base.py
WIN-JHFT4D3SIVT\caoxiaozhu e5bd492d74 feat(agents): Phase 6 tool system refactoring
Phase 6.1: ToolRegistry infrastructure
- Add ToolManifest with ToolCategory, PermissionClass, SideEffectScope
- Add ToolRegistry singleton with register/get/unregister/list/search
- Add BaseTool abstract class with ReadTool/WriteTool/DBWriteTool/ExternalTool/NetworkTool subclasses
- Add migration layer for backward compatibility

Phase 6.2: Hook interception system
- Add HookType (PRE_TOOL_USE, POST_TOOL_USE, TOOL_ERROR, TOOL_SKIP)
- Add HookManager with singleton for hook registration
- Add HookExecutor for pre/post/error hook execution

Phase 6.3: Streaming execution
- Add StreamingToolExecutor with batch execution support

Phase 6.4: New builtin tools
- Add file_tools: GlobTool, GrepTool, ReadFileTool, WriteFileTool
- Add system_tools: BashTool, PowerShellTool
- Add dev_tools: LSPTools, GitTool
- Add collaboration_tools: TeamAgentTool, TaskBroadcastTool

Tests: 29 passed
2026-04-04 22:47:48 +08:00

162 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""工具基类 - 工具系统重构 Phase 6.1"""
from abc import ABC, abstractmethod
from typing import Any, Generic, TypeVar
from app.agents.tools.manifest import (
PermissionClass,
SideEffectScope,
ToolCategory,
ToolManifest,
)
T = TypeVar("T")
class BaseTool(ABC, Generic[T]):
"""工具基类
提供工具的标准接口和默认实现。
所有自定义工具应继承此类。
"""
def __init__(
self,
name: str,
description: str,
category: ToolCategory,
permission_class: PermissionClass,
side_effect_scope: SideEffectScope = SideEffectScope.NONE,
requires_confirmation: bool = False,
is_streaming: bool = False,
tags: list[str] | None = None,
):
self.name = name
self.description = description
self.category = category
self.permission_class = permission_class
self.side_effect_scope = side_effect_scope
self.requires_confirmation = requires_confirmation
self.is_streaming = is_streaming
self.tags = tags or []
def get_manifest(self) -> ToolManifest:
"""获取工具元数据
Returns:
工具元数据
"""
return ToolManifest(
name=self.name,
description=self.description,
category=self.category,
parameters=self.get_parameters(),
return_schema=self.get_return_schema(),
permission_class=self.permission_class,
side_effect_scope=self.side_effect_scope,
requires_confirmation=self.requires_confirmation,
is_streaming=self.is_streaming,
tags=self.tags,
)
@abstractmethod
def get_parameters(self) -> dict[str, Any]:
"""获取参数 SchemaJSON Schema 格式)
Returns:
参数 schema
"""
pass
@abstractmethod
def get_return_schema(self) -> dict[str, Any]:
"""获取返回值 Schema
Returns:
返回值 schema
"""
pass
@abstractmethod
async def execute(self, **kwargs) -> T:
"""执行工具
Args:
**kwargs: 工具参数
Returns:
执行结果
"""
pass
async def execute_safe(self, **kwargs) -> dict[str, Any]:
"""安全执行工具,捕获异常
Args:
**kwargs: 工具参数
Returns:
包含 success 和 result/error 的字典
"""
try:
result = await self.execute(**kwargs)
return {"success": True, "result": result}
except Exception as e:
return {"success": False, "error": str(e)}
def __repr__(self) -> str:
return f"<{self.__class__.__name__}(name={self.name!r})>"
class ReadTool(BaseTool):
"""只读工具基类"""
def __init__(self, **kwargs):
kwargs.setdefault("category", ToolCategory.READ)
kwargs.setdefault("permission_class", PermissionClass.READ)
kwargs.setdefault("side_effect_scope", SideEffectScope.NONE)
super().__init__(**kwargs)
class WriteTool(BaseTool):
"""写入工具基类"""
def __init__(self, **kwargs):
kwargs.setdefault("category", ToolCategory.WRITE)
kwargs.setdefault("permission_class", PermissionClass.WRITE)
kwargs.setdefault("side_effect_scope", SideEffectScope.LOCAL_STATE)
super().__init__(**kwargs)
class DBWriteTool(BaseTool):
"""数据库写入工具基类"""
def __init__(self, **kwargs):
kwargs.setdefault("category", ToolCategory.DB_WRITE)
kwargs.setdefault("permission_class", PermissionClass.WRITE)
kwargs.setdefault("side_effect_scope", SideEffectScope.DB_WRITE)
kwargs.setdefault("requires_confirmation", True)
super().__init__(**kwargs)
class ExternalTool(BaseTool):
"""外部工具基类(执行外部命令等)"""
def __init__(self, **kwargs):
kwargs.setdefault("category", ToolCategory.EXTERNAL)
kwargs.setdefault("permission_class", PermissionClass.EXTERNAL)
kwargs.setdefault("side_effect_scope", SideEffectScope.NETWORK)
kwargs.setdefault("requires_confirmation", True)
super().__init__(**kwargs)
class NetworkTool(BaseTool):
"""网络工具基类"""
def __init__(self, **kwargs):
kwargs.setdefault("category", ToolCategory.NETWORK)
kwargs.setdefault("permission_class", PermissionClass.EXTERNAL)
kwargs.setdefault("side_effect_scope", SideEffectScope.NETWORK)
super().__init__(**kwargs)