Compare commits
5 Commits
fix/securi
...
feat/ms22-
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d686a0757 | |||
| b52c4e7ff9 | |||
| af56684e84 | |||
| ee4d6fa12b | |||
| 5bd08b0d0b |
47
apps/api/src/agent-template/agent-template.controller.ts
Normal file
47
apps/api/src/agent-template/agent-template.controller.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Patch,
|
||||||
|
Delete,
|
||||||
|
Body,
|
||||||
|
Param,
|
||||||
|
UseGuards,
|
||||||
|
ParseUUIDPipe,
|
||||||
|
} from "@nestjs/common";
|
||||||
|
import { AgentTemplateService } from "./agent-template.service";
|
||||||
|
import { CreateAgentTemplateDto } from "./dto/create-agent-template.dto";
|
||||||
|
import { UpdateAgentTemplateDto } from "./dto/update-agent-template.dto";
|
||||||
|
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||||
|
import { AdminGuard } from "../auth/guards/admin.guard";
|
||||||
|
|
||||||
|
@Controller("admin/agent-templates")
|
||||||
|
@UseGuards(AuthGuard, AdminGuard)
|
||||||
|
export class AgentTemplateController {
|
||||||
|
constructor(private readonly agentTemplateService: AgentTemplateService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
findAll() {
|
||||||
|
return this.agentTemplateService.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(":id")
|
||||||
|
findOne(@Param("id", ParseUUIDPipe) id: string) {
|
||||||
|
return this.agentTemplateService.findOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
create(@Body() dto: CreateAgentTemplateDto) {
|
||||||
|
return this.agentTemplateService.create(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(":id")
|
||||||
|
update(@Param("id", ParseUUIDPipe) id: string, @Body() dto: UpdateAgentTemplateDto) {
|
||||||
|
return this.agentTemplateService.update(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(":id")
|
||||||
|
remove(@Param("id", ParseUUIDPipe) id: string) {
|
||||||
|
return this.agentTemplateService.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
apps/api/src/agent-template/agent-template.module.ts
Normal file
12
apps/api/src/agent-template/agent-template.module.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { AgentTemplateService } from "./agent-template.service";
|
||||||
|
import { AgentTemplateController } from "./agent-template.controller";
|
||||||
|
import { PrismaModule } from "../prisma/prisma.module";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [PrismaModule],
|
||||||
|
controllers: [AgentTemplateController],
|
||||||
|
providers: [AgentTemplateService],
|
||||||
|
exports: [AgentTemplateService],
|
||||||
|
})
|
||||||
|
export class AgentTemplateModule {}
|
||||||
57
apps/api/src/agent-template/agent-template.service.ts
Normal file
57
apps/api/src/agent-template/agent-template.service.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { Injectable, NotFoundException, ConflictException } from "@nestjs/common";
|
||||||
|
import { PrismaService } from "../prisma/prisma.service";
|
||||||
|
import { CreateAgentTemplateDto } from "./dto/create-agent-template.dto";
|
||||||
|
import { UpdateAgentTemplateDto } from "./dto/update-agent-template.dto";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AgentTemplateService {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
async findAll() {
|
||||||
|
return this.prisma.agentTemplate.findMany({
|
||||||
|
orderBy: { createdAt: "asc" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string) {
|
||||||
|
const template = await this.prisma.agentTemplate.findUnique({ where: { id } });
|
||||||
|
if (!template) throw new NotFoundException(`AgentTemplate ${id} not found`);
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByName(name: string) {
|
||||||
|
const template = await this.prisma.agentTemplate.findUnique({ where: { name } });
|
||||||
|
if (!template) throw new NotFoundException(`AgentTemplate "${name}" not found`);
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(dto: CreateAgentTemplateDto) {
|
||||||
|
const existing = await this.prisma.agentTemplate.findUnique({ where: { name: dto.name } });
|
||||||
|
if (existing) throw new ConflictException(`AgentTemplate "${dto.name}" already exists`);
|
||||||
|
|
||||||
|
return this.prisma.agentTemplate.create({
|
||||||
|
data: {
|
||||||
|
name: dto.name,
|
||||||
|
displayName: dto.displayName,
|
||||||
|
role: dto.role,
|
||||||
|
personality: dto.personality,
|
||||||
|
primaryModel: dto.primaryModel,
|
||||||
|
fallbackModels: dto.fallbackModels ?? ([] as string[]),
|
||||||
|
toolPermissions: dto.toolPermissions ?? ([] as string[]),
|
||||||
|
...(dto.discordChannel !== undefined && { discordChannel: dto.discordChannel }),
|
||||||
|
isActive: dto.isActive ?? true,
|
||||||
|
isDefault: dto.isDefault ?? false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateAgentTemplateDto) {
|
||||||
|
await this.findOne(id);
|
||||||
|
return this.prisma.agentTemplate.update({ where: { id }, data: dto });
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string) {
|
||||||
|
await this.findOne(id);
|
||||||
|
return this.prisma.agentTemplate.delete({ where: { id } });
|
||||||
|
}
|
||||||
|
}
|
||||||
43
apps/api/src/agent-template/dto/create-agent-template.dto.ts
Normal file
43
apps/api/src/agent-template/dto/create-agent-template.dto.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { IsString, IsBoolean, IsOptional, IsArray, MinLength } from "class-validator";
|
||||||
|
|
||||||
|
export class CreateAgentTemplateDto {
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
name!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
displayName!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
role!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
personality!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
primaryModel!: string;
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@IsOptional()
|
||||||
|
fallbackModels?: string[];
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@IsOptional()
|
||||||
|
toolPermissions?: string[];
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
discordChannel?: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isActive?: boolean;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isDefault?: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from "@nestjs/mapped-types";
|
||||||
|
import { CreateAgentTemplateDto } from "./create-agent-template.dto";
|
||||||
|
|
||||||
|
export class UpdateAgentTemplateDto extends PartialType(CreateAgentTemplateDto) {}
|
||||||
@@ -48,6 +48,8 @@ import { TerminalModule } from "./terminal/terminal.module";
|
|||||||
import { PersonalitiesModule } from "./personalities/personalities.module";
|
import { PersonalitiesModule } from "./personalities/personalities.module";
|
||||||
import { WorkspacesModule } from "./workspaces/workspaces.module";
|
import { WorkspacesModule } from "./workspaces/workspaces.module";
|
||||||
import { AdminModule } from "./admin/admin.module";
|
import { AdminModule } from "./admin/admin.module";
|
||||||
|
import { AgentTemplateModule } from "./agent-template/agent-template.module";
|
||||||
|
import { UserAgentModule } from "./user-agent/user-agent.module";
|
||||||
import { TeamsModule } from "./teams/teams.module";
|
import { TeamsModule } from "./teams/teams.module";
|
||||||
import { ImportModule } from "./import/import.module";
|
import { ImportModule } from "./import/import.module";
|
||||||
import { ConversationArchiveModule } from "./conversation-archive/conversation-archive.module";
|
import { ConversationArchiveModule } from "./conversation-archive/conversation-archive.module";
|
||||||
@@ -129,6 +131,8 @@ import { OrchestratorModule } from "./orchestrator/orchestrator.module";
|
|||||||
PersonalitiesModule,
|
PersonalitiesModule,
|
||||||
WorkspacesModule,
|
WorkspacesModule,
|
||||||
AdminModule,
|
AdminModule,
|
||||||
|
AgentTemplateModule,
|
||||||
|
UserAgentModule,
|
||||||
TeamsModule,
|
TeamsModule,
|
||||||
ImportModule,
|
ImportModule,
|
||||||
ConversationArchiveModule,
|
ConversationArchiveModule,
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ export class ChatProxyController {
|
|||||||
const upstreamResponse = await this.chatProxyService.proxyChat(
|
const upstreamResponse = await this.chatProxyService.proxyChat(
|
||||||
userId,
|
userId,
|
||||||
body.messages,
|
body.messages,
|
||||||
abortController.signal
|
abortController.signal,
|
||||||
|
body.agent
|
||||||
);
|
);
|
||||||
|
|
||||||
const upstreamContentType = upstreamResponse.headers.get("content-type");
|
const upstreamContentType = upstreamResponse.headers.get("content-type");
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import { Type } from "class-transformer";
|
import { Type } from "class-transformer";
|
||||||
import { ArrayMinSize, IsArray, IsNotEmpty, IsString, ValidateNested } from "class-validator";
|
import {
|
||||||
|
ArrayMinSize,
|
||||||
|
IsArray,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
|
} from "class-validator";
|
||||||
|
|
||||||
export interface ChatMessage {
|
export interface ChatMessage {
|
||||||
role: string;
|
role: string;
|
||||||
@@ -22,4 +29,8 @@ export class ChatStreamDto {
|
|||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@Type(() => ChatMessageDto)
|
@Type(() => ChatMessageDto)
|
||||||
messages!: ChatMessageDto[];
|
messages!: ChatMessageDto[];
|
||||||
|
|
||||||
|
@IsString({ message: "agent must be a string" })
|
||||||
|
@IsOptional()
|
||||||
|
agent?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
BadGatewayException,
|
BadGatewayException,
|
||||||
Injectable,
|
Injectable,
|
||||||
Logger,
|
Logger,
|
||||||
|
NotFoundException,
|
||||||
ServiceUnavailableException,
|
ServiceUnavailableException,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
import { ConfigService } from "@nestjs/config";
|
import { ConfigService } from "@nestjs/config";
|
||||||
@@ -18,6 +19,13 @@ interface ContainerConnection {
|
|||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AgentConfig {
|
||||||
|
name: string;
|
||||||
|
displayName: string;
|
||||||
|
personality: string;
|
||||||
|
primaryModel: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChatProxyService {
|
export class ChatProxyService {
|
||||||
private readonly logger = new Logger(ChatProxyService.name);
|
private readonly logger = new Logger(ChatProxyService.name);
|
||||||
@@ -38,21 +46,38 @@ export class ChatProxyService {
|
|||||||
async proxyChat(
|
async proxyChat(
|
||||||
userId: string,
|
userId: string,
|
||||||
messages: ChatMessage[],
|
messages: ChatMessage[],
|
||||||
signal?: AbortSignal
|
signal?: AbortSignal,
|
||||||
|
agentName?: string
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const { url: containerUrl, token: gatewayToken } = await this.getContainerConnection(userId);
|
const { url: containerUrl, token: gatewayToken } = await this.getContainerConnection(userId);
|
||||||
const model = await this.getPreferredModel(userId);
|
|
||||||
|
// Get agent config if specified
|
||||||
|
let agentConfig: AgentConfig | null = null;
|
||||||
|
if (agentName) {
|
||||||
|
agentConfig = await this.getAgentConfig(userId, agentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const model = agentConfig?.primaryModel ?? (await this.getPreferredModel(userId));
|
||||||
|
|
||||||
|
const requestBody: Record<string, unknown> = {
|
||||||
|
messages,
|
||||||
|
model,
|
||||||
|
stream: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add agent config if available
|
||||||
|
if (agentConfig) {
|
||||||
|
requestBody.agent = agentConfig.name;
|
||||||
|
requestBody.agent_personality = agentConfig.personality;
|
||||||
|
}
|
||||||
|
|
||||||
const requestInit: RequestInit = {
|
const requestInit: RequestInit = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${gatewayToken}`,
|
Authorization: `Bearer ${gatewayToken}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(requestBody),
|
||||||
messages,
|
|
||||||
model,
|
|
||||||
stream: true,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (signal) {
|
if (signal) {
|
||||||
@@ -170,4 +195,32 @@ export class ChatProxyService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getAgentConfig(userId: string, agentName: string): Promise<AgentConfig> {
|
||||||
|
const agent = await this.prisma.userAgent.findUnique({
|
||||||
|
where: { userId_name: { userId, name: agentName } },
|
||||||
|
select: {
|
||||||
|
name: true,
|
||||||
|
displayName: true,
|
||||||
|
personality: true,
|
||||||
|
primaryModel: true,
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!agent) {
|
||||||
|
throw new NotFoundException(`Agent "${agentName}" not found for user`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!agent.isActive) {
|
||||||
|
throw new NotFoundException(`Agent "${agentName}" is not active`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: agent.name,
|
||||||
|
displayName: agent.displayName,
|
||||||
|
personality: agent.personality,
|
||||||
|
primaryModel: agent.primaryModel,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
apps/api/src/user-agent/dto/create-user-agent.dto.ts
Normal file
43
apps/api/src/user-agent/dto/create-user-agent.dto.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { IsString, IsBoolean, IsOptional, IsArray, MinLength } from "class-validator";
|
||||||
|
|
||||||
|
export class CreateUserAgentDto {
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
templateId?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
name!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
displayName!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
role!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
personality!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
primaryModel?: string;
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@IsOptional()
|
||||||
|
fallbackModels?: string[];
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@IsOptional()
|
||||||
|
toolPermissions?: string[];
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
discordChannel?: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
4
apps/api/src/user-agent/dto/update-user-agent.dto.ts
Normal file
4
apps/api/src/user-agent/dto/update-user-agent.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from "@nestjs/mapped-types";
|
||||||
|
import { CreateUserAgentDto } from "./create-user-agent.dto";
|
||||||
|
|
||||||
|
export class UpdateUserAgentDto extends PartialType(CreateUserAgentDto) {}
|
||||||
70
apps/api/src/user-agent/user-agent.controller.ts
Normal file
70
apps/api/src/user-agent/user-agent.controller.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Patch,
|
||||||
|
Delete,
|
||||||
|
Body,
|
||||||
|
Param,
|
||||||
|
UseGuards,
|
||||||
|
ParseUUIDPipe,
|
||||||
|
} from "@nestjs/common";
|
||||||
|
import { UserAgentService } from "./user-agent.service";
|
||||||
|
import { CreateUserAgentDto } from "./dto/create-user-agent.dto";
|
||||||
|
import { UpdateUserAgentDto } from "./dto/update-user-agent.dto";
|
||||||
|
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||||
|
import { CurrentUser } from "../auth/decorators/current-user.decorator";
|
||||||
|
import type { AuthUser } from "@mosaic/shared";
|
||||||
|
|
||||||
|
@Controller("agents")
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
export class UserAgentController {
|
||||||
|
constructor(private readonly userAgentService: UserAgentService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
findAll(@CurrentUser() user: AuthUser) {
|
||||||
|
return this.userAgentService.findAll(user.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("status")
|
||||||
|
getAllStatuses(@CurrentUser() user: AuthUser) {
|
||||||
|
return this.userAgentService.getAllStatuses(user.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(":id")
|
||||||
|
findOne(@CurrentUser() user: AuthUser, @Param("id", ParseUUIDPipe) id: string) {
|
||||||
|
return this.userAgentService.findOne(user.id, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(":id/status")
|
||||||
|
getStatus(@CurrentUser() user: AuthUser, @Param("id", ParseUUIDPipe) id: string) {
|
||||||
|
return this.userAgentService.getStatus(user.id, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
create(@CurrentUser() user: AuthUser, @Body() dto: CreateUserAgentDto) {
|
||||||
|
return this.userAgentService.create(user.id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("from-template/:templateId")
|
||||||
|
createFromTemplate(
|
||||||
|
@CurrentUser() user: AuthUser,
|
||||||
|
@Param("templateId", ParseUUIDPipe) templateId: string
|
||||||
|
) {
|
||||||
|
return this.userAgentService.createFromTemplate(user.id, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(":id")
|
||||||
|
update(
|
||||||
|
@CurrentUser() user: AuthUser,
|
||||||
|
@Param("id", ParseUUIDPipe) id: string,
|
||||||
|
@Body() dto: UpdateUserAgentDto
|
||||||
|
) {
|
||||||
|
return this.userAgentService.update(user.id, id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(":id")
|
||||||
|
remove(@CurrentUser() user: AuthUser, @Param("id", ParseUUIDPipe) id: string) {
|
||||||
|
return this.userAgentService.remove(user.id, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
apps/api/src/user-agent/user-agent.module.ts
Normal file
12
apps/api/src/user-agent/user-agent.module.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { UserAgentService } from "./user-agent.service";
|
||||||
|
import { UserAgentController } from "./user-agent.controller";
|
||||||
|
import { PrismaModule } from "../prisma/prisma.module";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [PrismaModule],
|
||||||
|
controllers: [UserAgentController],
|
||||||
|
providers: [UserAgentService],
|
||||||
|
exports: [UserAgentService],
|
||||||
|
})
|
||||||
|
export class UserAgentModule {}
|
||||||
153
apps/api/src/user-agent/user-agent.service.ts
Normal file
153
apps/api/src/user-agent/user-agent.service.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
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<AgentStatusResponse> {
|
||||||
|
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<AgentStatusResponse[]> {
|
||||||
|
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,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
| --- | ------------- | ------------- | ---------- | -------------- | --------------------- |
|
| --- | ------------- | ------------- | ---------- | -------------- | --------------------- |
|
||||||
| 1 | schema-seed | Schema+Seed | ✅ done | P2-001, P2-002 | PRs #675, #677 merged |
|
| 1 | schema-seed | Schema+Seed | ✅ done | P2-001, P2-002 | PRs #675, #677 merged |
|
||||||
| 2 | admin-crud | Admin CRUD | ✅ done | P2-003 | PR #678 merged |
|
| 2 | admin-crud | Admin CRUD | ✅ done | P2-003 | PR #678 merged |
|
||||||
| 3 | user-crud | User CRUD | 🔄 next | P2-004 | Depends on M2 |
|
| 3 | user-crud | User CRUD | ✅ done | P2-004 | PR #682 merged |
|
||||||
| 4 | agent-routing | Agent Routing | ⬜ pending | P2-005, P2-006 | Depends on M3 |
|
| 4 | agent-routing | Agent Routing | ⬜ pending | P2-005, P2-006 | Depends on M3 |
|
||||||
| 5 | discord-ui | Discord+UI | ⬜ pending | P2-007, P2-008 | Depends on M4 |
|
| 5 | discord-ui | Discord+UI | ⬜ pending | P2-007, P2-008 | Depends on M4 |
|
||||||
| 6 | verification | Verification | ⬜ pending | P2-009, P2-010 | Final gate |
|
| 6 | verification | Verification | ⬜ pending | P2-009, P2-010 | Final gate |
|
||||||
@@ -42,7 +42,7 @@ See `docs/TASKS.md` — MS22 Phase 2 section for full task details.
|
|||||||
| P2-001 Schema | ✅ done | #675 | AgentTemplate + UserAgent |
|
| P2-001 Schema | ✅ done | #675 | AgentTemplate + UserAgent |
|
||||||
| P2-002 Seed | ✅ done | #677 | jarvis/builder/medic templates |
|
| P2-002 Seed | ✅ done | #677 | jarvis/builder/medic templates |
|
||||||
| P2-003 Admin CRUD | ✅ done | #678 | /admin/agent-templates |
|
| P2-003 Admin CRUD | ✅ done | #678 | /admin/agent-templates |
|
||||||
| P2-004 User CRUD | ⬜ not-started | — | |
|
| P2-004 User CRUD | ✅ done | #682 | /api/agents |
|
||||||
| P2-005 Status endpoints | ⬜ not-started | — | |
|
| P2-005 Status endpoints | ⬜ not-started | — | |
|
||||||
| P2-006 Chat routing | ⬜ not-started | — | |
|
| P2-006 Chat routing | ⬜ not-started | — | |
|
||||||
| P2-007 Discord routing | ⬜ not-started | — | |
|
| P2-007 Discord routing | ⬜ not-started | — | |
|
||||||
@@ -54,14 +54,15 @@ See `docs/TASKS.md` — MS22 Phase 2 section for full task details.
|
|||||||
|
|
||||||
| Phase | Est | Used |
|
| Phase | Est | Used |
|
||||||
| ----------------- | -------- | -------------------- |
|
| ----------------- | -------- | -------------------- |
|
||||||
| Schema+Seed+CRUD | 30K | ~10K (done directly) |
|
| Schema+Seed+CRUD | 30K | ~15K (done directly) |
|
||||||
| User CRUD+Routing | 40K | — |
|
| User CRUD+Routing | 40K | ~25K |
|
||||||
| Discord+UI | 30K | — |
|
| Discord+UI | 30K | — |
|
||||||
| Verification | 10K | — |
|
| Verification | 10K | — |
|
||||||
| **Total** | **110K** | **~10K** |
|
| **Total** | **110K** | **~40K** |
|
||||||
|
|
||||||
## Session Log
|
## Session Log
|
||||||
|
|
||||||
| Date | Work Done |
|
| Date | Work Done |
|
||||||
| ---------- | ------------------------------------------------------------------ |
|
| ---------- | --------------------------------------------------------------------------------------------------------- |
|
||||||
| 2026-03-04 | P2-001..003 shipped; CI fix; postgres rebuilt; mission initialized |
|
| 2026-03-04 | Session 2: Fixed CI security audit, merged PRs #681, #678, #682. Milestones 1-3 complete (4/6 remaining). |
|
||||||
|
| 2026-03-04 | P2-001..003 shipped; CI fix; postgres rebuilt; mission initialized |
|
||||||
|
|||||||
@@ -97,10 +97,10 @@ PRD: `docs/PRD-MS22-P2-AGENT-FLEET.md`
|
|||||||
| Task ID | Status | Phase | Description | Issue | Scope | Branch | Depends On | Blocks | Assigned Worker | Started | Completed | Est Tokens | Act Tokens | Notes |
|
| Task ID | Status | Phase | Description | Issue | Scope | Branch | Depends On | Blocks | Assigned Worker | Started | Completed | Est Tokens | Act Tokens | Notes |
|
||||||
| ----------- | ----------- | -------- | -------------------------------------------- | -------- | ----- | --------------------------- | ------------- | ------------- | --------------- | ---------- | ---------- | ---------- | ---------- | -------------- |
|
| ----------- | ----------- | -------- | -------------------------------------------- | -------- | ----- | --------------------------- | ------------- | ------------- | --------------- | ---------- | ---------- | ---------- | ---------- | -------------- |
|
||||||
| MS22-P2-001 | done | p2-fleet | Prisma schema: AgentTemplate, UserAgent | TASKS:P2 | api | feat/ms22-p2-agent-schema | MS22-P1a | P2-002,P2-003 | orchestrator | 2026-03-04 | 2026-03-04 | 10K | 3K | PR #675 merged |
|
| MS22-P2-001 | done | p2-fleet | Prisma schema: AgentTemplate, UserAgent | TASKS:P2 | api | feat/ms22-p2-agent-schema | MS22-P1a | P2-002,P2-003 | orchestrator | 2026-03-04 | 2026-03-04 | 10K | 3K | PR #675 merged |
|
||||||
| MS22-P2-002 | not-started | p2-fleet | Seed default agents (jarvis, builder, medic) | TASKS:P2 | api | feat/ms22-p2-agent-seed | P2-001 | P2-004 | — | — | — | 5K | — | |
|
| MS22-P2-002 | done | p2-fleet | Seed default agents (jarvis, builder, medic) | TASKS:P2 | api | feat/ms22-p2-agent-seed | P2-001 | P2-004 | orchestrator | 2026-03-04 | 2026-03-04 | 5K | 2K | PR #677 merged |
|
||||||
| MS22-P2-003 | not-started | p2-fleet | Agent template CRUD endpoints (admin) | TASKS:P2 | api | feat/ms22-p2-agent-api | P2-001 | P2-005 | — | — | — | 15K | — | |
|
| MS22-P2-003 | done | p2-fleet | Agent template CRUD endpoints (admin) | TASKS:P2 | api | feat/ms22-p2-agent-crud | P2-001 | P2-005 | orchestrator | 2026-03-04 | 2026-03-04 | 15K | 5K | PR #678 merged |
|
||||||
| MS22-P2-004 | not-started | p2-fleet | User agent CRUD endpoints | TASKS:P2 | api | feat/ms22-p2-agent-api | P2-002,P2-003 | P2-006 | — | — | — | 15K | — | |
|
| MS22-P2-004 | done | p2-fleet | User agent CRUD endpoints | TASKS:P2 | api | feat/ms22-p2-user-agents | P2-002,P2-003 | P2-006 | orchestrator | 2026-03-04 | 2026-03-04 | 15K | 8K | PR #682 merged |
|
||||||
| MS22-P2-005 | not-started | p2-fleet | Agent status endpoints | TASKS:P2 | api | feat/ms22-p2-agent-api | P2-003 | P2-008 | — | — | — | 10K | — | |
|
| MS22-P2-005 | in-progress | p2-fleet | Agent status endpoints | TASKS:P2 | api | feat/ms22-p2-agent-status | P2-003 | P2-008 | orchestrator | 2026-03-04 | — | 10K | — | |
|
||||||
| MS22-P2-006 | not-started | p2-fleet | Agent chat routing (select agent by name) | TASKS:P2 | api | feat/ms22-p2-agent-routing | P2-004 | P2-007 | — | — | — | 15K | — | |
|
| MS22-P2-006 | not-started | p2-fleet | Agent chat routing (select agent by name) | TASKS:P2 | api | feat/ms22-p2-agent-routing | P2-004 | P2-007 | — | — | — | 15K | — | |
|
||||||
| MS22-P2-007 | not-started | p2-fleet | Discord channel → agent routing | TASKS:P2 | api | feat/ms22-p2-discord-router | P2-006 | P2-009 | — | — | — | 15K | — | |
|
| MS22-P2-007 | not-started | p2-fleet | Discord channel → agent routing | TASKS:P2 | api | feat/ms22-p2-discord-router | P2-006 | P2-009 | — | — | — | 15K | — | |
|
||||||
| MS22-P2-008 | not-started | p2-fleet | Agent list/selector UI in WebUI | TASKS:P2 | web | feat/ms22-p2-agent-ui | P2-005 | — | — | — | — | 15K | — | |
|
| MS22-P2-008 | not-started | p2-fleet | Agent list/selector UI in WebUI | TASKS:P2 | web | feat/ms22-p2-agent-ui | P2-005 | — | — | — | — | 15K | — | |
|
||||||
|
|||||||
23
docs/scratchpads/ms22-p2-named-agent-fleet-20260304.md
Normal file
23
docs/scratchpads/ms22-p2-named-agent-fleet-20260304.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Mission Scratchpad — MS22-P2 Named Agent Fleet
|
||||||
|
|
||||||
|
> Append-only log. NEVER delete entries. NEVER overwrite sections.
|
||||||
|
> This is the orchestrator's working memory across sessions.
|
||||||
|
|
||||||
|
## Original Mission Prompt
|
||||||
|
|
||||||
|
```
|
||||||
|
(Paste the mission prompt here on first session)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Planning Decisions
|
||||||
|
|
||||||
|
## Session Log
|
||||||
|
|
||||||
|
| Session | Date | Milestone | Tasks Done | Outcome |
|
||||||
|
| ------- | ---------- | --------- | ---------------------- | ------------------------------------------------------------------------------ |
|
||||||
|
| 2 | 2026-03-04 | M1+M2+M3 | P2-004 done | Fixed CI security audit, merged PRs #681, #678, #682. Milestones 1-3 complete. |
|
||||||
|
| 1 | 2026-03-04 | M1+M2 | P2-001, P2-002, P2-003 | Schema, seed, and Admin CRUD complete |
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
## Corrections
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
"undici": ">=6.23.0",
|
"undici": ">=6.23.0",
|
||||||
"rollup": ">=4.59.0",
|
"rollup": ">=4.59.0",
|
||||||
"serialize-javascript": ">=7.0.3",
|
"serialize-javascript": ">=7.0.3",
|
||||||
"multer": ">=2.1.0"
|
"multer": ">=2.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
pnpm-lock.yaml
generated
29
pnpm-lock.yaml
generated
@@ -17,7 +17,7 @@ overrides:
|
|||||||
undici: '>=6.23.0'
|
undici: '>=6.23.0'
|
||||||
rollup: '>=4.59.0'
|
rollup: '>=4.59.0'
|
||||||
serialize-javascript: '>=7.0.3'
|
serialize-javascript: '>=7.0.3'
|
||||||
multer: '>=2.1.0'
|
multer: '>=2.1.1'
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
@@ -1616,6 +1616,7 @@ packages:
|
|||||||
|
|
||||||
'@mosaicstack/telemetry-client@0.1.1':
|
'@mosaicstack/telemetry-client@0.1.1':
|
||||||
resolution: {integrity: sha512-1udg6p4cs8rhQgQ2pKCfi7EpRlJieRRhA5CIqthRQ6HQZLgQ0wH+632jEulov3rlHSM1iplIQ+AAe5DWrvSkEA==, tarball: https://git.mosaicstack.dev/api/packages/mosaic/npm/%40mosaicstack%2Ftelemetry-client/-/0.1.1/telemetry-client-0.1.1.tgz}
|
resolution: {integrity: sha512-1udg6p4cs8rhQgQ2pKCfi7EpRlJieRRhA5CIqthRQ6HQZLgQ0wH+632jEulov3rlHSM1iplIQ+AAe5DWrvSkEA==, tarball: https://git.mosaicstack.dev/api/packages/mosaic/npm/%40mosaicstack%2Ftelemetry-client/-/0.1.1/telemetry-client-0.1.1.tgz}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@mrleebo/prisma-ast@0.13.1':
|
'@mrleebo/prisma-ast@0.13.1':
|
||||||
resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==}
|
resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==}
|
||||||
@@ -5863,8 +5864,8 @@ packages:
|
|||||||
msgpackr@1.11.5:
|
msgpackr@1.11.5:
|
||||||
resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==}
|
resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==}
|
||||||
|
|
||||||
multer@2.1.0:
|
multer@2.1.1:
|
||||||
resolution: {integrity: sha512-TBm6j41rxNohqawsxlsWsNNh/VdV4QFXcBvRcPhXaA05EZ79z0qJ2bQFpync6JBoHTeNY5Q1JpG7AlTjdlfAEA==}
|
resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==}
|
||||||
engines: {node: '>= 10.16.0'}
|
engines: {node: '>= 10.16.0'}
|
||||||
|
|
||||||
mute-stream@2.0.0:
|
mute-stream@2.0.0:
|
||||||
@@ -8004,7 +8005,7 @@ snapshots:
|
|||||||
chalk: 5.6.2
|
chalk: 5.6.2
|
||||||
commander: 12.1.0
|
commander: 12.1.0
|
||||||
dotenv: 17.2.4
|
dotenv: 17.2.4
|
||||||
drizzle-orm: 0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
drizzle-orm: 0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
||||||
open: 10.2.0
|
open: 10.2.0
|
||||||
pg: 8.17.2
|
pg: 8.17.2
|
||||||
prettier: 3.8.1
|
prettier: 3.8.1
|
||||||
@@ -8868,7 +8869,7 @@ snapshots:
|
|||||||
'@nestjs/core': 11.1.12(@nestjs/common@11.1.12(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.12)(@nestjs/websockets@11.1.12)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
'@nestjs/core': 11.1.12(@nestjs/common@11.1.12(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.12)(@nestjs/websockets@11.1.12)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
cors: 2.8.5
|
cors: 2.8.5
|
||||||
express: 5.2.1
|
express: 5.2.1
|
||||||
multer: 2.1.0
|
multer: 2.1.1
|
||||||
path-to-regexp: 8.3.0
|
path-to-regexp: 8.3.0
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -11344,7 +11345,7 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@prisma/client': 5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
'@prisma/client': 5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
||||||
better-sqlite3: 12.6.2
|
better-sqlite3: 12.6.2
|
||||||
drizzle-orm: 0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
drizzle-orm: 0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
||||||
next: 16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
next: 16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
pg: 8.17.2
|
pg: 8.17.2
|
||||||
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
||||||
@@ -11369,7 +11370,7 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@prisma/client': 6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3)
|
'@prisma/client': 6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3)
|
||||||
better-sqlite3: 12.6.2
|
better-sqlite3: 12.6.2
|
||||||
drizzle-orm: 0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
drizzle-orm: 0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
||||||
next: 16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
next: 16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
pg: 8.17.2
|
pg: 8.17.2
|
||||||
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
||||||
@@ -12193,6 +12194,17 @@ snapshots:
|
|||||||
|
|
||||||
dotenv@17.2.4: {}
|
dotenv@17.2.4: {}
|
||||||
|
|
||||||
|
drizzle-orm@0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)):
|
||||||
|
optionalDependencies:
|
||||||
|
'@opentelemetry/api': 1.9.0
|
||||||
|
'@prisma/client': 5.22.0(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))
|
||||||
|
'@types/pg': 8.16.0
|
||||||
|
better-sqlite3: 12.6.2
|
||||||
|
kysely: 0.28.10
|
||||||
|
pg: 8.17.2
|
||||||
|
postgres: 3.4.8
|
||||||
|
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
||||||
|
|
||||||
drizzle-orm@0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)):
|
drizzle-orm@0.41.0(@opentelemetry/api@1.9.0)(@prisma/client@6.19.2(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.10)(pg@8.17.2)(postgres@3.4.8)(prisma@6.19.2(magicast@0.3.5)(typescript@5.9.3)):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
@@ -12203,6 +12215,7 @@ snapshots:
|
|||||||
pg: 8.17.2
|
pg: 8.17.2
|
||||||
postgres: 3.4.8
|
postgres: 3.4.8
|
||||||
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
prisma: 6.19.2(magicast@0.3.5)(typescript@5.9.3)
|
||||||
|
optional: true
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -13473,7 +13486,7 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
msgpackr-extract: 3.0.3
|
msgpackr-extract: 3.0.3
|
||||||
|
|
||||||
multer@2.1.0:
|
multer@2.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
append-field: 1.0.0
|
append-field: 1.0.0
|
||||||
busboy: 1.6.0
|
busboy: 1.6.0
|
||||||
|
|||||||
Reference in New Issue
Block a user