修改了nanobot,往Hermes agent的风格走,进度1/3
This commit is contained in:
82
app-instance/backend/beaver/tools/builtins/skill_view.py
Normal file
82
app-instance/backend/beaver/tools/builtins/skill_view.py
Normal file
@ -0,0 +1,82 @@
|
||||
"""Beaver 内置 skill_view tool。
|
||||
|
||||
这个工具对应 Hermes 风格的显式 skill loading path:
|
||||
1. skill 正文默认不会长期塞进 system prompt
|
||||
2. 模型若想查看某个 skill 的完整正文或支持文件,必须显式调用 `skill_view`
|
||||
|
||||
这样 skill 的按需展开路径会保持显式,而不是依赖 prompt 里长期堆目录信息。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
from beaver.skills.catalog.loader import SkillsLoader
|
||||
|
||||
SKILL_VIEW_TOOL_DESCRIPTION = (
|
||||
"Load the full content of a skill or one of its supporting files. "
|
||||
"Use this when you want to inspect a skill in detail."
|
||||
)
|
||||
|
||||
SKILL_VIEW_TOOL_PARAMETERS: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The skill name to inspect.",
|
||||
},
|
||||
"file_path": {
|
||||
"type": "string",
|
||||
"description": (
|
||||
"Optional relative path to a supporting file inside the skill directory, "
|
||||
"for example 'references/usage.md'. Omit to load SKILL.md itself."
|
||||
),
|
||||
},
|
||||
},
|
||||
"required": ["name"],
|
||||
}
|
||||
|
||||
|
||||
def skill_view(*, name: str, file_path: str | None = None, loader: SkillsLoader | None = None) -> str:
|
||||
"""读取 skill 正文或支持文件,并返回结构化 JSON。"""
|
||||
|
||||
if loader is None:
|
||||
return json.dumps({"success": False, "error": "Skills loader is not available."}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
viewed = loader.view_skill(name, file_path=file_path)
|
||||
except FileNotFoundError as exc:
|
||||
return json.dumps({"success": False, "error": str(exc)}, ensure_ascii=False)
|
||||
except ValueError as exc:
|
||||
return json.dumps({"success": False, "error": str(exc)}, ensure_ascii=False)
|
||||
|
||||
if viewed is None:
|
||||
return json.dumps({"success": False, "error": f"Unknown skill '{name}'."}, ensure_ascii=False)
|
||||
|
||||
display_name, content = viewed
|
||||
support_files = loader.list_skill_supporting_files(name)
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"name": name,
|
||||
"file": display_name,
|
||||
"content": content,
|
||||
"supporting_files": support_files,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class SkillViewTool:
|
||||
"""面向 runtime 的 skill_view 工具封装。"""
|
||||
|
||||
loader: SkillsLoader
|
||||
name: str = "skill_view"
|
||||
description: str = SKILL_VIEW_TOOL_DESCRIPTION
|
||||
parameters: dict[str, Any] = field(default_factory=lambda: dict(SKILL_VIEW_TOOL_PARAMETERS))
|
||||
|
||||
async def execute(self, **kwargs: Any) -> str:
|
||||
return skill_view(loader=self.loader, **kwargs)
|
||||
Reference in New Issue
Block a user