Files
Hermes-Memory-Next-Level/hermes_memory/tier2/entities.py
T
Florian Hartmann b83546d833 Add AI Council architecture: Tier 2/3/Graph implementation + Integration Plan
Architecture (Agent 1):
- hermes_memory/tier2/{schema,facts,entities,relations,timeline}.py
- hermes_memory/tier3/{backend,chroma_backend,embedder}.py
- hermes_memory/graph/nx_store.py
- hermes_memory/api/memory_api.py (unified API)
- hermes_memory/cron/{consolidate,embed_queue,graph_refresh,prune}.py
- hermes_memory/config.py + pyproject.toml

Integration Plan (Agent 3):
- INTEGRATION_PLAN.md: Memory Provider Plugin strategy
- Hermes Core needs minimal changes
- sync_turn() + prefetch() hooks
- Skills integration via nextlevel_search/remember

Auto-Extraction (Agent 2):
- ARCHITECTURE.md: Full extraction pipeline docs
- Chunking, Pre-Filter, LLM Prompts, Classification
- Entity-Linking, Temporal Reasoning, Deduplication

All files: Python syntax checked, ECC standards applied.
2026-06-03 22:51:50 +00:00

109 lines
3.4 KiB
Python

"""EntityStore — Entitäts-Verwaltung für Tier 2."""
import json
import sqlite3
import time
import uuid as uuid_mod
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class Entity:
uuid: str
name: str
aliases: List[str]
entity_type: str
description: Optional[str]
first_seen: float
last_seen: float
occurrence_count: int
metadata: dict
class EntityStore:
def __init__(self, conn: sqlite3.Connection):
self.conn = conn
def ensure(
self,
name: str,
entity_type: str,
aliases: Optional[List[str]] = None,
description: Optional[str] = None,
metadata: Optional[dict] = None,
) -> Entity:
existing = self._find_by_name(name)
if existing:
# Aktualisiere last_seen und occurrence_count
self.conn.execute(
"UPDATE entities SET last_seen = ?, occurrence_count = occurrence_count + 1 WHERE uuid = ?",
(time.time(), existing.uuid),
)
self.conn.commit()
return self.get_by_uuid(existing.uuid)
ent_uuid = str(uuid_mod.uuid4())
now = time.time()
self.conn.execute(
"""
INSERT INTO entities (uuid, name, aliases, entity_type, description, first_seen, last_seen, occurrence_count, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
ent_uuid,
name,
json.dumps(aliases or []),
entity_type,
description,
now,
now,
1,
json.dumps(metadata or {}),
),
)
self.conn.commit()
return self.get_by_uuid(ent_uuid)
def _find_by_name(self, name: str) -> Optional[Entity]:
row = self.conn.execute(
"SELECT * FROM entities WHERE name = ? COLLATE NOCASE LIMIT 1", (name,)
).fetchone()
return self._row_to_entity(row) if row else None
def get_by_uuid(self, ent_uuid: str) -> Optional[Entity]:
row = self.conn.execute("SELECT * FROM entities WHERE uuid = ? LIMIT 1", (ent_uuid,)).fetchone()
return self._row_to_entity(row) if row else None
def query(
self,
name: Optional[str] = None,
entity_type: Optional[str] = None,
limit: int = 10,
) -> List[Entity]:
sql = "SELECT * FROM entities WHERE 1=1"
params: List = []
if name:
sql += " AND (name LIKE ? OR aliases LIKE ?)"
params.extend([f"%{name}%", f"%{name}%"])
if entity_type:
sql += " AND entity_type = ?"
params.append(entity_type)
sql += " ORDER BY occurrence_count DESC, last_seen DESC LIMIT ?"
params.append(limit)
rows = self.conn.execute(sql, params).fetchall()
return [self._row_to_entity(r) for r in rows]
def _row_to_entity(self, row: sqlite3.Row) -> Entity:
return Entity(
uuid=row["uuid"],
name=row["name"],
aliases=json.loads(row["aliases"] or "[]"),
entity_type=row["entity_type"],
description=row["description"],
first_seen=row["first_seen"],
last_seen=row["last_seen"],
occurrence_count=row["occurrence_count"],
metadata=json.loads(row["metadata"] or "{}"),
)