Initial commit: Pegas Memory (PG + Qdrant + Memgraph, MCP server, 14 tools)
This commit is contained in:
commit
83e77ea8c9
24 files changed
+2201
No files matched your search
@@ -0,0 +1,85 @@
|
||||
"""PostgreSQL — источник истины (psycopg)."""
|
||||
from __future__ import annotations
|
||||
import hashlib
|
||||
import json
|
||||
import psycopg
|
||||
from psycopg.rows import dict_row
|
||||
from . import config
|
||||
|
||||
def connect():
|
||||
return psycopg.connect(config.PG_DSN, row_factory=dict_row)
|
||||
|
||||
def _as_text(content) -> str:
|
||||
"""Привести content к строке: dict/list -> JSON, иначе str."""
|
||||
if isinstance(content, str):
|
||||
return content
|
||||
import json as _json
|
||||
return _json.dumps(content, ensure_ascii=False, sort_keys=True)
|
||||
|
||||
def content_hash(content) -> str:
|
||||
return hashlib.sha256(_as_text(content).encode("utf-8")).hexdigest()
|
||||
|
||||
def upsert_document(conn, *, kind: str, uri: str | None, title: str | None,
|
||||
content_hash: str | None = None, authority: float = 0.5,
|
||||
meta: dict | None = None) -> int:
|
||||
"""Вставить/вернуть документ по uri."""
|
||||
with conn.cursor() as cur:
|
||||
if uri:
|
||||
cur.execute("SELECT id FROM pm_document WHERE uri = %s", (uri,))
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
return row["id"]
|
||||
cur.execute(
|
||||
"""INSERT INTO pm_document (kind, uri, title, content_hash, authority, meta)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
ON CONFLICT (uri) DO UPDATE SET title = EXCLUDED.title
|
||||
RETURNING id""",
|
||||
(kind, uri, title, content_hash, authority, json.dumps(meta or {}, ensure_ascii=False)),
|
||||
)
|
||||
return cur.fetchone()["id"]
|
||||
|
||||
def upsert_atom(conn, *, type: str, claim: str | None, content,
|
||||
confidence: float = 0.5, status: str = "candidate",
|
||||
doc_id: int | None = None, locator: dict | None = None,
|
||||
metadata: dict | None = None) -> tuple[int, bool]:
|
||||
"""Вставить атом по content_hash. Возвращает (id, created).
|
||||
|
||||
content может быть str (text/fact/definition/code) или dict/list
|
||||
(logical_rule/table) — dict сериализуется в JSON.
|
||||
"""
|
||||
content = _as_text(content)
|
||||
h = content_hash(content)
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT id FROM pm_atom WHERE content_hash = %s", (h,))
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
return row["id"], False
|
||||
cur.execute(
|
||||
"""INSERT INTO pm_atom (type, claim, content, content_hash, confidence,
|
||||
status, doc_id, locator, metadata)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING id""",
|
||||
(type, claim, content, h, confidence, status, doc_id,
|
||||
json.dumps(locator or {}, ensure_ascii=False),
|
||||
json.dumps(metadata or {}, ensure_ascii=False)),
|
||||
)
|
||||
return cur.fetchone()["id"], True
|
||||
|
||||
def upsert_link(conn, *, src: int, dst: int, kind: str, confidence: float = 0.5) -> int:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""INSERT INTO pm_atom_link (src, dst, kind, confidence)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
ON CONFLICT (src, dst, kind) DO NOTHING
|
||||
RETURNING id""",
|
||||
(src, dst, kind, confidence),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return row["id"] if row else 0
|
||||
|
||||
def enqueue_outbox(conn, *, entity_type: str, entity_id: int, op: str = "upsert"):
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"INSERT INTO pm_outbox (entity_type, entity_id, op) VALUES (%s, %s, %s)",
|
||||
(entity_type, entity_id, op),
|
||||
)
|
||||
Reference in new issue
Block a user