import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Inject, NotFoundException, Param, Patch, Post, UseGuards, } from '@nestjs/common'; import type { Brain } from '@mosaic/brain'; import { BRAIN } from '../brain/brain.tokens.js'; import { AuthGuard } from '../auth/auth.guard.js'; import { CurrentUser } from '../auth/current-user.decorator.js'; import { assertOwner } from '../auth/resource-ownership.js'; import { CreateConversationDto, UpdateConversationDto, SendMessageDto, } from './conversations.dto.js'; @Controller('api/conversations') @UseGuards(AuthGuard) export class ConversationsController { constructor(@Inject(BRAIN) private readonly brain: Brain) {} @Get() async list(@CurrentUser() user: { id: string }) { return this.brain.conversations.findAll(user.id); } @Get(':id') async findOne(@Param('id') id: string, @CurrentUser() user: { id: string }) { return this.getOwnedConversation(id, user.id); } @Post() async create(@CurrentUser() user: { id: string }, @Body() dto: CreateConversationDto) { return this.brain.conversations.create({ userId: user.id, title: dto.title, projectId: dto.projectId, }); } @Patch(':id') async update( @Param('id') id: string, @Body() dto: UpdateConversationDto, @CurrentUser() user: { id: string }, ) { await this.getOwnedConversation(id, user.id); const conversation = await this.brain.conversations.update(id, dto); if (!conversation) throw new NotFoundException('Conversation not found'); return conversation; } @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) async remove(@Param('id') id: string, @CurrentUser() user: { id: string }) { await this.getOwnedConversation(id, user.id); const deleted = await this.brain.conversations.remove(id); if (!deleted) throw new NotFoundException('Conversation not found'); } @Get(':id/messages') async listMessages(@Param('id') id: string, @CurrentUser() user: { id: string }) { await this.getOwnedConversation(id, user.id); return this.brain.conversations.findMessages(id); } @Post(':id/messages') async addMessage( @Param('id') id: string, @Body() dto: SendMessageDto, @CurrentUser() user: { id: string }, ) { await this.getOwnedConversation(id, user.id); return this.brain.conversations.addMessage({ conversationId: id, role: dto.role, content: dto.content, metadata: dto.metadata, }); } private async getOwnedConversation(id: string, userId: string) { const conversation = await this.brain.conversations.findById(id); if (!conversation) throw new NotFoundException('Conversation not found'); assertOwner(conversation.userId, userId, 'Conversation'); return conversation; } }