// src/controllers/api/v1/chat-session.ts // Copyright (C) 2026 Robert Colbert // All Rights Reserved import { Request, Response } from "express"; import { DtpController } from "../../../lib/controller.js"; import ChatSessionService from "../../../services/chat-session.js"; import { ChatSessionMode } from "@gadget/api"; class ChatSessionController extends DtpController { get name(): string { return "ChatSessionController"; } get slug(): string { return "ctrl:api:v1:chat-session"; } get route(): string { return "/chat-sessions"; } async start(): Promise { this.router.get("/", this.requireUser(), this.listSessions.bind(this)); this.router.post("/", this.requireUser(), this.createSession.bind(this)); this.router.get("/:id", this.requireUser(), this.getSession.bind(this)); this.router.put("/:id", this.requireUser(), this.updateSession.bind(this)); this.router.delete( "/:id", this.requireUser(), this.deleteSession.bind(this), ); this.router.get( "/:id/turns", this.requireUser(), this.getSessionTurns.bind(this), ); } /** * GET /api/v1/chat-sessions?projectId=:projectId * List chat sessions for a project or user. */ private async listSessions(req: Request, res: Response): Promise { try { const user = req.user; if (!user) { res.status(401).json({ success: false, message: "Unauthorized" }); return; } const projectId = req.query.projectId as string | undefined; let sessions; if (projectId) { sessions = await ChatSessionService.getByProject(projectId); } else { sessions = await ChatSessionService.getByUser(user._id); } res.json({ success: true, data: sessions, }); } catch (error) { const err = error as Error; this.log.error("failed to list chat sessions", { error: err.message }); res.status(500).json({ success: false, message: err.message, }); } } /** * POST /api/v1/chat-sessions * Create a new chat session. */ private async createSession(req: Request, res: Response): Promise { try { const user = req.user; if (!user) { res.status(401).json({ success: false, message: "Unauthorized" }); return; } const { projectId, providerId, selectedModel, mode, name } = req.body; if (!projectId) { res.status(400).json({ success: false, message: "projectId is required", }); return; } if (!providerId) { res.status(400).json({ success: false, message: "providerId is required", }); return; } if (!selectedModel) { res.status(400).json({ success: false, message: "selectedModel is required", }); return; } const sessionMode = mode ? ChatSessionMode[mode as keyof typeof ChatSessionMode] : ChatSessionMode.Build; const session = await ChatSessionService.create( user._id, projectId, providerId, selectedModel, sessionMode, name, ); res.status(201).json({ success: true, data: session, }); } catch (error) { const err = error as Error; this.log.error("failed to create chat session", { error: err.message }); res.status(500).json({ success: false, message: err.message, }); } } /** * GET /api/v1/chat-sessions/:id * Get a specific chat session. */ private async getSession(req: Request, res: Response): Promise { try { const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; if (!id) { res.status(400).json({ success: false, message: "Session ID is required", }); return; } const session = await ChatSessionService.getById(id); res.json({ success: true, data: session, }); } catch (error) { const err = error as Error; this.log.error("failed to get chat session", { error: err.message }); if (err.message.includes("not found")) { res.status(404).json({ success: false, message: err.message, }); } else { res.status(500).json({ success: false, message: err.message, }); } } } /** * PUT /api/v1/chat-sessions/:id * Update a chat session. */ private async updateSession(req: Request, res: Response): Promise { try { const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; if (!id) { res.status(400).json({ success: false, message: "Session ID is required", }); return; } const updates = req.body; // Validate allowed updates const allowedUpdates: Partial<{ name: string; provider: string; selectedModel: string; mode: ChatSessionMode; }> = {}; if (updates.name !== undefined) { allowedUpdates.name = updates.name; } if (updates.provider !== undefined) { allowedUpdates.provider = updates.provider; } if (updates.selectedModel !== undefined) { allowedUpdates.selectedModel = updates.selectedModel; } if (updates.mode !== undefined) { allowedUpdates.mode = ChatSessionMode[updates.mode as keyof typeof ChatSessionMode]; } const session = await ChatSessionService.update(id, allowedUpdates); res.json({ success: true, data: session, }); } catch (error) { const err = error as Error; this.log.error("failed to update chat session", { error: err.message }); if (err.message.includes("not found")) { res.status(404).json({ success: false, message: err.message, }); } else { res.status(500).json({ success: false, message: err.message, }); } } } /** * DELETE /api/v1/chat-sessions/:id * Delete a chat session. */ private async deleteSession(req: Request, res: Response): Promise { try { const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; if (!id) { res.status(400).json({ success: false, message: "Session ID is required", }); return; } await ChatSessionService.delete(id); res.json({ success: true, message: "Chat session deleted", }); } catch (error) { const err = error as Error; this.log.error("failed to delete chat session", { error: err.message }); if (err.message.includes("not found")) { res.status(404).json({ success: false, message: err.message, }); } else { res.status(500).json({ success: false, message: err.message, }); } } } /** * GET /api/v1/chat-sessions/:id/turns * Get all turns for a chat session. */ private async getSessionTurns(req: Request, res: Response): Promise { try { const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; if (!id) { res.status(400).json({ success: false, message: "Session ID is required", }); return; } const turns = await ChatSessionService.getTurns(id); res.json({ success: true, data: turns, }); } catch (error) { const err = error as Error; this.log.error("failed to get chat session turns", { error: err.message, }); res.status(500).json({ success: false, message: err.message, }); } } } export default ChatSessionController;