Files
GoClaw/drizzle/0005_chat_sessions.sql
bboxwtf 471ca42835 feat(phase20): persistent background chat sessions — DB-backed polling architecture
ARCHITECTURE:
- Replace SSE stream (breaks on page reload) with DB-backed background sessions
- Go Gateway runs orchestrator in detached goroutine using context.Background()
  (survives HTTP disconnect, page reload, and laptop sleep/shutdown)
- Every SSE event (thinking/tool_call/delta/done/error) is persisted to chatEvents table
- Session lifecycle stored in chatSessions table (running→done/error)
- Frontend polls GET /api/orchestrator/getEvents every 1.5 s until status=done

DB CHANGES:
- Migration 0005_chat_sessions.sql: chatSessions + chatEvents tables
- schema.ts: TypeScript types for chatSessions and chatEvents
- db.go: ChatSessionRow and ChatEventRow structs with proper json tags (camelCase)
- db.go: CreateSession, AppendEvent, MarkSessionDone, GetSession, GetEvents, GetRecentSessions

GO GATEWAY:
- handlers.go: StartChatSession — creates DB session, launches goroutine, returns {sessionId} immediately
- handlers.go: GetChatSession, GetChatEvents, ListChatSessions handlers
- main.go: routes POST /api/chat/session, GET /api/chat/session/{id}, GET /api/chat/session/{id}/events, GET /api/chat/sessions
- JSON tags added to ChatSessionRow/ChatEventRow so Go returns camelCase to frontend

NODE.JS SERVER:
- gateway-proxy.ts: startChatSession, getChatSession, getChatEvents, listChatSessions functions
- routers.ts: orchestrator.startSession, .getSession, .getEvents, .listSessions tRPC procedures

FRONTEND:
- chatStore.ts: completely rewritten — uses background sessions + localStorage-based polling resume
  * send() calls orchestrator.startSession via tRPC (returns immediately)
  * Stores sessionId in localStorage (goclaw-pending-sessions)
  * Polls getEvents every 1.5 s, applies events to UI incrementally
  * On page reload: _resumePendingSessions() checks pending sessions and resumes polling
  * cancel() stops all active polls
- chatStore.ts: conversations persisted to localStorage (v3 key, survives page reload)
- Chat.tsx: updated status texts to 'Фоновая обработка…', 'Обработка в фоне…'

VERIFIED:
- POST /api/chat/session → {sessionId, status:'running'} in <100ms
- Poll events → thinking, delta('Привет!'), done after ~2s
- chatSessions table has rows with status=done, model, totalTokens
- Cyrillic stored correctly in UTF-8
- JSON fields are camelCase: id, sessionId, seq, eventType, content, toolName...
2026-03-21 16:50:44 +00:00

37 lines
1.3 KiB
SQL

-- chatSessions: one row per chat request, survives page reloads
CREATE TABLE IF NOT EXISTS chatSessions (
id INT AUTO_INCREMENT PRIMARY KEY,
sessionId VARCHAR(64) NOT NULL UNIQUE,
agentId INT NOT NULL DEFAULT 1,
status ENUM('running','done','error') NOT NULL DEFAULT 'running',
userMessage TEXT NOT NULL,
finalResponse TEXT,
model VARCHAR(128),
totalTokens INT DEFAULT 0,
processingTimeMs INT DEFAULT 0,
errorMessage TEXT,
createdAt TIMESTAMP NOT NULL DEFAULT NOW(),
updatedAt TIMESTAMP NOT NULL DEFAULT NOW() ON UPDATE NOW(),
INDEX chatSessions_status_idx (status),
INDEX chatSessions_createdAt_idx (createdAt)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- chatEvents: one row per SSE event within a session
CREATE TABLE IF NOT EXISTS chatEvents (
id INT AUTO_INCREMENT PRIMARY KEY,
sessionId VARCHAR(64) NOT NULL,
seq INT NOT NULL DEFAULT 0,
eventType ENUM('thinking','tool_call','delta','done','error') NOT NULL,
content TEXT,
toolName VARCHAR(128),
toolArgs JSON,
toolResult TEXT,
toolSuccess TINYINT(1),
durationMs INT,
model VARCHAR(128),
usageJson JSON,
errorMsg TEXT,
createdAt TIMESTAMP(3) NOT NULL DEFAULT NOW(3),
INDEX chatEvents_sessionId_seq_idx (sessionId, seq)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;