import { Injectable, NotFoundException, ConflictException, ForbiddenException, } from "@nestjs/common"; import { PrismaService } from "../prisma/prisma.service"; import { CreateUserAgentDto } from "./dto/create-user-agent.dto"; import { UpdateUserAgentDto } from "./dto/update-user-agent.dto"; export interface AgentStatusResponse { id: string; name: string; displayName: string; role: string; isActive: boolean; containerStatus?: "running" | "stopped" | "unknown"; } @Injectable() export class UserAgentService { constructor(private readonly prisma: PrismaService) {} async findAll(userId: string) { return this.prisma.userAgent.findMany({ where: { userId }, orderBy: { createdAt: "asc" }, }); } async findOne(userId: string, id: string) { const agent = await this.prisma.userAgent.findUnique({ where: { id } }); if (!agent) throw new NotFoundException(`UserAgent ${id} not found`); if (agent.userId !== userId) throw new ForbiddenException("Access denied to this agent"); return agent; } async findByName(userId: string, name: string) { const agent = await this.prisma.userAgent.findUnique({ where: { userId_name: { userId, name } }, }); if (!agent) throw new NotFoundException(`UserAgent "${name}" not found for user`); return agent; } async create(userId: string, dto: CreateUserAgentDto) { // Check for unique name within user scope const existing = await this.prisma.userAgent.findUnique({ where: { userId_name: { userId, name: dto.name } }, }); if (existing) throw new ConflictException(`UserAgent "${dto.name}" already exists for this user`); // If templateId provided, verify it exists if (dto.templateId) { const template = await this.prisma.agentTemplate.findUnique({ where: { id: dto.templateId }, }); if (!template) throw new NotFoundException(`AgentTemplate ${dto.templateId} not found`); } return this.prisma.userAgent.create({ data: { userId, templateId: dto.templateId ?? null, name: dto.name, displayName: dto.displayName, role: dto.role, personality: dto.personality, primaryModel: dto.primaryModel ?? null, fallbackModels: dto.fallbackModels ?? ([] as string[]), toolPermissions: dto.toolPermissions ?? ([] as string[]), discordChannel: dto.discordChannel ?? null, isActive: dto.isActive ?? true, }, }); } async createFromTemplate(userId: string, templateId: string) { const template = await this.prisma.agentTemplate.findUnique({ where: { id: templateId }, }); if (!template) throw new NotFoundException(`AgentTemplate ${templateId} not found`); // Check for unique name within user scope const existing = await this.prisma.userAgent.findUnique({ where: { userId_name: { userId, name: template.name } }, }); if (existing) throw new ConflictException(`UserAgent "${template.name}" already exists for this user`); return this.prisma.userAgent.create({ data: { userId, templateId: template.id, name: template.name, displayName: template.displayName, role: template.role, personality: template.personality, primaryModel: template.primaryModel, fallbackModels: template.fallbackModels as string[], toolPermissions: template.toolPermissions as string[], discordChannel: template.discordChannel, isActive: template.isActive, }, }); } async update(userId: string, id: string, dto: UpdateUserAgentDto) { const agent = await this.findOne(userId, id); // If name is being changed, check for uniqueness if (dto.name && dto.name !== agent.name) { const existing = await this.prisma.userAgent.findUnique({ where: { userId_name: { userId, name: dto.name } }, }); if (existing) throw new ConflictException(`UserAgent "${dto.name}" already exists for this user`); } return this.prisma.userAgent.update({ where: { id }, data: dto, }); } async remove(userId: string, id: string) { await this.findOne(userId, id); return this.prisma.userAgent.delete({ where: { id } }); } async getStatus(userId: string, id: string): Promise { const agent = await this.findOne(userId, id); return { id: agent.id, name: agent.name, displayName: agent.displayName, role: agent.role, isActive: agent.isActive, }; } async getAllStatuses(userId: string): Promise { const agents = await this.findAll(userId); return agents.map((agent) => ({ id: agent.id, name: agent.name, displayName: agent.displayName, role: agent.role, isActive: agent.isActive, })); } }