valhalla / backend /src /agents /memory_index.py
Dontcryx_07
final
d660fa9
Raw History Blame Contribute Delete
4.02 kB
"""memory_index — CLI admin tool for the Qdrant memory backend.
Supports status, migrate-json (one-time import of legacy JSON archives
into Qdrant), and clear operations for per-agent collections.
Architecture: a developer utility that calls vector_memory.py directly;
not part of the simulation runtime.
Design: migration is idempotent (deterministic point ids) so reruns are
safe; --delete-source is explicit and documented.
"""
from __future__ import annotations
import argparse
import json
from collections import defaultdict
from pathlib import Path
from src.agents.vector_memory import VectorMemoryRetriever, archive_records
from src.config import DATA_DIR
def _legacy_archives() -> tuple[dict[str, list], list[Path]]:
root = DATA_DIR / "Long_term_db"
result: dict[str, list] = defaultdict(list)
sources: list[Path] = []
for path in root.glob("*/memory.json"):
try:
content = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
continue
agent = str(content.get("persona_name") or path.parent.name)
for day in content.get("days", []):
result[agent].extend(archive_records(agent, day))
sources.append(path)
return result, sources
def main() -> int:
parser = argparse.ArgumentParser(description="Manage Qdrant-only long-term memory")
parser.add_argument("operation", choices=("status", "migrate-json", "clear"))
parser.add_argument("--agent", help="limit work to one persona name")
parser.add_argument("--delete-source", action="store_true",
help="after a successful migrate-json, delete legacy memory.json files")
parser.add_argument("--yes", action="store_true",
help="required for clear; confirms permanent deletion of Valhalla Qdrant memory")
args = parser.parse_args()
index = VectorMemoryRetriever()
if not index.available:
print("Qdrant memory is unavailable. Set SIM_SEMANTIC_MEMORY_ENABLED=true, QDRANT_URL, QDRANT_API_KEY, and Gemini keys.")
return 2
if args.operation == "clear":
if args.agent:
parser.error("clear always removes all Valhalla long-term memory; --agent is not supported")
if not args.yes:
parser.error("clear is permanent; rerun with --yes to remove all Valhalla long-term memory")
result = index.clear_all_memory()
deleted = result["deleted_collections"]
failed = result["failed_collections"]
print(f"Cleared {len(deleted)} Valhalla long-term-memory collection(s): {', '.join(deleted) or '(none found)'}")
if failed:
print(f"Could not clear {len(failed)} collection(s): {', '.join(failed)}")
return 1
return 0
archives, sources = _legacy_archives()
if args.agent:
archives = {args.agent: archives.get(args.agent, [])}
sources = [p for p in sources if p.parent.name == args.agent.lower().replace(" ", "_")]
if args.operation == "status":
agents = sorted(archives) if archives else ([args.agent] if args.agent else [])
for agent in agents:
print(f"{agent}: {index.collection_status(agent)}")
return 0
successful = True
for agent, records in sorted(archives.items()):
indexed = index.index_records(agent, records)
expected = len({record.id for record in records})
print(f"{agent}: indexed {indexed}/{expected} legacy memories")
successful = successful and indexed == expected
if args.delete_source:
if not successful:
print("Legacy JSON was retained because migration was incomplete.")
return 1
for path in sources:
path.unlink()
try:
path.parent.rmdir()
except OSError:
pass
print(f"Deleted {len(sources)} migrated legacy memory.json file(s).")
return 0
if __name__ == "__main__":
raise SystemExit(main())