main.py (5146 lines, 106 routes) becomes an assembly only: one package per domain — core, files, settings, dashboards, conversations, diff, notifications, forms, runs, accounts, workers, models, cron, agents, projects, services, goals, memories, plans, templates — each exposing an APIRouter; the flat domain modules move into their package behind a barrel that keeps the old `import conversations` / `import projects` spellings. The shared singletons (store, meta_store, hub, indexer, …) are built once by core.state.build_state() and attached to app.state.ai; routes take them as the `deps: State` dependency and helpers as an explicit `deps: AppState`. conversations/pricing.py carries the per-model rates out of the parser. Verified: route table and OpenAPI byte-identical; 90 read endpoints golden-diffed against the monolith on a copy of the live data (identical); write routes smoke-tested; 66 backend tests pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
51 lines
1.7 KiB
Python
51 lines
1.7 KiB
Python
"""Memories routes."""
|
|
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
|
|
import memories as memories_mod
|
|
import schemas
|
|
from conversations.catalog import _conv_card
|
|
from core.http import _r
|
|
from core.state import State
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
# ── memories (the assistant's persistent file-based memory for this repo) ─────
|
|
@router.get("/api/memories", responses=_r(schemas.MemoriesResponse))
|
|
def memories_list():
|
|
"""All memory summaries (projects + links derived), newest-updated first."""
|
|
return {"memories": memories_mod.list_memories()}
|
|
|
|
|
|
@router.get("/api/memory", responses=_r(schemas.MemoryDetail))
|
|
def memory_detail(deps: State, slug: str):
|
|
"""One memory + its body, with the conversations that created / read it."""
|
|
mem = memories_mod.memory_detail(slug)
|
|
if mem is None:
|
|
raise HTTPException(404, "memory not found")
|
|
origin = mem.get("originSessionId")
|
|
created_in, read_in = [], []
|
|
created_sids: set[str] = set()
|
|
for path, s in deps.store.all_summaries():
|
|
if not s.get("messages"):
|
|
continue
|
|
sid = s.get("sessionId")
|
|
if sid and sid == origin:
|
|
created_in.append(_conv_card(deps, path, s))
|
|
created_sids.add(sid)
|
|
for path, s in deps.store.all_summaries():
|
|
if not s.get("messages"):
|
|
continue
|
|
# don't repeat the originating conversation under "read"
|
|
if s.get("sessionId") in created_sids:
|
|
continue
|
|
if slug in (s.get("memoriesRead") or []):
|
|
read_in.append(_conv_card(deps, path, s))
|
|
created_in.sort(key=lambda c: c.get("endedAt") or "", reverse=True)
|
|
read_in.sort(key=lambda c: c.get("endedAt") or "", reverse=True)
|
|
mem["createdIn"] = created_in
|
|
mem["readIn"] = read_in
|
|
return mem
|