Files
mai-bot/plugins/A_memorix/scripts/runtime_self_check.py
DawnARC 71b3a828c6 添加 A_Memorix 插件 v2.0.0(包含运行时与文档)
引入 A_Memorix 插件 v2.0.0:新增大量运行时组件、存储/模式更新、检索能力提升、管理工具、导入/调优工作流以及相关文档。关键新增内容包括:lifecycle_orchestrator、SDKMemoryKernel/运行时初始化器、新的存储层与 metadata_store 变更(SCHEMA_VERSION v8)、检索增强(双路径检索、图关系召回、稀疏 BM25),以及多种工具服务(episode/person_profile/relation/segmentation/tuning/search execution)。同时新增 Web 导入/摘要导入器及大量维护脚本。还更新了插件清单、embedding API 适配器、plugin.py、requirements/pyproject,以及主入口文件,使新插件接入项目。该变更为 2.0.0 版本发布做好准备,实现统一的 SDK Tool 接口并扩展整体运行能力。
2026-03-19 00:09:04 +08:00

153 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""Run A_Memorix runtime self-check against real embedding/runtime configuration."""
from __future__ import annotations
import argparse
import asyncio
import json
import sys
import tempfile
from pathlib import Path
from typing import Any
import tomlkit
CURRENT_DIR = Path(__file__).resolve().parent
PLUGIN_ROOT = CURRENT_DIR.parent
PROJECT_ROOT = PLUGIN_ROOT.parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
sys.path.insert(0, str(PLUGIN_ROOT))
def _build_arg_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="A_Memorix runtime self-check")
parser.add_argument(
"--config",
default=str(PLUGIN_ROOT / "config.toml"),
help="config.toml path (default: plugins/A_memorix/config.toml)",
)
parser.add_argument(
"--data-dir",
default="",
help="optional data dir override; default resolved from config.storage.data_dir",
)
parser.add_argument(
"--use-config-data-dir",
action="store_true",
help="use config.storage.data_dir directly instead of an isolated temp dir",
)
parser.add_argument(
"--sample-text",
default="A_Memorix runtime self check",
help="sample text used for real embedding probe",
)
parser.add_argument("--json", action="store_true", help="print JSON report")
return parser
if any(arg in {"-h", "--help"} for arg in sys.argv[1:]):
_build_arg_parser().print_help()
raise SystemExit(0)
from core.runtime.lifecycle_orchestrator import initialize_storage_async
from core.utils.runtime_self_check import run_embedding_runtime_self_check
def _load_config(path: Path) -> dict[str, Any]:
with open(path, "r", encoding="utf-8") as f:
raw = tomlkit.load(f)
return dict(raw) if isinstance(raw, dict) else {}
def _nested_get(config: dict[str, Any], key: str, default: Any = None) -> Any:
current: Any = config
for part in key.split("."):
if isinstance(current, dict) and part in current:
current = current[part]
else:
return default
return current
class _PluginStub:
def __init__(self, config: dict[str, Any]):
self.config = config
self.vector_store = None
self.graph_store = None
self.metadata_store = None
self.embedding_manager = None
self.sparse_index = None
self.relation_write_service = None
def get_config(self, key: str, default: Any = None) -> Any:
return _nested_get(self.config, key, default)
async def _main_async(args: argparse.Namespace) -> int:
config_path = Path(args.config).resolve()
if not config_path.exists():
print(f"❌ 配置文件不存在: {config_path}")
return 2
config = _load_config(config_path)
temp_dir_ctx = None
if args.data_dir:
storage_dir = str(Path(args.data_dir).resolve())
elif args.use_config_data_dir:
raw_data_dir = str(_nested_get(config, "storage.data_dir", "./data") or "./data").strip()
if raw_data_dir.startswith("."):
storage_dir = str((config_path.parent / raw_data_dir).resolve())
else:
storage_dir = str(Path(raw_data_dir).resolve())
else:
temp_dir_ctx = tempfile.TemporaryDirectory(prefix="memorix-runtime-self-check-")
storage_dir = temp_dir_ctx.name
storage_cfg = config.setdefault("storage", {})
storage_cfg["data_dir"] = storage_dir
plugin = _PluginStub(config)
try:
await initialize_storage_async(plugin)
report = await run_embedding_runtime_self_check(
config=config,
vector_store=plugin.vector_store,
embedding_manager=plugin.embedding_manager,
sample_text=str(args.sample_text or "A_Memorix runtime self check"),
)
report["data_dir"] = storage_dir
report["isolated_data_dir"] = temp_dir_ctx is not None
if args.json:
print(json.dumps(report, ensure_ascii=False, indent=2))
else:
print("A_Memorix Runtime Self-Check")
print(f"ok: {report.get('ok')}")
print(f"code: {report.get('code')}")
print(f"message: {report.get('message')}")
print(f"configured_dimension: {report.get('configured_dimension')}")
print(f"vector_store_dimension: {report.get('vector_store_dimension')}")
print(f"detected_dimension: {report.get('detected_dimension')}")
print(f"encoded_dimension: {report.get('encoded_dimension')}")
print(f"elapsed_ms: {float(report.get('elapsed_ms', 0.0)):.2f}")
return 0 if bool(report.get("ok")) else 1
finally:
if plugin.metadata_store is not None:
try:
plugin.metadata_store.close()
except Exception:
pass
if temp_dir_ctx is not None:
temp_dir_ctx.cleanup()
def main() -> int:
parser = _build_arg_parser()
args = parser.parse_args()
return asyncio.run(_main_async(args))
if __name__ == "__main__":
raise SystemExit(main())