import { defineAction } from "@agent-native/core"; import { assertAccess } from "@agent-native/core/sharing"; import { eq } from "drizzle-orm"; import { z } from "zod"; import { getDb, schema } from "../server/db/index.js"; import { nowIso } from "../server/lib/json.js"; import { getAssetOrThrow, serializeLibrary } from "./_helpers.js"; /** * Pin one asset as the library's canonical logo. The logo composite pipeline * uses this when generate-image is called with `includeLogo: true`. Setting a * canonical logo also flips its role to `logo_reference` so reference selection * upweights it for any future generation. */ export default defineAction({ description: "Mark an image asset as the library's canonical logo. The logo will be composited onto generated images when the user toggles 'Use logo'. Pixel-perfect — never regenerated by the model.", schema: z.object({ libraryId: z.string(), assetId: z.string(), }), run: async ({ libraryId, assetId }) => { await assertAccess("asset-library", libraryId, "editor"); const asset = await getAssetOrThrow(assetId); if (asset.libraryId !== libraryId) { throw new Error("Asset does not belong to this library."); } const db = getDb(); const now = nowIso(); await db .update(schema.assets) .set({ role: "logo_reference", status: "reference", updatedAt: now }) .where(eq(schema.assets.id, assetId)); await db .update(schema.assetLibraries) .set({ canonicalLogoAssetId: assetId, updatedAt: now }) .where(eq(schema.assetLibraries.id, libraryId)); const [library] = await db .select() .from(schema.assetLibraries) .where(eq(schema.assetLibraries.id, libraryId)) .limit(1); return { libraryId, assetId, library: library ? serializeLibrary(library) : null, }; }, });