feat(#130): add Personality Prisma schema and backend
Implement Personality system backend with database schema, service, controller, and comprehensive tests. Personalities define assistant behavior with system prompts and LLM configuration. Changes: - Update Personality model in schema.prisma with LLM provider relation - Create PersonalitiesService with CRUD and default management - Create PersonalitiesController with REST endpoints - Add DTOs with validation (create/update) - Add entity for type safety - Remove unused PromptFormatterService - Achieve 26 tests with full coverage Endpoints: - GET /personality - List all - GET /personality/default - Get default - GET /personality/by-name/:name - Get by name - GET /personality/:id - Get one - POST /personality - Create - PATCH /personality/:id - Update - DELETE /personality/:id - Delete - POST /personality/:id/set-default - Set default Fixes #130 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,52 +3,15 @@ import { PrismaService } from "../prisma/prisma.service";
|
||||
import { CreatePersonalityDto, UpdatePersonalityDto } from "./dto";
|
||||
import { Personality } from "./entities/personality.entity";
|
||||
|
||||
/**
|
||||
* Service for managing personality/assistant configurations
|
||||
*/
|
||||
@Injectable()
|
||||
export class PersonalitiesService {
|
||||
private readonly logger = new Logger(PersonalitiesService.name);
|
||||
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
/**
|
||||
* Find all personalities for a workspace
|
||||
*/
|
||||
async findAll(workspaceId: string, isActive = true): Promise<Personality[]> {
|
||||
return this.prisma.personality.findMany({
|
||||
where: { workspaceId, isActive },
|
||||
orderBy: [{ isDefault: "desc" }, { name: "asc" }],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a specific personality by ID
|
||||
*/
|
||||
async findOne(workspaceId: string, id: string): Promise<Personality> {
|
||||
const personality = await this.prisma.personality.findUnique({
|
||||
where: { id, workspaceId },
|
||||
});
|
||||
|
||||
if (!personality) {
|
||||
throw new NotFoundException(`Personality with ID ${id} not found`);
|
||||
}
|
||||
|
||||
return personality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the default personality for a workspace
|
||||
*/
|
||||
async findDefault(workspaceId: string): Promise<Personality> {
|
||||
const personality = await this.prisma.personality.findFirst({
|
||||
where: { workspaceId, isDefault: true, isActive: true },
|
||||
});
|
||||
|
||||
if (!personality) {
|
||||
throw new NotFoundException(`No default personality found for workspace ${workspaceId}`);
|
||||
}
|
||||
|
||||
return personality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new personality
|
||||
*/
|
||||
@@ -68,15 +31,79 @@ export class PersonalitiesService {
|
||||
}
|
||||
|
||||
const personality = await this.prisma.personality.create({
|
||||
data: Object.assign({}, dto, {
|
||||
data: {
|
||||
workspaceId,
|
||||
}),
|
||||
name: dto.name,
|
||||
displayName: dto.displayName,
|
||||
description: dto.description ?? null,
|
||||
systemPrompt: dto.systemPrompt,
|
||||
temperature: dto.temperature ?? null,
|
||||
maxTokens: dto.maxTokens ?? null,
|
||||
llmProviderInstanceId: dto.llmProviderInstanceId ?? null,
|
||||
isDefault: dto.isDefault ?? false,
|
||||
isEnabled: dto.isEnabled ?? true,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log(`Created personality ${personality.id} for workspace ${workspaceId}`);
|
||||
return personality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all personalities for a workspace
|
||||
*/
|
||||
async findAll(workspaceId: string): Promise<Personality[]> {
|
||||
return this.prisma.personality.findMany({
|
||||
where: { workspaceId },
|
||||
orderBy: [{ isDefault: "desc" }, { name: "asc" }],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a specific personality by ID
|
||||
*/
|
||||
async findOne(workspaceId: string, id: string): Promise<Personality> {
|
||||
const personality = await this.prisma.personality.findUnique({
|
||||
where: { id, workspaceId },
|
||||
});
|
||||
|
||||
if (!personality) {
|
||||
throw new NotFoundException(`Personality with ID ${id} not found`);
|
||||
}
|
||||
|
||||
return personality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a personality by name
|
||||
*/
|
||||
async findByName(workspaceId: string, name: string): Promise<Personality> {
|
||||
const personality = await this.prisma.personality.findFirst({
|
||||
where: { workspaceId, name },
|
||||
});
|
||||
|
||||
if (!personality) {
|
||||
throw new NotFoundException(`Personality with name "${name}" not found`);
|
||||
}
|
||||
|
||||
return personality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the default personality for a workspace
|
||||
*/
|
||||
async findDefault(workspaceId: string): Promise<Personality> {
|
||||
const personality = await this.prisma.personality.findFirst({
|
||||
where: { workspaceId, isDefault: true, isEnabled: true },
|
||||
});
|
||||
|
||||
if (!personality) {
|
||||
throw new NotFoundException(`No default personality found for workspace ${workspaceId}`);
|
||||
}
|
||||
|
||||
return personality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing personality
|
||||
*/
|
||||
@@ -112,15 +139,34 @@ export class PersonalitiesService {
|
||||
/**
|
||||
* Delete a personality
|
||||
*/
|
||||
async remove(workspaceId: string, id: string): Promise<Personality> {
|
||||
async delete(workspaceId: string, id: string): Promise<void> {
|
||||
// Check existence
|
||||
await this.findOne(workspaceId, id);
|
||||
|
||||
const personality = await this.prisma.personality.delete({
|
||||
await this.prisma.personality.delete({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
this.logger.log(`Deleted personality ${id} from workspace ${workspaceId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a personality as the default
|
||||
*/
|
||||
async setDefault(workspaceId: string, id: string): Promise<Personality> {
|
||||
// Check existence
|
||||
await this.findOne(workspaceId, id);
|
||||
|
||||
// Unset other defaults
|
||||
await this.unsetOtherDefaults(workspaceId, id);
|
||||
|
||||
// Set this one as default
|
||||
const personality = await this.prisma.personality.update({
|
||||
where: { id },
|
||||
data: { isDefault: true },
|
||||
});
|
||||
|
||||
this.logger.log(`Set personality ${id} as default for workspace ${workspaceId}`);
|
||||
return personality;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user