集成新的Beaver后端服务到应用实例中,替换原有的nanobot实现。 主要变更包括: - 在Dockerfile和环境配置中添加Beaver相关路径和配置变量 - 更新工作目录结构从.nanobot到.beaver - 实现Beaver引擎加载器,支持配置文件加载和工具组装 - 添加内置工具如ListDirectoryTool、ReadFileTool、SearchFilesTool - 更新消息处理流程,支持通道适配器和网关模式 - 重构技能系统,支持显式工具提示和嵌入式检索 - 改进错误处理和生命周期管理 此变更使应用实例能够使用统一的Beaver后端进行AI代理运行时管理。
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
"""Beaver 工具注册表。
|
||
|
||
这层只做三件事:
|
||
1. 注册工具
|
||
2. 按名称查找工具
|
||
3. 导出 provider 可消费的 tool schemas
|
||
|
||
不要把执行逻辑塞进这里。
|
||
执行属于 runtime/executor,那样边界更清晰。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections.abc import Sequence
|
||
from typing import Iterable
|
||
|
||
from beaver.tools.base import BaseTool, ToolSpec
|
||
|
||
|
||
class ToolRegistry:
|
||
"""统一维护当前 runtime 可用的工具集合。"""
|
||
|
||
def __init__(self) -> None:
|
||
self._tools: dict[str, BaseTool] = {}
|
||
|
||
def register(self, tool: BaseTool, *, replace: bool = False) -> None:
|
||
"""注册一个工具。
|
||
|
||
默认不允许重名覆盖,避免 loader/runtime 不小心把同名工具静默冲掉。
|
||
"""
|
||
|
||
name = tool.spec.name
|
||
if not replace and name in self._tools:
|
||
raise ValueError(f"Tool '{name}' is already registered")
|
||
self._tools[name] = tool
|
||
|
||
def register_many(self, tools: Iterable[BaseTool], *, replace: bool = False) -> None:
|
||
for tool in tools:
|
||
self.register(tool, replace=replace)
|
||
|
||
def get(self, name: str) -> BaseTool | None:
|
||
return self._tools.get(name)
|
||
|
||
def require(self, name: str) -> BaseTool:
|
||
tool = self.get(name)
|
||
if tool is None:
|
||
raise KeyError(f"Unknown tool '{name}'")
|
||
return tool
|
||
|
||
def list_specs(self) -> list[ToolSpec]:
|
||
return [tool.spec for tool in self._tools.values()]
|
||
|
||
def list_always_specs(self) -> list[ToolSpec]:
|
||
"""列出每轮 run 都应该暴露给模型的基础工具。"""
|
||
|
||
return [spec for spec in self.list_specs() if spec.always_available]
|
||
|
||
def get_specs(self, names: Sequence[str]) -> list[ToolSpec]:
|
||
"""按名称顺序返回已注册工具 spec,忽略未知工具。"""
|
||
|
||
specs: list[ToolSpec] = []
|
||
seen: set[str] = set()
|
||
for name in names:
|
||
tool = self.get(name)
|
||
if tool is None or name in seen:
|
||
continue
|
||
specs.append(tool.spec)
|
||
seen.add(name)
|
||
return specs
|
||
|
||
def export_provider_schemas(self) -> list[dict]:
|
||
"""导出给 provider 的函数工具 schema 列表。"""
|
||
|
||
return [spec.to_provider_schema() for spec in self.list_specs()]
|
||
|
||
def export_selected_provider_schemas(self, specs: Sequence[ToolSpec]) -> list[dict]:
|
||
"""导出一组已选择工具的 provider schema。"""
|
||
|
||
return [spec.to_provider_schema() for spec in specs]
|