import { Injectable, NotFoundException } from "@nestjs/common"; import type { AgentProviderConfig, Prisma } from "@prisma/client"; import { EncryptionService } from "../../security/encryption.service"; import { PrismaService } from "../../prisma/prisma.service"; import { CreateAgentProviderDto } from "./dto/create-agent-provider.dto"; import { UpdateAgentProviderDto } from "./dto/update-agent-provider.dto"; const OPENCLAW_PROVIDER_TYPE = "openclaw"; const OPENCLAW_TOKEN_KEYS = ["apiToken", "token", "bearerToken"] as const; @Injectable() export class AgentProvidersService { constructor( private readonly prisma: PrismaService, private readonly encryptionService: EncryptionService ) {} async list(): Promise { return this.prisma.agentProviderConfig.findMany({ orderBy: [{ createdAt: "desc" }, { id: "desc" }], }); } async getById(id: string): Promise { const providerConfig = await this.prisma.agentProviderConfig.findUnique({ where: { id }, }); if (!providerConfig) { throw new NotFoundException(`Agent provider config with id ${id} not found`); } return providerConfig; } async create(dto: CreateAgentProviderDto): Promise { const credentials = this.sanitizeCredentials(dto.provider, dto.credentials ?? {}); return this.prisma.agentProviderConfig.create({ data: { workspaceId: dto.workspaceId, name: dto.name, provider: dto.provider, gatewayUrl: dto.gatewayUrl, credentials: this.toJsonValue(credentials), ...(dto.isActive !== undefined ? { isActive: dto.isActive } : {}), }, }); } async update(id: string, dto: UpdateAgentProviderDto): Promise { const existingConfig = await this.getById(id); const provider = dto.provider ?? existingConfig.provider; const data: Prisma.AgentProviderConfigUpdateInput = { ...(dto.workspaceId !== undefined ? { workspaceId: dto.workspaceId } : {}), ...(dto.name !== undefined ? { name: dto.name } : {}), ...(dto.provider !== undefined ? { provider: dto.provider } : {}), ...(dto.gatewayUrl !== undefined ? { gatewayUrl: dto.gatewayUrl } : {}), ...(dto.isActive !== undefined ? { isActive: dto.isActive } : {}), ...(dto.credentials !== undefined ? { credentials: this.toJsonValue(this.sanitizeCredentials(provider, dto.credentials)) } : {}), }; return this.prisma.agentProviderConfig.update({ where: { id }, data, }); } async delete(id: string): Promise { await this.getById(id); return this.prisma.agentProviderConfig.delete({ where: { id }, }); } private sanitizeCredentials( provider: string, credentials: Record ): Record { if (provider.toLowerCase() !== OPENCLAW_PROVIDER_TYPE) { return credentials; } const nextCredentials: Record = { ...credentials }; for (const key of OPENCLAW_TOKEN_KEYS) { const tokenValue = nextCredentials[key]; if (typeof tokenValue === "string" && tokenValue.length > 0) { nextCredentials[key] = this.encryptionService.encryptIfNeeded(tokenValue); } } return nextCredentials; } private toJsonValue(value: Record): Prisma.InputJsonValue { return value as Prisma.InputJsonValue; } }