oclaw/runtime/tools/public/memory_wiki_tools.py

182 lines
5.7 KiB
Python

from __future__ import annotations
import importlib.util
import sys
from types import SimpleNamespace
from typing import Any, Callable
from oclaw.platform.config.paths import PROJECT_ROOT
from oclaw.runtime.tools.base import ToolSpec
def _plugin_cfg() -> dict[str, Any]:
cfg_path = (PROJECT_ROOT / "oclaw.json").resolve()
if not cfg_path.exists():
return {}
try:
import json
obj = json.loads(cfg_path.read_text(encoding="utf-8"))
except Exception:
return {}
plugins = obj.get("plugins") if isinstance(obj, dict) else {}
entries = plugins.get("entries") if isinstance(plugins, dict) else {}
entry = entries.get("memory-wiki") if isinstance(entries, dict) else {}
return entry if isinstance(entry, dict) else {}
def _wiki_handlers() -> dict[str, Callable[[dict[str, Any]], dict[str, Any]]]:
api_path = (PROJECT_ROOT / "runtime" / "extensions" / "memory-wiki" / "api.py").resolve()
spec = importlib.util.spec_from_file_location("memory_wiki_api", str(api_path))
if spec is None or spec.loader is None:
return {}
mod = importlib.util.module_from_spec(spec)
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):
return {}
specs = fn(SimpleNamespace(plugin_config=_plugin_cfg()))
out: dict[str, Callable[[dict[str, Any]], dict[str, Any]]] = {}
for spec_item in specs:
if not isinstance(spec_item, dict):
continue
name = str(spec_item.get("name") or "").strip()
handler = spec_item.get("handler")
if name and callable(handler):
out[name] = handler
return out
def _delegate(tool_name: str, args: dict[str, Any]) -> dict[str, Any]:
handlers = _wiki_handlers()
h = handlers.get(tool_name)
if not callable(h):
return {"ok": False, "error": f"wiki handler unavailable: {tool_name}"}
try:
return h(dict(args or {}))
except Exception as exc:
return {"ok": False, "error": f"{type(exc).__name__}: {exc}"}
def _status_tool(public_name: str, desc: str) -> ToolSpec:
return ToolSpec(
name=public_name,
description=desc,
parameters={"type": "object", "properties": {}, "required": [], "additionalProperties": False},
handler=lambda args: _delegate("wiki_status", args),
tags=frozenset({"wiki", "curator"}),
risk_level="low",
read_only=True,
)
def _get_tool(public_name: str, desc: str) -> ToolSpec:
return ToolSpec(
name=public_name,
description=desc,
parameters={
"type": "object",
"properties": {
"path": {"type": "string"},
"start_line": {"type": "integer"},
"end_line": {"type": "integer"},
},
"required": ["path"],
"additionalProperties": False,
},
handler=lambda args: _delegate("wiki_get", args),
tags=frozenset({"wiki", "curator"}),
risk_level="low",
read_only=True,
)
def _search_tool(public_name: str, desc: str) -> ToolSpec:
return ToolSpec(
name=public_name,
description=desc,
parameters={
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer"},
"is_regex": {"type": "boolean"},
"case_sensitive": {"type": "boolean"},
},
"required": ["query"],
"additionalProperties": False,
},
handler=lambda args: _delegate("wiki_search", args),
tags=frozenset({"wiki", "curator"}),
risk_level="low",
read_only=True,
)
def _lint_tool(public_name: str, desc: str) -> ToolSpec:
return ToolSpec(
name=public_name,
description=desc,
parameters={
"type": "object",
"properties": {"path": {"type": "string"}},
"required": [],
"additionalProperties": False,
},
handler=lambda args: _delegate("wiki_lint", args),
tags=frozenset({"wiki", "curator"}),
risk_level="low",
read_only=True,
)
def _apply_tool(public_name: str, desc: str) -> ToolSpec:
return ToolSpec(
name=public_name,
description=desc,
parameters={
"type": "object",
"properties": {
"action": {"type": "string", "enum": ["write", "append", "delete"]},
"path": {"type": "string"},
"content": {"type": "string"},
},
"required": ["action", "path"],
"additionalProperties": False,
},
handler=lambda args: _delegate("wiki_apply", args),
tags=frozenset({"wiki", "curator", "write"}),
risk_level="low",
read_only=False,
)
def memory_wiki_status_tool() -> ToolSpec:
return _status_tool("memory_wiki_status", "Read wiki runtime status for memory.")
def memory_wiki_get_tool() -> ToolSpec:
return _get_tool("memory_wiki_get", "Read a markdown file from memory wiki.")
def memory_wiki_search_tool() -> ToolSpec:
return _search_tool("memory_wiki_search", "Search memory wiki markdown.")
def memory_wiki_lint_tool() -> ToolSpec:
return _lint_tool("memory_wiki_lint", "Lint memory wiki markdown structure.")
def memory_wiki_apply_tool() -> ToolSpec:
return _apply_tool("memory_wiki_apply", "Apply write/append/delete changes to memory wiki markdown.")
__all__ = [
"memory_wiki_status_tool",
"memory_wiki_get_tool",
"memory_wiki_search_tool",
"memory_wiki_lint_tool",
"memory_wiki_apply_tool",
]