| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- """
- Glob Tool - 文件模式匹配工具
- 参考:vendor/opencode/packages/opencode/src/tool/glob.ts
- 核心功能:
- - 使用 glob 模式匹配文件
- - 按修改时间排序
- - 限制返回数量
- """
- import glob as glob_module
- from pathlib import Path
- from typing import Optional
- from agent.tools import tool, ToolResult, ToolContext
- # 常量
- LIMIT = 100 # 最大返回数量(参考 opencode glob.ts:35)
- @tool(description="使用 glob 模式匹配文件", hidden_params=["context"])
- async def glob_files(
- pattern: str,
- path: Optional[str] = None,
- context: Optional[ToolContext] = None
- ) -> ToolResult:
- """
- 使用 glob 模式匹配文件
- 参考 OpenCode 实现
- Args:
- pattern: glob 模式(如 "*.py", "src/**/*.ts")
- path: 搜索目录(默认当前目录)
- context: 工具上下文
- Returns:
- ToolResult: 匹配的文件列表
- """
- # 确定搜索路径
- search_path = Path(path) if path else Path.cwd()
- if not search_path.is_absolute():
- search_path = Path.cwd() / search_path
- if not search_path.exists():
- return ToolResult(
- title="目录不存在",
- output=f"搜索目录不存在: {path}",
- error="Directory not found"
- )
- # 执行 glob 搜索
- try:
- # 使用 pathlib 的 glob(支持 ** 递归)
- if "**" in pattern:
- matches = list(search_path.glob(pattern))
- else:
- # 使用标准 glob(更快)
- pattern_path = search_path / pattern
- matches = [Path(p) for p in glob_module.glob(str(pattern_path))]
- # 过滤掉目录,只保留文件
- file_matches = [m for m in matches if m.is_file()]
- # 按修改时间排序(参考 opencode:47-56)
- file_matches_with_mtime = []
- for file_path in file_matches:
- try:
- mtime = file_path.stat().st_mtime
- file_matches_with_mtime.append((file_path, mtime))
- except Exception:
- file_matches_with_mtime.append((file_path, 0))
- # 按修改时间降序排序(最新的在前)
- file_matches_with_mtime.sort(key=lambda x: x[1], reverse=True)
- # 限制数量
- truncated = len(file_matches_with_mtime) > LIMIT
- file_matches_with_mtime = file_matches_with_mtime[:LIMIT]
- # 格式化输出
- if not file_matches_with_mtime:
- output = "未找到匹配的文件"
- else:
- file_paths = [str(f[0]) for f in file_matches_with_mtime]
- output = "\n".join(file_paths)
- if truncated:
- output += f"\n\n(结果已截断。考虑使用更具体的路径或模式。)"
- return ToolResult(
- title=f"匹配: {pattern}",
- output=output,
- metadata={
- "count": len(file_matches_with_mtime),
- "truncated": truncated,
- "pattern": pattern,
- "search_path": str(search_path)
- }
- )
- except Exception as e:
- return ToolResult(
- title="Glob 错误",
- output=f"glob 匹配失败: {str(e)}",
- error=str(e)
- )
|