引入 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 接口并扩展整体运行能力。
153 lines
5.0 KiB
Python
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())
|