Add generic memory gateway v1
This commit is contained in:
108
memory_gateway/evermemos_service.py
Normal file
108
memory_gateway/evermemos_service.py
Normal file
@ -0,0 +1,108 @@
|
||||
"""Standalone EverMemOS-compatible consolidation service.
|
||||
|
||||
This is a lightweight local service for POC use. It intentionally exposes the
|
||||
same HTTP contract that Memory Gateway calls:
|
||||
|
||||
POST /v1/sessions/consolidate
|
||||
|
||||
The service does not own Memory Gateway's metadata database. It receives
|
||||
episodes and existing memories in the request, returns candidate/promoted
|
||||
MemoryRecord payloads, and creates Obsidian review drafts for high-value or
|
||||
conflicting candidates.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .config import load_config, set_config
|
||||
from .repositories import InMemoryRepository
|
||||
from .schemas import AccessContext, EpisodeRecord, MemoryRecord
|
||||
from .workers.evermemos_worker import EverMemOSWorker
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConsolidateRequest(BaseModel):
|
||||
schema_version: str = "memory-gateway.evermemos.consolidate.v1"
|
||||
session_id: str
|
||||
context: dict[str, Any]
|
||||
min_importance: float = 0.6
|
||||
target_namespace: str | None = None
|
||||
episodes: list[dict[str, Any]] = Field(default_factory=list)
|
||||
existing_memories: list[dict[str, Any]] = Field(default_factory=list)
|
||||
|
||||
|
||||
app = FastAPI(title="Local EverMemOS POC Service", version="0.1.0")
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health() -> dict[str, Any]:
|
||||
return {
|
||||
"status": "ok",
|
||||
"service": "evermemos-local",
|
||||
"version": "0.1.0",
|
||||
"contract": "memory-gateway.evermemos.consolidate.v1",
|
||||
}
|
||||
|
||||
|
||||
@app.post("/v1/sessions/consolidate")
|
||||
async def consolidate_session(request: ConsolidateRequest) -> dict[str, Any]:
|
||||
repo = InMemoryRepository()
|
||||
ctx = AccessContext.model_validate(request.context)
|
||||
|
||||
for item in request.existing_memories:
|
||||
try:
|
||||
repo.upsert_memory(MemoryRecord.model_validate(item))
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning("Skipping invalid existing memory: %s", exc)
|
||||
|
||||
for item in request.episodes:
|
||||
try:
|
||||
repo.append_episode(EpisodeRecord.model_validate(item))
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning("Skipping invalid episode: %s", exc)
|
||||
|
||||
worker = EverMemOSWorker(repo)
|
||||
result = worker.consolidate_session(
|
||||
session_id=request.session_id,
|
||||
ctx=ctx,
|
||||
min_importance=request.min_importance,
|
||||
target_namespace=request.target_namespace,
|
||||
)
|
||||
return {
|
||||
"status": "ok",
|
||||
"backend": "evermemos-local",
|
||||
"result": {
|
||||
"session_id": result.session_id,
|
||||
"episodes": result.episodes,
|
||||
"candidates": [memory.model_dump(mode="json") for memory in result.candidates],
|
||||
"promoted": [memory.model_dump(mode="json") for memory in result.promoted],
|
||||
"duplicates": result.duplicates,
|
||||
"conflicts": result.conflicts,
|
||||
"review_drafts": result.review_drafts,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
import uvicorn
|
||||
|
||||
parser = argparse.ArgumentParser(description="Run the local EverMemOS POC service.")
|
||||
parser.add_argument("--config", default="config.yaml")
|
||||
parser.add_argument("--host", default="127.0.0.1")
|
||||
parser.add_argument("--port", type=int, default=1995)
|
||||
args = parser.parse_args()
|
||||
|
||||
config = load_config(args.config)
|
||||
set_config(config)
|
||||
uvicorn.run(app, host=args.host, port=args.port, log_level=config.logging.level.lower())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user