asset_search
Search registered asset sources and list assets they contain. Filter by source ID or fuzzy query to locate images, fonts, and uploads for use in designs.
Instructions
Discover the asset sources registered on the CreativeEngine and search the assets they contain. Read-only — never creates a revision.
Without sourceId: lists every source id with its supported MIME types.
With sourceId: returns one page of assets as JSON { total, currentPage, nextPage, assets: [{ id, label, groups, uri, thumbUri, width, height, uploadedAt }] }. Typeface assets (e.g. the ly.img.gfonts Google Fonts source) additionally carry a compact typeface: { name, weights, styles } summary. query fuzzy-matches labels and tags.
The ly.img.workspace.images source is this workspace's own image store: every image the agent generated or imported AND every image the human uploaded in the browser editor, newest first. Uploads carry their original filename as label (the human will refer to it — "use logo-final.png" — so search that name), plus groups: ["uploads"] and an uploadedAt timestamp. "The image the user just uploaded" = the uploads-group asset with the newest uploadedAt.
⚠ Asset sources are deployment configuration — where their content lives (IMG.LY CDN, a customer host) is the server's business. NEVER fetch asset manifests (content.json) or hardcode cdn.img.ly URLs yourself; this tool and engine.asset.* are the only correct path. A source missing from the no-arg listing is not available on this server — say so instead of working around it.
To USE a result, apply it inside edit code — re-find it there, then either:
(A) new block: const id = await engine.asset.apply(sourceId, (await engine.asset.findAssets(sourceId, { query, page: 0, perPage: 1 })).assets[0]) — then, if you resize the frame, set engine.block.setContentFillMode(id, "Cover") (resizing does NOT update the crop; without Cover a portrait photo forced into a landscape frame gets squished);
(B) existing block: const fill = engine.block.createFill("image"); engine.block.setString(fill, "fill/image/imageFileURI", asset.meta.uri); engine.block.setFill(blockId, fill); engine.block.setContentFillMode(blockId, "Cover").
(C) fonts: re-find the family inside edit code and pass the payload straight to setFont — const { assets } = await engine.asset.findAssets("ly.img.gfonts", { query: name, page: 0, perPage: 20 }); const tf = assets.map((a) => a?.payload?.typeface).find((t) => t?.name === name); if (!tf) throw new Error("font lookup missed: " + assets.map((a) => a?.payload?.typeface?.name).join(", ")); engine.block.setFont(id, tf.fonts[0].uri, tf); engine.block.setTextFontWeight(id, "normal"). Take the EXACT name out of a page of results — fuzzy ranking can put it behind longer names (query "Lora" returns Explora first), so perPage: 1 fetches the wrong family. And always set the weight: tf.fonts[0] is the family's LIGHTEST declared weight (Thin/100 on Inter, Roboto, …), so setFont alone renders hairline text with no error. Never copy font URIs out of this tool into edit code.
Do NOT use engine.asset.applyToBlock — on this server it silently no-ops (the block keeps its old fill, no error).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page index. Default 0. | |
| query | No | Fuzzy search over asset labels and tags. | |
| perPage | No | Results per page. Default 20, max 50. | |
| sourceId | No | Asset source id. Omit to list all sources. |