修复 memory wiki 工具加载异常并在系统提示词声明默认 wiki 路径。

为动态加载的 memory-wiki 模块补充 sys.modules 注册以避免 dataclass 导入期崩溃,同时在统一技能策略中明确默认根路径为 data/wiki,并新增工具加载回归测试。

Made-with: Cursor
This commit is contained in:
oliver 2026-04-29 08:34:38 +08:00
parent c6a1da1980
commit 27b8698f9b
3 changed files with 42 additions and 0 deletions

View file

@ -42,6 +42,7 @@ def _unified_skill_policy_guidance() -> str:
"- 不要为了“列出技能”而去读取 SKILL.md。只有在你确实需要某个技能的详细使用说明时,才读取对应 SKILL.md。\n"
"- 当你需要技能细节时,请按目录中给出的 path 读取对应的 SKILL.md。\n"
"- 当对话涉及长期记忆、用户身份/偏好、项目背景延续、复发问题沉淀时,优先启用 wiki-first-autonomy 技能,并优先使用 memory_wiki_search/memory_wiki_get 检索上下文,再执行与回复。\n"
"- memory wiki 默认根路径为 `data/wiki`(例如 `data/wiki/improvement/learnings.md`);未被用户明确覆盖时,统一按该路径读写与检索。\n"
"- 当新增事实会影响后续决策时,完成当前任务后使用 memory_wiki_apply 写入结构化记忆,并用 memory_wiki_lint 做质量检查。\n"
"- 技能包由说明文档和可选文件组成。运行时不会自动执行技能 `scripts/` 目录下的文件;\n"
"- internal hooks 是独立系统,也不会自动执行这些脚本。\n"

View file

@ -1,6 +1,7 @@
from __future__ import annotations
import importlib.util
import sys
from types import SimpleNamespace
from typing import Any, Callable
@ -30,6 +31,9 @@ def _wiki_handlers() -> dict[str, Callable[[dict[str, Any]], dict[str, Any]]]:
if spec is None or spec.loader is None:
return {}
mod = importlib.util.module_from_spec(spec)
# Register module before exec so decorators (e.g., @dataclass) can resolve
# cls.__module__ via sys.modules during import-time processing.
sys.modules[spec.name] = mod
spec.loader.exec_module(mod) # type: ignore[assignment]
fn = getattr(mod, "build_wiki_tool_specs", None)
if not callable(fn):

View file

@ -0,0 +1,37 @@
from __future__ import annotations
from oclaw.runtime.tools.experts.memory.wiki_tools import (
memory_wiki_apply_tool,
memory_wiki_get_tool,
memory_wiki_lint_tool,
memory_wiki_search_tool,
memory_wiki_status_tool,
)
def test_memory_wiki_tools_handlers_load_without_dataclass_module_error() -> None:
status = memory_wiki_status_tool().handler({})
assert isinstance(status, dict)
assert "AttributeError" not in str(status.get("error", ""))
assert "__dict__" not in str(status.get("error", ""))
search = memory_wiki_search_tool().handler({"query": "test"})
assert isinstance(search, dict)
assert "AttributeError" not in str(search.get("error", ""))
assert "__dict__" not in str(search.get("error", ""))
get_res = memory_wiki_get_tool().handler({"path": "improvement/learnings.md"})
assert isinstance(get_res, dict)
assert "AttributeError" not in str(get_res.get("error", ""))
assert "__dict__" not in str(get_res.get("error", ""))
lint = memory_wiki_lint_tool().handler({})
assert isinstance(lint, dict)
assert "AttributeError" not in str(lint.get("error", ""))
assert "__dict__" not in str(lint.get("error", ""))
apply_res = memory_wiki_apply_tool().handler({"action": "delete", "path": "improvement/_nonexistent_test_.md"})
assert isinstance(apply_res, dict)
assert "AttributeError" not in str(apply_res.get("error", ""))
assert "__dict__" not in str(apply_res.get("error", ""))