Skip to content

工具

基础工具

注意事项

在工具的当前支持中,我们可以采用迭代器/生成器的方式输出,例如使用yield语句。此外,我们的工具现在支持在一个函数中同时使用yieldreturn语句。不同于传统的生成器,您不再需要捕获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

在使用TFRobotBaseTool基类时,您可以更简单地通过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对象。