feat(gateway): persist chat sessions and messages in PostgreSQL

- store: new chat_sessions/chat_messages tables with CRUD, ILIKE message
  search, and auto-titling from the first user message
- context: optional Persister on the sliding-window store — messages are
  saved asynchronously on Add, sessions not in memory are restored from
  the database on Get
- orchestrator: ProcessInput/FinishRound now carry userID so persisted
  messages have an owner
- api: real session handlers (list/create/delete), message history and
  clear endpoints, working message search and three-format export
  (markdown/txt/json), fixing the short-ID panic in export
- main: migration, store wiring, ctxStore persister adapter

Tests: chat store handler lifecycle (fake store), context persister
save/restore, stub auth login flow updated.
This commit is contained in:
Aska committed 2026-08-20 20:34:08 +08:00
1 parent f44bf26050
commit f8196c111c
11 files changed
+787 -27

No files matched your search

+2 -2
View File
@@ -22,7 +22,7 @@ var upgrader = websocket.Upgrader{
// Orchestrator is the interface for the AI dialogue pipeline.
type Orchestrator interface {
ProcessInput(ctx context.Context, sessionID, userMessage string) (<-chan model.StreamToken, *model.Intent, error)
ProcessInput(ctx context.Context, sessionID, userID, userMessage string) (<-chan model.StreamToken, *model.Intent, error)
// FinishRound records the assistant reply and triggers post-round work
// (e.g. memory extraction) after the response stream completes.
FinishRound(sessionID, userID, assistantReply string)
@@ -160,7 +160,7 @@ func (c *Client) handleChatMessage(msg WSMessage) {
}
// Call orchestrator
tokenCh, intent, err := c.hub.orchestrator.ProcessInput(context.Background(), msg.SessionID, msg.Content)
tokenCh, intent, err := c.hub.orchestrator.ProcessInput(context.Background(), msg.SessionID, c.UserID, msg.Content)
if err != nil {
c.sendJSON(WSMessage{Type: "error", Error: err.Error()})
return