Message Recording & History
STELLA includes a message recording system that silently captures all session messages for history retrieval and persistence.
Overviewβ
The system provides:
- Silent recording - Backend automatically records all sessions
- Full history - Users see complete conversation when entering a session
- Real-time merge - New messages seamlessly append to history
- Infinite scroll - Older messages load automatically
- Production-ready - Handles failures, reconnections, and edge cases
Architectureβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LiveKit Server β
β Room: session-123 Room: session-456 β
β βββ Agent βββ Agent β
β βββ User βββ User β
β βββ Monitor (message-recorder) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β² β²
β β
βββββββββββ΄βββββββββ¬βββββββ΄βββββββ
β β β
βββββββββββΌββββββββββ β β
β Room Monitor β β β
β Service (NestJS) β β β
β β’ Auto-joins β β β
β β’ Silent listener β β β
β β’ Filters finals β β β
β β’ Persists to DB β β β
βββββββββββ¬ββββββββββ β β
β β β
βΌ β β
βββββββββββββββββββ β β
β PostgreSQL β β β
β (Messages) β β β
βββββββββββ¬ββββββββ β β
β β β
βΌ β β
βββββββββββββββββββ β β
β REST API βββββββββββ β
β /messages β β
βββββββββ¬ββββββββββ β
β β
βΌ β
βββββββββββββββββββ β
β Frontend βββββββββββββββββββββββββ
β ChatView β (Real-time msgs)
β β’ Load history β
β β’ Merge realtimeβ
β β’ Infinite scrollβ
βββββββββββββββββββ
Componentsβ
Backendβ
| Component | Location | Purpose |
|---|---|---|
| RoomMonitorService | src/message-recorder/room-monitor.service.ts | Silently joins LiveKit rooms |
| MessageRecorderService | src/message-recorder/message-recorder.service.ts | Persists messages to PostgreSQL |
| Message API | src/sessions/sessions.controller.ts | REST endpoints for history |
Frontendβ
| Component | Location | Purpose |
|---|---|---|
| ApiClient | src/services/ApiClient.ts | getSessionMessages(), getLatestMessages() |
| Store | src/store/index.ts | Historical message state management |
| ChatView | src/components/ChatView.tsx | Merges historical + real-time messages |
Database Schemaβ
Enhanced Message model in prisma/schema.prisma. See Database Schema for the complete data model.
model Message {
id String @id @default(uuid())
sessionId String
content String
role String // user, assistant, system
status String? // pending, complete
metadata Json? // Additional message data
timestamp DateTime @default(now())
createdAt DateTime @default(now())
session Session @relation(fields: [sessionId], references: [id])
@@index([sessionId, timestamp])
}
API Endpointsβ
Get Session Messagesβ
GET /sessions/:sessionId/messages?cursor=<id>&limit=50
Returns cursor-based paginated messages.
Get Latest Messagesβ
GET /sessions/:sessionId/messages/latest?since=<timestamp>
Returns messages since a specific timestamp for real-time sync.
Message Filteringβ
Recordedβ
- Final transcripts (
is_final: true) - Task list updates (
complete_todo_list) - Deliverables (
plan_deliverable_update) - State changes (
state_change_notification) - Participant events (join/leave)
Skippedβ
- Partial transcripts
- TTS control messages
- Audio stream chunks
Deploymentβ
Step 1: Install Dependenciesβ
npm install
Step 2: Generate Prisma Clientβ
npx prisma generate
Step 3: Run Database Migrationβ
npx prisma migrate dev --name enhance_message_model
Step 4: Restart Backendβ
The Room Monitor Service will automatically:
- Start monitoring all ACTIVE sessions on startup
- Begin recording messages immediately
npm run start:dev
Verify in logs:
[RoomMonitorService] Room Monitor Service initializing...
[RoomMonitorService] Found X active sessions to monitor
[RoomMonitorService] Successfully connected to room session-...
Step 5: Rebuild Frontendβ
cd frontend-ui
npm run build # production
# OR
npm run dev # development
Configurationβ
No new environment variables required. The system uses existing LiveKit configuration:
LIVEKIT_URL=ws://livekit:7880
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=secret
DATABASE_URL=postgresql://...
Monitoring Behaviorβ
| Feature | Behavior |
|---|---|
| Auto-start | Joins all ACTIVE sessions on app boot |
| Auto-reconnect | 5 retry attempts with exponential backoff |
| Auto-stop | Disconnects when session is closed |
Performanceβ
Databaseβ
- Indexes: Optimized for
sessionId + timestampqueries - Storage: ~2.5MB per 1000 messages
- Query time: Under 50ms for 50 messages with proper indexes
Frontendβ
- Initial load: 50 messages (configurable)
- Pagination: 50 messages per scroll
- Deduplication: O(n) using Map
- Re-renders: Optimized with useMemo
Backendβ
- Connection per session: One silent LiveKit connection
- Memory usage: ~5MB per monitored room
- Scalability: Tested with 100+ parallel sessions
Verification Checklistβ
Backendβ
- Database migration completed successfully
- Room Monitor Service starts without errors
- Messages are being recorded:
SELECT * FROM "Message" ORDER BY "timestamp" DESC LIMIT 10;
Frontendβ
- Opening a session loads historical messages
- Scrolling to top loads more messages (if >50 exist)
- New real-time messages append to the bottom
- No duplicate messages in the UI
- Loading indicators appear during fetch
Troubleshootingβ
Messages Not Being Recordedβ
-
Check Room Monitor Service logs:
grep "RoomMonitorService" logs/ -
Verify the service is monitoring the session:
curl http://localhost:3000/monitoring/stats -
Check database connectivity:
npx prisma studio
Frontend Not Loading Historyβ
- Open browser DevTools β Network tab
- Look for failed
/sessions/:id/messagesrequests - Verify API endpoint is accessible:
curl http://localhost:3000/sessions/SESSION_ID/messages
Duplicate Messages in UIβ
This should not happen (deduplication by ID), but if it does:
-
Check for duplicate IDs in database:
SELECT id, COUNT(*) FROM "Message" GROUP BY id HAVING COUNT(*) > 1; -
Verify deduplication logic in ChatView.tsx
Future Enhancementsβ
- Message search: Full-text search across historical messages
- Export: Download conversation history as JSON/PDF
- Filters: Filter by message type, participant, date range
- Analytics: Message statistics and conversation insights
- Compression: Archive old messages to reduce database size
See Alsoβ
- Database Schema - Complete data model
- Session Lifecycle
- LiveKit Integration
- Frontend Integration