hermoso 0.1.63 → 0.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mcp/tools.mjs +13 -4
- package/package.json +1 -1
package/mcp/tools.mjs
CHANGED
|
@@ -7600,17 +7600,22 @@ export function registerTools(rawServer, opts = {}) {
|
|
|
7600
7600
|
|
|
7601
7601
|
server.registerTool('set_product_image', {
|
|
7602
7602
|
title: 'Set product photo',
|
|
7603
|
-
description: "Lock an image as the ad's real PRODUCT photo so every
|
|
7603
|
+
description: "Lock an image as the ad's real PRODUCT photo and SAVE it as this brand's default product, so every later plan_ad / render_ad / generate_image grounds on the true packaging without being told again. Pass `imageUrl` = a product shot's URL — an image from a prior research result (an organic Instagram/TikTok post, a scraped page image), a workspace / list_product_photos url, or any public product photo. The server downloads it and runs a product+safety check: a lifestyle/scene shot with no clear product, or an off-category / unsafe image, is REJECTED and NOTHING is locked or saved (the summary says why). On PASS it persists the photo to a DURABLE url, writes it to the brand's product library as the DEFAULT, and READS THE BRAND BACK to confirm — `savedToBrand` and the summary report what the brand ACTUALLY holds now, never what was asked for, so if it did not become the default you are told instead of finding out from a paid render. Bills one vision check. Reads YOUR saved brand for the category match (pass brandId to target a specific brand — switches this key's active brand like use_brand).",
|
|
7604
7604
|
inputSchema: {
|
|
7605
7605
|
imageUrl: z.string().describe('the image URL to lock as the product (from a research result, a workspace / list_product_photos url, or any public product photo)'),
|
|
7606
7606
|
source_note: z.string().optional().describe('a short note on where it came from, e.g. "from their IG post"'),
|
|
7607
7607
|
brandId: z.string().optional().describe('a brand id/name from list_brands to lock the product for; omit to use the active brand'),
|
|
7608
7608
|
},
|
|
7609
7609
|
outputSchema: {
|
|
7610
|
-
attached: z.boolean().optional().describe('true when the image passed the product check and was
|
|
7611
|
-
|
|
7610
|
+
attached: z.boolean().optional().describe('true when the image passed the product check and a durable url was minted'),
|
|
7611
|
+
savedToBrand: z.boolean().optional().describe('THE READ-BACK: true only when the brand row came back naming this photo as its default product. False means a render will NOT use it — see defaultProduct'),
|
|
7612
|
+
defaultProduct: z.string().nullable().optional().describe("the brand's default product photo as READ BACK from the store — the photo a render will actually ground on"),
|
|
7613
|
+
productImages: z.array(z.string()).nullable().optional().describe("the brand's product library as read back, newest first"),
|
|
7614
|
+
summary: z.string().optional().describe('the check verdict plus the read-back — on rejection, why nothing was locked; on a failed save, what a render would use instead'),
|
|
7612
7615
|
url: z.string().nullable().optional().describe('the durable served URL of the locked product photo'),
|
|
7613
7616
|
source_note: z.string().nullable().optional().describe('where the photo came from'),
|
|
7617
|
+
unconfirmed: z.string().nullable().optional().describe('set when the save landed but the confirming read failed — neither saved nor failed; verify with list_product_photos'),
|
|
7618
|
+
saveError: z.string().nullable().optional().describe('set when the photo passed the check but could NOT be saved to the brand'),
|
|
7614
7619
|
},
|
|
7615
7620
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
7616
7621
|
}, wrap(async ({ imageUrl, source_note, brandId }) => {
|
|
@@ -7619,7 +7624,11 @@ export function registerTools(rawServer, opts = {}) {
|
|
|
7619
7624
|
if (!d.attached) return ok(d.summary || 'That image was not locked as the product.', d); // gate honesty: rejected → nothing attached
|
|
7620
7625
|
const url = abs(d.url);
|
|
7621
7626
|
const img = await imageBlock(url); // show the locked product inline
|
|
7622
|
-
|
|
7627
|
+
// THE ANSWER IS THE READ-BACK. `d.summary` already carries it (productLockReadbackNote, server-side, one copy for
|
|
7628
|
+
// every surface). A photo that passed the check but did NOT become the brand's default must not be shown as a
|
|
7629
|
+
// finished job, so the headline is the read-back verdict rather than the ask — same law the ads tree follows.
|
|
7630
|
+
const head = d.savedToBrand ? 'Locked as this brand\u2019s product photo' : d.unconfirmed ? 'Checked and saved \u2014 but NOT confirmed' : 'Checked, but NOT saved as the brand\u2019s product photo';
|
|
7631
|
+
return { content: [{ type: 'text', text: `${head}.\n${d.summary}\nProduct photo: ${url}` }, ...(img ? [img] : [])], structuredContent: { ...d, url } };
|
|
7623
7632
|
}));
|
|
7624
7633
|
|
|
7625
7634
|
// APP SCREENS — the one asset class a headless caller could never acquire after onboarding. `draft_brand` pulls them
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermoso",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.64",
|
|
4
4
|
"mcpName": "io.github.hermoso-ai/hermoso",
|
|
5
5
|
"description": "Generate finished VIDEO ADS, image ads and UGC avatar ads for any brand with AI \u2014 spy on competitor ads across the Meta, Google and LinkedIn ad libraries plus TikTok/Instagram/YouTube organic \u2014 then publish to Facebook, Instagram, Threads, TikTok, YouTube, X, LinkedIn and Pinterest and build & manage the ad campaigns behind them on Meta, Google Ads, LinkedIn, Pinterest, Microsoft Advertising and ChatGPT Ads. MCP server (344 tools), CLI and Claude skills for Hermoso, the AI ad studio: brand onboarding, 30+ image/video models, finished-ad pipeline (script, voiceover, music, brand end card), ad scoring and competitor teardowns.",
|
|
6
6
|
"type": "module",
|