import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { auth } from "@/app/(auth)/auth"; import { ChatSDKError } from "@/lib/errors"; import { deleteAgentPresetById, getAccessibleAgentPresetById, getSystemSetting, updateAgentPreset, } from "@/lib/db/queries"; import { isAgentWorkflowAdminType } from "@/lib/middleware/admin"; import { AGENT_SECONDARY_TYPE_CONFIG_KEY, isValidSecondaryTypeForPresetType, normalizeAgentSecondaryTypeConfig, } from "@/lib/agents/secondary-type-config"; const slotSchema = z.object({ title: z.string().trim().max(128).optional(), promptTemplate: z.string().trim().min(1).max(8000), defaultParams: z.record(z.string(), z.any()).nullable().optional(), requireUpload: z.boolean().optional(), uploadLabel: z.string().trim().max(128).optional(), referenceAssetIds: z.array(z.string().uuid()).max(12).optional(), }); const updateAgentSchema = z .object({ name: z.string().trim().min(1).max(128).optional(), type: z.enum(["image", "video", "text"]).optional(), secondaryType: z.string().trim().max(128).nullable().optional(), visibility: z.enum(["public", "private"]).optional(), categoryPath: z .object({ sectionId: z.string().trim().max(64).optional(), sectionName: z.string().trim().max(64).optional(), level1Id: z.string().trim().max(64).optional(), level1Name: z.string().trim().max(64).optional(), level2Id: z.string().trim().max(64).optional(), level2Name: z.string().trim().max(64).optional(), level3Id: z.string().trim().max(64).optional(), level3Name: z.string().trim().max(64).optional(), productCategory: z.string().trim().max(64).optional(), audienceTag: z.string().trim().max(64).optional(), usageScenario: z.string().trim().max(64).optional(), brand: z.string().trim().max(64).optional(), }) .nullable() .optional(), description: z.string().trim().max(2000).nullable().optional(), defaultModelId: z.string().uuid().optional(), defaultParams: z.record(z.string(), z.any()).nullable().optional(), avatarAssetId: z.string().uuid().nullable().optional(), slots: z.array(slotSchema).min(1).max(20).optional(), status: z.enum(["active", "disabled", "hidden", "blocked"]).optional(), }); export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const session = await auth(); if (!session?.user?.id) { return NextResponse.json({ success: false, error: "未登录" }, { status: 401 }); } const { id } = await params; const preset = await getAccessibleAgentPresetById({ id, userId: session.user.id, }); if (!preset) { return NextResponse.json({ success: false, error: "风格化不存在" }, { status: 404 }); } return NextResponse.json({ success: true, data: preset }); } catch (error) { if (error instanceof ChatSDKError) { return error.toResponse(); } return NextResponse.json( { success: false, error: "获取风格化失败" }, { status: 500 } ); } } export async function PUT( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const session = await auth(); if (!session?.user?.id) { return NextResponse.json({ success: false, error: "未登录" }, { status: 401 }); } const { id } = await params; const body = await request.json(); const data = updateAgentSchema.parse(body); const existingPreset = await getAccessibleAgentPresetById({ id, userId: session.user.id, }); if (!existingPreset) { return NextResponse.json({ success: false, error: "风格化不存在" }, { status: 404 }); } const canManagePublicPreset = isAgentWorkflowAdminType(session.user.type) && existingPreset.visibility === "public"; if (!canManagePublicPreset && existingPreset.ownerUserId !== session.user.id) { return NextResponse.json({ success: false, error: "Forbidden" }, { status: 403 }); } const effectiveType = data.type || existingPreset.type; const effectiveSecondaryType = data.secondaryType === undefined ? existingPreset.secondaryType : data.secondaryType; const secondaryTypeConfig = normalizeAgentSecondaryTypeConfig( ( await getSystemSetting({ key: AGENT_SECONDARY_TYPE_CONFIG_KEY }).catch(() => undefined) )?.value ); if ( !isValidSecondaryTypeForPresetType({ presetType: effectiveType, secondaryType: effectiveSecondaryType, config: secondaryTypeConfig, }) ) { return NextResponse.json( { success: false, error: "所选二级类型不在后台配置列表中" }, { status: 400 } ); } const preset = await updateAgentPreset({ id, userId: canManagePublicPreset ? existingPreset.ownerUserId : session.user.id, name: data.name, type: data.type, secondaryType: data.secondaryType ?? undefined, visibility: data.visibility, categoryPath: data.categoryPath ?? undefined, description: data.description ?? undefined, defaultModelId: data.defaultModelId, defaultParams: data.defaultParams ?? undefined, avatarAssetId: data.avatarAssetId ?? undefined, slots: data.slots, status: data.status, }); return NextResponse.json({ success: true, data: preset }); } catch (error) { if (error instanceof ChatSDKError) { return error.toResponse(); } if (error instanceof z.ZodError) { return NextResponse.json( { success: false, error: error.message }, { status: 400 } ); } return NextResponse.json( { success: false, error: "更新风格化失败" }, { status: 500 } ); } } export async function DELETE( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const session = await auth(); if (!session?.user?.id) { return NextResponse.json({ success: false, error: "未登录" }, { status: 401 }); } const { id } = await params; const existingPreset = await getAccessibleAgentPresetById({ id, userId: session.user.id, }); if (!existingPreset) { return NextResponse.json({ success: false, error: "风格化不存在" }, { status: 404 }); } const canManagePublicPreset = isAgentWorkflowAdminType(session.user.type) && existingPreset.visibility === "public"; if (!canManagePublicPreset && existingPreset.ownerUserId !== session.user.id) { return NextResponse.json({ success: false, error: "Forbidden" }, { status: 403 }); } const deleted = await deleteAgentPresetById({ id, userId: canManagePublicPreset ? existingPreset.ownerUserId : session.user.id, }); if (!deleted) { return NextResponse.json({ success: false, error: "风格化不存在" }, { status: 404 }); } return NextResponse.json({ success: true, data: deleted }); } catch (error) { if (error instanceof ChatSDKError) { return error.toResponse(); } return NextResponse.json( { success: false, error: "删除风格化失败" }, { status: 500 } ); } }