Spaces:
Runtime error
Runtime error
| import { NextRequest, NextResponse } from 'next/server' | |
| import { getDatabase } from '@/lib/db' | |
| import { requireRole } from '@/lib/auth' | |
| import { logger } from '@/lib/logger' | |
| /** | |
| * GET /api/chat/conversations - List conversations derived from messages | |
| * Query params: agent (filter by participant), limit, offset | |
| */ | |
| export async function GET(request: NextRequest) { | |
| const auth = requireRole(request, 'viewer') | |
| if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status }) | |
| try { | |
| const db = getDatabase() | |
| const { searchParams } = new URL(request.url) | |
| const workspaceId = auth.user.workspace_id ?? 1 | |
| const agent = searchParams.get('agent') | |
| const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 200) | |
| const offset = parseInt(searchParams.get('offset') || '0') | |
| let query: string | |
| const params: any[] = [] | |
| if (agent) { | |
| // Get conversations where this agent is a participant | |
| query = ` | |
| SELECT | |
| m.conversation_id, | |
| MAX(m.created_at) as last_message_at, | |
| COUNT(*) as message_count, | |
| COUNT(DISTINCT m.from_agent) + COUNT(DISTINCT CASE WHEN m.to_agent IS NOT NULL THEN m.to_agent END) as participant_count, | |
| SUM(CASE WHEN m.to_agent = ? AND m.read_at IS NULL THEN 1 ELSE 0 END) as unread_count | |
| FROM messages m | |
| WHERE m.workspace_id = ? AND (m.from_agent = ? OR m.to_agent = ? OR m.to_agent IS NULL) | |
| GROUP BY m.conversation_id | |
| ORDER BY last_message_at DESC | |
| LIMIT ? OFFSET ? | |
| ` | |
| params.push(agent, workspaceId, agent, agent, limit, offset) | |
| } else { | |
| query = ` | |
| SELECT | |
| m.conversation_id, | |
| MAX(m.created_at) as last_message_at, | |
| COUNT(*) as message_count, | |
| COUNT(DISTINCT m.from_agent) + COUNT(DISTINCT CASE WHEN m.to_agent IS NOT NULL THEN m.to_agent END) as participant_count, | |
| 0 as unread_count | |
| FROM messages m | |
| WHERE m.workspace_id = ? | |
| GROUP BY m.conversation_id | |
| ORDER BY last_message_at DESC | |
| LIMIT ? OFFSET ? | |
| ` | |
| params.push(workspaceId, limit, offset) | |
| } | |
| const conversations = db.prepare(query).all(...params) as any[] | |
| // Prepare last message statement once (avoids N+1) | |
| const lastMsgStmt = db.prepare(` | |
| SELECT * FROM messages | |
| WHERE conversation_id = ? AND workspace_id = ? | |
| ORDER BY created_at DESC | |
| LIMIT 1 | |
| `); | |
| const withLastMessage = conversations.map((conv) => { | |
| const lastMsg = lastMsgStmt.get(conv.conversation_id, workspaceId) as any; | |
| return { | |
| ...conv, | |
| last_message: lastMsg | |
| ? { | |
| ...lastMsg, | |
| metadata: lastMsg.metadata ? JSON.parse(lastMsg.metadata) : null | |
| } | |
| : null | |
| } | |
| }) | |
| // Get total count for pagination | |
| let countQuery: string | |
| const countParams: any[] = [workspaceId] | |
| if (agent) { | |
| countQuery = ` | |
| SELECT COUNT(DISTINCT m.conversation_id) as total | |
| FROM messages m | |
| WHERE m.workspace_id = ? AND (m.from_agent = ? OR m.to_agent = ? OR m.to_agent IS NULL) | |
| ` | |
| countParams.push(agent, agent) | |
| } else { | |
| countQuery = 'SELECT COUNT(DISTINCT conversation_id) as total FROM messages WHERE workspace_id = ?' | |
| } | |
| const countRow = db.prepare(countQuery).get(...countParams) as { total: number } | |
| return NextResponse.json({ conversations: withLastMessage, total: countRow.total, page: Math.floor(offset / limit) + 1, limit }) | |
| } catch (error) { | |
| logger.error({ err: error }, 'GET /api/chat/conversations error') | |
| return NextResponse.json({ error: 'Failed to fetch conversations' }, { status: 500 }) | |
| } | |
| } | |