mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 13:08:46 +02:00
Assistant: persist the chat thread in Postgres
Back MAF's opt-in AG-UI snapshot persistence with a DB store so the conversation survives page reloads and restarts: - ChatThreadSnapshot: one upserted row per (scope, thread_id), JSONB messages/state/interrupt (migration 794baf50635b) - PostgresSnapshotStore implements the AGUIThreadSnapshotStore protocol. It opens its own sessions (MAF saves during SSE streaming, after the request middleware has closed the ContextVar session) and sanitizes on save: camelCase toolCalls/toolCallId (the @ag-ui/client Zod schema strips snake_case, which would lose cards on replay), drop BFF ctx-* context messages, dedupe MAF's re-recorded multi-run turns, and drop orphaned tool results - Endpoint mount gains snapshot_store + a constant scope resolver (single-user app; auth already enforced by agent_auth_and_session) - DELETE /api/v1/chat/thread resets the conversation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
41
backend/app/api/v1/endpoints/chat.py
Normal file
41
backend/app/api/v1/endpoints/chat.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""Assistant chat thread management.
|
||||
|
||||
The conversation itself is persisted by the AG-UI snapshot store
|
||||
(app/agent/snapshot_store.py) under a single ("default", "main") thread;
|
||||
this router only exposes the reset used by "Nueva conversación".
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.auth import get_current_user
|
||||
from app.db import get_session
|
||||
from app.models.models import ChatThreadSnapshot
|
||||
|
||||
router = APIRouter(prefix="/chat", tags=["chat"])
|
||||
|
||||
CHAT_SCOPE = "default"
|
||||
CHAT_THREAD_ID = "main"
|
||||
|
||||
|
||||
class ClearThreadResponse(BaseModel):
|
||||
cleared: bool
|
||||
|
||||
|
||||
@router.delete("/thread", response_model=ClearThreadResponse)
|
||||
def clear_thread(
|
||||
session: Session = Depends(get_session),
|
||||
_user: str = Depends(get_current_user),
|
||||
):
|
||||
row = session.exec(
|
||||
select(ChatThreadSnapshot).where(
|
||||
ChatThreadSnapshot.scope == CHAT_SCOPE,
|
||||
ChatThreadSnapshot.thread_id == CHAT_THREAD_ID,
|
||||
)
|
||||
).first()
|
||||
if row is None:
|
||||
return {"cleared": False}
|
||||
session.delete(row)
|
||||
session.commit()
|
||||
return {"cleared": True}
|
||||
@@ -6,6 +6,7 @@ from app.api.v1.endpoints import (
|
||||
auth,
|
||||
budget,
|
||||
categories,
|
||||
chat,
|
||||
exchange_rate,
|
||||
import_transactions,
|
||||
installments,
|
||||
@@ -38,3 +39,4 @@ api_router.include_router(pensions.router)
|
||||
api_router.include_router(municipal_receipts.router)
|
||||
api_router.include_router(savings_accrual.router)
|
||||
api_router.include_router(sync_status.router)
|
||||
api_router.include_router(chat.router)
|
||||
|
||||
Reference in New Issue
Block a user