# BuiltinTool 注册机制设计说明

本文档面向 turbo-agent 内部开发者，说明 `turbo_agent_core.schema.utils.tools` 中内置工具注册机制的设计目标、核心对象、执行链路与当前边界。

## 1. 背景与目标

Turbo Agent 中的工具分为多种类型：

- `APITool`：通过 HTTP/API 请求调用外部能力。
- `BuiltinTool`：通过本地 Python 代码直接执行内部能力。
- `FrontendTool`：需要在前端环境中完成交互或执行的工具。

其中 `BuiltinTool` 的核心特点不是“如何调用网络”，而是“如何把一段 Python 函数/方法组织成一个完整的工具定义，并且在运行时安全地调用”。

这一机制需要同时满足以下目标：

1. 支持类似 LangChain 的注解式注册体验。
2. 不仅注册 handler，还要补齐 `Tool` 的基础字段与 schema 信息。
3. 支持按 `space/project` 组织工具，避免全局无命名空间注册。
4. 支持权限与平台信息注入。
5. 支持同步/异步后处理回调，便于观测、审计、结果变换。
6. 支持函数、类、对象三种工具组织方式。
7. 能被 Agent Runtime 透明调用，而不是只支持手工单独执行。

## 2. 模块边界

当前实现分布在以下位置：

- `turbo_agent_core.schema.agents.BuiltinTool`
- `turbo_agent_core.schema.agents.FrontendTool`
- `turbo_agent_core.schema.utils.tools`
- `turbo_agent_runtime.executors.tool.builtin_tool.BuiltinToolRuntime`
- `turbo_agent_runtime.executors.tool.frontend_tool.FrontendToolRuntime`
- `turbo_agent_runtime.executors.agent.AgentRuntime`

职责划分如下：

### 2.1 core.schema

负责定义工具实体的数据结构，例如：

- `builtin_name`
- `platform`
- `required_permissions`
- `tags`
- `execution_hint`

这些字段属于“工具定义本身”，必须能够被存储、传输、展示。

### 2.2 core.schema.utils.tools

负责工具注册与组织，是 BuiltinTool 机制的“控制面”：

- 注解注册
- 类/对象导出
- 路由组织
- 作用域归档
- schema 自动推导
- 权限校验
- 后处理回调
- 执行上下文注入

### 2.3 runtime

负责执行，是 BuiltinTool 机制的“数据面”：

- `BuiltinToolRuntime` 调用 registry 执行 handler
- `AgentRuntime` 透传用户/权限/notifier 等运行时上下文
- `FrontendToolRuntime` 负责前端等待与结果回写的执行模型

## 3. 核心设计对象

## 3.1 BuiltinToolExecutionContext

执行上下文对象，承载运行期信息。

主要字段：

- `name`：调用时传入的工具名
- `registration`：匹配到的注册记录
- `input_data`：工具输入
- `tool`：当前 `BuiltinTool` 定义对象
- `runtime_kwargs`：运行时透传参数
- `user_id` / `username`
- `permissions`
- `space_name`
- `project_name_id`
- `belong_to_project_path`
- `platform`

设计原因：

1. 避免在 handler 中到处手工解包 `kwargs`。
2. 允许权限校验、后处理器、handler 使用统一的上下文对象。
3. 为后续审计、trace、指标扩展保留稳定入口。

## 3.2 BuiltinToolRegistration

注册记录对象，表示“一个已经注册好的内部工具定义”。

它不仅保存 handler，也保存下列元数据：

- 名称与 `name_id`
- `input_schema` / `output_schema`
- `input_parameters` / `output_parameters`
- `space_name` / `project_name_id` / `belong_to_project_path`
- `platform`
- `required_permissions`
- `tags`
- `execution_hint`
- `permission_checker`
- `post_processors`
- `source`

设计原因：

注册表不能只是“函数名 -> 函数对象”的简单字典，否则无法构造完整的 `BuiltinTool` 实体，也无法做后续 UI 展示、导出、权限判断和路由。

## 3.3 BuiltinToolRegistry

全局单例注册表，是 BuiltinTool 机制的核心入口。

主要能力：

- `register()`：装饰器注册函数或类
- `register_handler()`：手工注册函数
- `register_provider()`：导出类/对象公开方法
- `include_toolset()`：统一挂载 toolset 中定义的工具
- `get()` / `get_tool_def()`：查询注册项或构造 `BuiltinTool`
- `execute()` / `aexecute()`：同步/异步执行工具
- `set_default_scope()` / `scoped()`：配置默认作用域

## 3.4 BuiltinToolSet

用于统一组织工具，模式类似 FastAPI 的 `APIRouter` 或 Typer 的命令分组。

toolset 层的职责：

1. 先收集工具定义。
2. 统一附加 `space/project/platform/tags/permissions`。
3. 再由 registry 统一挂载。

这样可以避免每个工具单独写一遍作用域配置。

## 4. 作用域设计

BuiltinTool 不采用“只有全局名称”的注册方式，而是按作用域键存储：

`builtin_name@belong_to_project_path`

例如：

- `sum_numbers@default`
- `create_issue@official/devtools`
- `sync_project@team_a/project_x`

### 4.1 默认作用域

- 默认 `space_name = "default"`
- 默认 `project_name_id = None`
- 若没有显式传入 `belong_to_project_path`，则自动按 `space_name/project_name_id` 组装

### 4.2 设计原因

这是为了满足以下场景：

1. 不同空间允许存在同名工具。
2. 相同工具名在不同项目下可以有不同权限或平台配置。
3. Agent 在运行时可以根据 `tool.belong_to_project_path` 精确命中工具定义。

## 5. 注解式注册设计

当前支持三种注册方式。

### 5.1 函数注册

通过 `builtin_tool()` 或 `registry.register()` 装饰普通函数。

适合：

- 简单工具
- 独立函数式能力
- 少量内置工具

### 5.2 类注册

将类通过 `@builtin_tool_provider()` 装饰，或显式传给 `registry.register_provider()`。

规则：

1. 仅导出不以下划线开头的方法。
2. 支持实例方法、`@staticmethod`、`@classmethod`。
3. 若类可无参实例化，则自动实例化；否则跳过需实例方法的导出。

适合：

- 将一组相关工具按领域组织
- 复用同一个类上的公共状态或方法

### 5.3 对象注册

对已实例化对象执行 provider 注册。

适合：

- 需要提前注入依赖的服务对象
- 工具依赖外部资源、缓存、数据库客户端等对象状态

## 6. schema 与参数自动推导

BuiltinTool 的完整定义不能全部手写，因此当前实现会自动从以下信息推导：

1. Python 类型注解
2. 函数签名默认值
3. docstring 中的摘要、参数说明、返回说明

### 6.1 输入推导

从函数签名中提取：

- 参数名
- 是否必填
- 默认值
- JSON Schema
- `Parameter` 列表

若有注入型参数，不会计入工具输入：

- `context`
- `tool`
- `runtime_kwargs`

### 6.2 输出推导

从返回值类型注解推导输出 schema。

若返回不是 object，则统一包成：

```json
{
	"type": "object",
	"properties": {
		"result": ...
	}
}
```

这样可以和现有 `Tool.validate_output()` 行为保持一致。

### 6.3 手工覆盖

自动推导只是默认行为。若用户在注册时显式传入：

- `input_schema`
- `output_schema`
- `description`

则以手工配置优先。

## 7. 权限模型

BuiltinTool 当前支持两层权限控制。

### 7.1 静态权限声明

通过 `required_permissions` 配置声明此工具需要哪些权限。

运行时从以下参数中读取用户权限：

- `permissions`
- `user_permissions`

若缺失则抛出 `PermissionError`。

### 7.2 动态权限校验

通过 `permission_checker(context)` 注入动态校验逻辑。

适合处理：

- 与用户角色、租户、项目状态相关的权限判断
- 需要根据输入参数做额外拦截
- 需要根据平台状态、凭据状态做准入控制

同步执行要求同步 checker，异步执行支持异步 checker。

## 8. 后处理回调模型

BuiltinTool 支持后处理回调链 `post_processors`。

回调签名：

```python
post_processor(context, result, error)
```

语义：

- `error is None`：表示执行成功
- `error is not None`：表示执行失败
- 返回 `None`：不修改结果
- 返回非 `None`：覆盖当前结果，传给后续回调

作用：

1. 结果标准化
2. 审计埋点
3. 指标采集
4. 输出脱敏
5. 按需包装结果结构

## 9. Agent Runtime 接入点

BuiltinTool 机制要真正可用，不能只停留在 registry 层。

因此本次实现对 runtime 做了两个关键补充。

### 9.1 BuiltinToolRuntime

`BuiltinToolRuntime.run/a_run` 在调用 registry 时，会透传：

- 当前 `tool` 定义对象
- 所有 `**kwargs`

这样 registry 才能正确获得：

- `belong_to_project_path`
- `user_id`
- `permissions`
- 其它运行期上下文

### 9.2 AgentRuntime

Agent 执行工具时，原先没有把 `**kwargs` 继续透传给工具层。现在已经补上。

这一步非常关键，因为如果不透传：

1. BuiltinTool 的权限校验拿不到用户权限。
2. FrontendTool 拿不到 `record_creator` / `record_fetcher` / `frontend_notifier`。
3. 运行时上下文会在 Agent -> Tool 链路中丢失。

## 10. FrontendTool 当前边界

当前 `FrontendTool` 已补齐定义字段：

- `platform`
- `frontend_handler`
- `frontend_module`
- `wait_strategy`
- `timeout_ms`
- `required_permissions`
- `tags`
- `execution_hint`

但前端注册机制仍未完全定稿。

当前 runtime 采用的是“执行注入”模式：

1. 创建待执行记录
2. 通过 `frontend_notifier` 通知前端
3. 通过 `record_fetcher` 轮询前端执行结果

这说明 FrontendTool 的定义层已经可承载完整配置，但其“前端如何注册 handler、如何统一组织模块”仍需后续单独设计。

## 11. 当前推荐模式

在现阶段，推荐以下组织方式：

### 11.1 少量工具

直接用 `builtin_tool()` 装饰函数。

### 11.2 一组相关工具

定义类并优先用 `@builtin_tool_provider()` 导出；对象场景再使用 `builtin_tool_provider(instance, ...)` 或 toolset 的 `toolset()`。

### 11.3 按空间/项目成组挂载

使用 `BuiltinToolSet`：

1. 在模块内部声明 toolset。
2. 将函数和 provider 注册到 toolset。
3. 在应用启动时统一 `include_toolset()`。

这是当前最接近 FastAPI / Typer 风格的统一组织方式。

## 12. 后续演进建议

当前机制已经满足 BuiltinTool 的核心需求，但还可以继续演进：

1. 为 FrontendTool 增加对称的 `FrontendToolRegistry` 与 router 机制。
2. 将 BuiltinTool 的注册元数据与 store/cloud 持久化模型对齐。
3. 为 provider 注册增加显式排除/包含机制，而不只依赖下划线规则。
4. 为注入参数增加更清晰的约定与类型别名。
5. 增加更完整的 docstring 解析规则，例如 Google/Numpy 风格兼容增强。

## 13. 总结

BuiltinTool 机制当前已经从“按名字调用一个函数”的简化实现，升级为一套完整的工具注册与组织框架，具备以下特征：

- 注解式注册
- 完整工具定义承载
- 作用域化路由
- 权限校验
- 后处理回调
- 函数/类/对象三种组织方式
- 与 Agent Runtime 的上下文联通

这套设计的目标不是模仿 LangChain 的表层 API，而是让 BuiltinTool 真正成为 Turbo Agent 内部统一工具系统的一等公民。
