Files
JARVIS/backend/app/agents/tools/builtins/dev_tools.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

156 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.4"""
from typing import Any
from app.agents.tools.base import ReadTool, WriteTool
from app.agents.tools.manifest import (
PermissionClass,
SideEffectScope,
)
class LSPTools(ReadTool):
"""语言服务器协议工具集
提供代码导航、查找引用等 LSP 功能。
"""
def __init__(self):
super().__init__(
name="lsp_tools",
description="LSP 代码导航和查找引用",
permission_class=PermissionClass.READ,
side_effect_scope=SideEffectScope.NONE,
tags=["development", "lsp", "code"],
)
def get_parameters(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["goto_definition", "find_references", "document_symbols"],
"description": "LSP 操作类型",
},
"file": {
"type": "string",
"description": "文件路径",
},
"line": {
"type": "integer",
"description": "行号1-based",
},
"character": {
"type": "integer",
"description": "列号0-based",
},
},
"required": ["action", "file"],
}
def get_return_schema(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"success": {"type": "boolean"},
"results": {"type": "array"},
},
}
async def execute(
self,
action: str,
file: str,
line: int = 1,
character: int = 0,
) -> dict[str, Any]:
# 注意:实际 LSP 调用需要通过 lsp-utils 或类似库
# 这里只是一个框架实现
return {
"success": False,
"error": f"LSP action '{action}' not fully implemented - requires LSP server integration",
"action": action,
"file": file,
"position": {"line": line, "character": character},
}
class GitTool(ReadTool):
"""Git 操作工具
提供常用的 Git 操作。
"""
def __init__(self, repo_path: str = "."):
super().__init__(
name="git",
description="执行 Git 命令",
permission_class=PermissionClass.EXTERNAL,
side_effect_scope=SideEffectScope.LOCAL_STATE,
requires_confirmation=True,
tags=["development", "git", "version-control"],
)
self.repo_path = repo_path
def get_parameters(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "Git 子命令和参数,如 'status''log --oneline -10'",
},
"repo_path": {
"type": "string",
"description": "仓库路径(可选)",
},
},
"required": ["command"],
}
def get_return_schema(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"stdout": {"type": "string"},
"stderr": {"type": "string"},
"returncode": {"type": "integer"},
},
}
async def execute(self, command: str, repo_path: str | None = None) -> dict[str, Any]:
import asyncio
import os
import platform
repo = repo_path or self.repo_path
# 构建完整的 git 命令
if platform.system() == "Windows":
full_command = f'git -C "{repo}" {command}'
else:
full_command = f"git -C '{repo}' {command}"
try:
process = await asyncio.create_subprocess_shell(
full_command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await process.communicate()
return {
"stdout": stdout.decode("utf-8", errors="replace"),
"stderr": stderr.decode("utf-8", errors="replace"),
"returncode": process.returncode,
}
except Exception as e:
return {
"stdout": "",
"stderr": str(e),
"returncode": -1,
}