feat(app-instance): 集成Beaver后端并更新配置管理
集成新的Beaver后端服务到应用实例中,替换原有的nanobot实现。 主要变更包括: - 在Dockerfile和环境配置中添加Beaver相关路径和配置变量 - 更新工作目录结构从.nanobot到.beaver - 实现Beaver引擎加载器,支持配置文件加载和工具组装 - 添加内置工具如ListDirectoryTool、ReadFileTool、SearchFilesTool - 更新消息处理流程,支持通道适配器和网关模式 - 重构技能系统,支持显式工具提示和嵌入式检索 - 改进错误处理和生命周期管理 此变更使应用实例能够使用统一的Beaver后端进行AI代理运行时管理。
This commit is contained in:
@ -18,6 +18,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@ -111,6 +112,32 @@ class SkillsLoader:
|
||||
metadata, _ = parse_frontmatter(content)
|
||||
return metadata
|
||||
|
||||
def get_skill_tool_hints(self, name: str) -> list[str]:
|
||||
"""读取 skill 显式声明的推荐工具。
|
||||
|
||||
第一版只信任显式 metadata,不从正文里猜:
|
||||
- `tools: read_file, search_files`
|
||||
- `tools: ["read_file", "search_files"]`
|
||||
- YAML-like list:
|
||||
tools:
|
||||
- read_file
|
||||
- search_files
|
||||
- 兼容 metadata JSON blob 里的 `tools`
|
||||
"""
|
||||
|
||||
frontmatter = self.get_skill_metadata(name) or {}
|
||||
meta_blob = parse_skill_metadata_blob(frontmatter.get("metadata", ""))
|
||||
names = [
|
||||
*self._coerce_tool_names(frontmatter.get("tools")),
|
||||
*self._coerce_tool_names(meta_blob.get("tools")),
|
||||
*self._coerce_tool_names(meta_blob.get("required_tools")),
|
||||
]
|
||||
result: list[str] = []
|
||||
for item in names:
|
||||
if item and item not in result:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
def load_skills_for_context(self, skill_names: list[str]) -> str:
|
||||
"""加载指定 skills 的正文,并整理成上下文块。"""
|
||||
|
||||
@ -253,6 +280,26 @@ class SkillsLoader:
|
||||
result.append(record.name)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _coerce_tool_names(value: Any) -> list[str]:
|
||||
if value is None:
|
||||
return []
|
||||
if isinstance(value, str):
|
||||
raw = value.strip()
|
||||
if not raw:
|
||||
return []
|
||||
if raw.startswith("["):
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except Exception:
|
||||
parsed = None
|
||||
if isinstance(parsed, list):
|
||||
return [str(item).strip() for item in parsed if str(item).strip()]
|
||||
return [item.strip() for item in raw.split(",") if item.strip()]
|
||||
if isinstance(value, (list, tuple, set)):
|
||||
return [str(item).strip() for item in value if str(item).strip()]
|
||||
return []
|
||||
|
||||
def _find_record(self, name: str) -> SkillRecord | None:
|
||||
for record in self.list_skills(filter_unavailable=False):
|
||||
if record.name == name:
|
||||
|
||||
@ -20,7 +20,7 @@ import shutil
|
||||
from typing import Any
|
||||
|
||||
|
||||
def parse_frontmatter(content: str) -> tuple[dict[str, str], str]:
|
||||
def parse_frontmatter(content: str) -> tuple[dict[str, Any], str]:
|
||||
"""解析 Markdown 文件顶部的极简 frontmatter。
|
||||
|
||||
当前先只支持最常见的:
|
||||
@ -43,12 +43,36 @@ def parse_frontmatter(content: str) -> tuple[dict[str, str], str]:
|
||||
if match is None:
|
||||
return {}, content
|
||||
|
||||
metadata: dict[str, str] = {}
|
||||
for line in match.group(1).splitlines():
|
||||
metadata: dict[str, Any] = {}
|
||||
lines = match.group(1).splitlines()
|
||||
index = 0
|
||||
while index < len(lines):
|
||||
line = lines[index]
|
||||
if ":" not in line:
|
||||
index += 1
|
||||
continue
|
||||
key, value = line.split(":", 1)
|
||||
metadata[key.strip()] = value.strip().strip('"\'')
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
if not value:
|
||||
items: list[str] = []
|
||||
lookahead = index + 1
|
||||
while lookahead < len(lines):
|
||||
candidate = lines[lookahead]
|
||||
stripped = candidate.strip()
|
||||
if not stripped:
|
||||
lookahead += 1
|
||||
continue
|
||||
if not stripped.startswith("- "):
|
||||
break
|
||||
items.append(stripped[2:].strip().strip('"\''))
|
||||
lookahead += 1
|
||||
if items:
|
||||
metadata[key] = items
|
||||
index = lookahead
|
||||
continue
|
||||
metadata[key] = value.strip('"\'')
|
||||
index += 1
|
||||
body = content[match.end():].strip()
|
||||
return metadata, body
|
||||
|
||||
|
||||
Reference in New Issue
Block a user