工具¶
基础工具¶
注意事项¶
在工具的当前支持中,我们可以采用迭代器/生成器的方式输出,例如使用yield语句。此外,我们的工具现在支持在一个函数中同时使用yield和return语句。不同于传统的生成器,您不再需要捕获StopIteration异常来获取return语句的值,可以直接在循环中处理所有结果。
但需要注意这种yield与return混用的模式权支持在同步工具中使用,异步工具中不支持。因为目前Python对于Async模式下的生成器,还有没有特别好的办法直接获取最终的return值。
但无论是同步还是异步工具,我们都建议您使用for循环来获取所有生成器的结果,而不是使用next函数。也建议在封装工具时返回数据全部使用yield语句,可以配合使用return结束迭代,但不要使用return返回数据。
示例:非Async生成器工具¶
def simple_generator():
yield "yielded value 1"
yield "yielded value 2"
return "returned value"
def test_simple_generator() -> None:
gen = simple_generator()
try:
while True:
print(next(gen))
except StopIteration as e:
print("Generator return value:", e.value)
# 输出:
# yielded value 1
# yielded value 2
# Generator return value: returned value
在使用TFRobot的BaseTool基类时,您可以更简单地通过for循环来获取所有生成器的结果。
示例:Git Diff 工具封装¶
import subprocess
from pathlib import Path
from typing import ClassVar, Optional, Iterator
import cachetools
from tfrobot.drive.tool.base import BaseTool
from tfrobot.schema.drive.tool.base import ToolReturn, MessageMeta, MessageCategory
from tfrobot.schema.meta.tf_field import TFField
class GitDiffTool(BaseTool):
"""
GitDiff Tool
此工具用于查看项目的Git Diff信息,并支持通过配置的excludes参数排除不需差异对比的文件。
"""
name: ClassVar[str] = "git_diff"
version: ClassVar[str] = "0.0.1"
description: ClassVar[str] = "查看项目的Git Diff信息,支持文件排除配置。"
cache: cachetools.TTLCache = cachetools.TTLCache(maxsize=100, ttl=300)
project_root: Path
excludes: list[str] = TFField(default_factory=list)
def _run(self, tool_params: Optional[dict] = None, **kwargs) -> Iterator[ToolReturn] | ToolReturn:
# 获取所有变化的文件列表
if not self.cache.get("all_files"):
cmd = ["git", "diff", "--name-only"] + (self.excludes if self.excludes else [])
changed_files_result = subprocess.run(cmd, stdout=subprocess.PIPE, text=True, cwd=str(self.project_root))
self.cache["all_files"] = changed_files_result.stdout.splitlines()
changed_files = self.cache["all_files"]
if not changed_files:
raise ValueError("当前没有文件变化")
# 逐个显示文件的变化
for file in changed_files:
diff_result = subprocess.run(["git", "diff", file], stdout=subprocess.PIPE, text=True, cwd=str(self.project_root))
res = diff_result.stdout
yield ToolReturn(origin=res, msg_meta=MessageMeta(category=MessageCategory.Map, summary=f"{res[:30]}...已省略...{res[-30:]}"))
return ToolReturn(origin="你已经查看完所有的变更文件,请根据目前的信息再次整合所有的变更,形成一个中英双语的Commit Message", msg_meta=MessageMeta(category=MessageCategory.Map, summary=""))
async def _async_run(self, tool_params: Optional[dict] = None, **kwargs) -> Iterator[ToolReturn]:
return self._run(tool_params, **kwargs)
def test_git_diff_tool() -> None:
"""
测试封装的Git Diff Tool可以正常运行
"""
git_diff_tool = GitDiffTool(project_root=Path("project_root"), excludes=[":(exclude)poetry.lock", ":(exclude)*.png", ":(exclude)*.svg"])
for r in git_diff_tool.run():
print(r.origin)
在以上封装中,您仅需使用for循环即可获取所有结果,包括return语句返回的最终ToolReturn对象。