移除了所有Hermes相关的命名引用,包括: - 从.gitignore中清理相关构建缓存文件 - 将README中的beaver-home路径配置更新 - 完善backend/README.md文档说明Beaver后端主线实现 - 移除Hermes风格的相关注释和兼容性代码 - 清理nanobot环境变量兼容性处理 - 删除技能迁移和服务迁移相关功能代码 - 更新测试用例中相关命名和函数名 BREAKING CHANGE: 移除了Hermes迁移相关API和CLI命令,不再支持nanobot环境变量兼容性
132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
"""Beaver 内置 memory tool。
|
||
|
||
这个文件的职责很单纯:把 `MemoryStore` 暴露成一个 agent runtime 可以调用的统一工具。
|
||
|
||
设计边界:
|
||
1. `store.py` 负责底层数据与并发安全
|
||
2. 本文件负责工具接口、参数校验分发、JSON 响应
|
||
3. 更高层的 engine / loader 之后再决定如何把这个工具注册进 runtime
|
||
|
||
换句话说,本文件是“memory 能力的工具化外壳”,不是记忆实现本身。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
from dataclasses import dataclass, field
|
||
from typing import Any
|
||
|
||
from beaver.memory.curated.store import MemoryStore
|
||
|
||
MEMORY_TOOL_DESCRIPTION = (
|
||
"Save durable information to persistent memory that survives across sessions. "
|
||
"Use this proactively for user corrections, preferences, environment facts, "
|
||
"project conventions, and stable tool quirks. Do not store temporary task "
|
||
"progress or raw session logs here; use session search for historical detail."
|
||
)
|
||
|
||
MEMORY_TOOL_PARAMETERS: dict[str, Any] = {
|
||
"type": "object",
|
||
"properties": {
|
||
"action": {
|
||
"type": "string",
|
||
"enum": ["add", "replace", "remove"],
|
||
"description": "The memory operation to perform.",
|
||
},
|
||
"target": {
|
||
"type": "string",
|
||
"enum": ["memory", "user"],
|
||
"description": "Which curated store to update.",
|
||
},
|
||
"content": {
|
||
"type": "string",
|
||
"description": "The new entry content. Required for add and replace.",
|
||
},
|
||
"old_text": {
|
||
"type": "string",
|
||
"description": "A short unique substring identifying the entry to replace or remove.",
|
||
},
|
||
},
|
||
"required": ["action", "target"],
|
||
}
|
||
|
||
|
||
def memory_tool(
|
||
*,
|
||
action: str,
|
||
target: str = "memory",
|
||
content: str | None = None,
|
||
old_text: str | None = None,
|
||
store: MemoryStore | None = None,
|
||
) -> str:
|
||
"""分发 CRUD memory API,并返回 JSON 字符串。
|
||
|
||
这里统一采用 JSON 返回,是为了兼容常见 tool-calling 场景:
|
||
- LLM 更容易消费结构化结果
|
||
- Web/API/日志层也更容易透传和记录
|
||
"""
|
||
|
||
if store is None:
|
||
return json.dumps(
|
||
{
|
||
"success": False,
|
||
"error": "Memory store is not available for this runtime.",
|
||
},
|
||
ensure_ascii=False,
|
||
)
|
||
|
||
if target not in {"memory", "user"}:
|
||
return json.dumps(
|
||
{
|
||
"success": False,
|
||
"error": f"Invalid target '{target}'. Use 'memory' or 'user'.",
|
||
},
|
||
ensure_ascii=False,
|
||
)
|
||
|
||
if action == "add":
|
||
if not content:
|
||
result = {"success": False, "error": "content is required for add."}
|
||
else:
|
||
result = store.add(target, content)
|
||
elif action == "replace":
|
||
if not old_text:
|
||
result = {"success": False, "error": "old_text is required for replace."}
|
||
elif not content:
|
||
result = {"success": False, "error": "content is required for replace."}
|
||
else:
|
||
result = store.replace(target, old_text, content)
|
||
elif action == "remove":
|
||
if not old_text:
|
||
result = {"success": False, "error": "old_text is required for remove."}
|
||
else:
|
||
result = store.remove(target, old_text)
|
||
else:
|
||
result = {
|
||
"success": False,
|
||
"error": f"Unknown action '{action}'. Use add, replace, or remove.",
|
||
}
|
||
|
||
return json.dumps(result, ensure_ascii=False)
|
||
|
||
|
||
@dataclass(slots=True)
|
||
class MemoryTool:
|
||
"""面向 runtime 的轻量工具封装。
|
||
|
||
这里故意保持很薄:
|
||
1. 不重复实现业务逻辑
|
||
2. 不重复维护 schema
|
||
3. 只做 `execute()` 到 `memory_tool()` 的桥接
|
||
"""
|
||
|
||
store: MemoryStore
|
||
name: str = "memory"
|
||
description: str = MEMORY_TOOL_DESCRIPTION
|
||
toolset: str = "memory"
|
||
always_available: bool = True
|
||
parameters: dict[str, Any] = field(default_factory=lambda: dict(MEMORY_TOOL_PARAMETERS))
|
||
|
||
async def execute(self, **kwargs: Any) -> str:
|
||
return memory_tool(store=self.store, **kwargs)
|