hermoso 0.1.530 → 0.1.531
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/README.md +2 -2
- package/mcp/tools.mjs +53 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Ask in your own words. The agent picks the tools:
|
|
|
67
67
|
- "Compare last week's Google Ads and Meta Ads results and tell me what to pause."
|
|
68
68
|
- "Schedule this video to TikTok, Instagram Reels and YouTube Shorts for Tuesday at 9am."
|
|
69
69
|
|
|
70
|
-
**
|
|
70
|
+
**1198 tools.** `tools/list` is always the authoritative set; `hermoso_capabilities` (free) returns the live model
|
|
71
71
|
catalog with exact per-render credit costs plus the full capability map.
|
|
72
72
|
|
|
73
73
|
**No markup on models** on Starter, Pro and Studio. Stop overpaying markups on AI models. Plans: [hermoso.ai/pricing](https://hermoso.ai/pricing).
|
|
@@ -304,7 +304,7 @@ block entirely if you signed in above; it is there for CI, where the process can
|
|
|
304
304
|
|
|
305
305
|
Then ask your agent: *“Generate an image ad with Hermoso.”*
|
|
306
306
|
|
|
307
|
-
### What the
|
|
307
|
+
### What the 1198 tools cover
|
|
308
308
|
|
|
309
309
|
**Ad spy / research** — `find_competitors`, `competitor_teardown`, `pull_competitor_ads`, `research_ads`; the
|
|
310
310
|
Meta / Google / LinkedIn ad libraries (`search_meta_ads`, `search_google_ads`, `search_linkedin_ads`); organic
|
package/mcp/tools.mjs
CHANGED
|
@@ -3061,7 +3061,7 @@ export const widgetHostHides = (name, widgetHost) => (widgetHost
|
|
|
3061
3061
|
// self-describing schema, and the default roster sits at its token ceiling. find_tools finds these, call_tool or a
|
|
3062
3062
|
// direct tools/call runs them, and enable_tools({groups:['create']}) (or 'all', or ?tools=all) lists them. post_edit's description names
|
|
3063
3063
|
// edit_timeline, and edit_timeline's names video_frames, so a caller that starts from post_edit reaches both.
|
|
3064
|
-
export const ON_DEMAND_TOOLS = new Set(['save_location', 'delete_location', 'edit_timeline', 'video_frames', 'recast_hook', 'face_check', 'list_templates', 'finish_draft', 'make_static_ads', 'make_listing_set', 'reangle_video', 'repurpose_transcript', 'tiktok_ideas', 'generate_sfx', 'repurpose_image', 'add_presenter', 'list_products', 'add_product', 'refresh_products', 'update_product', 'remove_product', 'make_short', 'finish_short', 'rewrite_ad_line', 'save_video_preset', 'list_video_presets', 'update_video_preset', 'delete_video_preset', 'make_from_preset', 'list_winning_ads']); // rewrite_ad_line (2026-11-08): multiply_ad's description and its change note name it // list_winning_ads (2026-11-08): multiply_ad's description names it // the five video-preset tools (2026-11-08): clone_video's description names save_video_preset, whose reply names make_from_preset; list_video_presets names the rest // make_short / finish_short (2026-11-08): clone_video's description names make_short, and make_short's description and reply name finish_short // make_static_ads (2026-10-06): plan_variations' description names it, so a caller planning variants reaches it; // recast_hook and face_check (2026-09-24): hook_variants names recast_hook, and recast_hook's reply names face_check // finish_draft (2026-10-03): every 480p Seedance 2.5 video reply names it (draftLine) // generate_sfx (2026-11-03): find_sound's and generate_voice's descriptions name it
|
|
3064
|
+
export const ON_DEMAND_TOOLS = new Set(['submit_to_gallery', 'list_gallery_submissions', 'withdraw_from_gallery', 'save_location', 'delete_location', 'edit_timeline', 'video_frames', 'recast_hook', 'face_check', 'list_templates', 'finish_draft', 'make_static_ads', 'make_listing_set', 'reangle_video', 'repurpose_transcript', 'tiktok_ideas', 'generate_sfx', 'repurpose_image', 'add_presenter', 'list_products', 'add_product', 'refresh_products', 'update_product', 'remove_product', 'make_short', 'finish_short', 'rewrite_ad_line', 'save_video_preset', 'list_video_presets', 'update_video_preset', 'delete_video_preset', 'make_from_preset', 'list_winning_ads']); // rewrite_ad_line (2026-11-08): multiply_ad's description and its change note name it // list_winning_ads (2026-11-08): multiply_ad's description names it // the five video-preset tools (2026-11-08): clone_video's description names save_video_preset, whose reply names make_from_preset; list_video_presets names the rest // make_short / finish_short (2026-11-08): clone_video's description names make_short, and make_short's description and reply name finish_short // make_static_ads (2026-10-06): plan_variations' description names it, so a caller planning variants reaches it; // recast_hook and face_check (2026-09-24): hook_variants names recast_hook, and recast_hook's reply names face_check // finish_draft (2026-10-03): every 480p Seedance 2.5 video reply names it (draftLine) // generate_sfx (2026-11-03): find_sound's and generate_voice's descriptions name it
|
|
3065
3065
|
|
|
3066
3066
|
// ── A TOOL NAME A HOST STILL HOLDS MUST KEEP ANSWERING (2026-09-14) ─────────────────────────────────────────────
|
|
3067
3067
|
// ChatGPT users get the tool roster OpenAI SNAPSHOTTED at review time, never a live tools/list (memory:
|
|
@@ -6671,7 +6671,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
6671
6671
|
verifiedAccount: z.boolean().optional().describe('true = verified accounts only'), hasPortfolio: z.boolean().optional().describe('true = creators with a portfolio only'), hasPublicContactEmail: z.boolean().optional().describe('true = creators with a public contact email only'),
|
|
6672
6672
|
featuredInPaidAds: z.boolean().optional().describe('true = creators featured in paid ads only'), excludeMessagedCreators: z.boolean().optional().describe('true = hide creators this brand has already messaged'),
|
|
6673
6673
|
limit: z.number().optional().describe('1 to 50'), cursor: z.string().optional().describe('next page: the cursor value from the previous reply'),
|
|
6674
|
-
pageId: z.string().optional().describe("Facebook Page id linked to the brand's Instagram; from list_meta_pages"), account: z.string().optional().describe('direct Instagram account (@handle or id) when several are connected; from list_connector_accounts'),
|
|
6674
|
+
pageId: z.string().optional().describe("Facebook Page id linked to the brand's Instagram; from list_meta_pages; if omitted, the Page that can search is used"), account: z.string().optional().describe('direct Instagram account (@handle or id) when several are connected; from list_connector_accounts'),
|
|
6675
6675
|
},
|
|
6676
6676
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
6677
6677
|
}, wrap(async (a) => {
|
|
@@ -27289,6 +27289,57 @@ function memoryNoteVerdict(text) {
|
|
|
27289
27289
|
return ok(`${d?.message || ''}${items ? '\n' + items : ''}${kept ? '\n' + kept : ''}${nf}`, { deleted: !!d?.deleted, needsConfirm: !!d?.needsConfirm });
|
|
27290
27290
|
}));
|
|
27291
27291
|
|
|
27292
|
+
// THE PUBLIC GALLERY (2026-11-10, lib/gallery.mjs): opt-in per item, reviewed by the Hermoso team before it is public,
|
|
27293
|
+
// withdrawable at once. Held on demand (ON_DEMAND_TOOLS); each reply names the next tool.
|
|
27294
|
+
const galleryUrlOf = async (id, url) => {
|
|
27295
|
+
if (url) return String(url);
|
|
27296
|
+
const m = /^L(\d+)$/i.exec(String(id || '').trim()); if (!m) return '';
|
|
27297
|
+
const list = await readStore('heist.assets.v1');
|
|
27298
|
+
return (Array.isArray(list) ? list.filter((x) => x && x.url) : [])[Number(m[1])]?.url || '';
|
|
27299
|
+
};
|
|
27300
|
+
server.registerTool('submit_to_gallery', {
|
|
27301
|
+
title: 'Submit to the Hermoso gallery',
|
|
27302
|
+
description: "Submit ONE image or video this brand made in Hermoso to the public Hermoso gallery. Only when the user asks. They must confirm they have the rights to it, including any people and logos in it (rights:true); their brand name shows only with showBrand:true. Nothing is public until the Hermoso team approves it. preview:true returns what would be public and saves nothing. Free.",
|
|
27303
|
+
inputSchema: {
|
|
27304
|
+
id: z.string().optional().describe('Library id (L0…) from list_library'),
|
|
27305
|
+
url: z.string().optional().describe('or the file link'),
|
|
27306
|
+
rights: z.boolean().optional().describe('true only after the user confirmed the rights'),
|
|
27307
|
+
showBrand: z.boolean().optional().describe('show the brand name (default false)'),
|
|
27308
|
+
title: z.string().optional(),
|
|
27309
|
+
format: z.enum(['ugc_video', 'product_video', 'talking_avatar', 'motion', 'product_photo', 'static_ad', 'carousel', 'other']).optional(),
|
|
27310
|
+
niche: z.enum(['beauty', 'fashion', 'food', 'fitness', 'health', 'tech', 'home', 'pets', 'finance', 'education', 'travel', 'local', 'other']).optional(),
|
|
27311
|
+
preview: z.boolean().optional(),
|
|
27312
|
+
},
|
|
27313
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
27314
|
+
}, wrap(async ({ id, url, rights, showBrand, title, format, niche, preview }) => {
|
|
27315
|
+
const u = await galleryUrlOf(id, url);
|
|
27316
|
+
if (!u) return ok('Pass a Library id (L0… from list_library) or the file link. Nothing was submitted.', { submitted: false });
|
|
27317
|
+
const d = await apiPost('/api/gallery/submit', { url: u, rights: rights === true, showBrand: showBrand === true, ...(title ? { title } : {}), ...(format ? { format } : {}), ...(niche ? { niche } : {}), ...(preview ? { preview: true } : {}) });
|
|
27318
|
+
if (d?.preview) { const p = d.public || {}; return ok(`Would be public:\n Title: ${p.title}\n Brand: ${p.brandShown || 'hidden'}\n${(p.recipe || []).map((r) => ` ${r.k}: ${r.v}`).join('\n')}\nNothing was saved. Ask the user to confirm the rights, then call again with rights:true.`, { preview: true, public: p }); }
|
|
27319
|
+
return ok(`${d?.message || 'Submitted.'} Status: ${d?.status}${d?.publicUrl ? ` · ${d.publicUrl}` : ''} (id ${d?.id}). list_gallery_submissions shows it; withdraw_from_gallery takes it down.`, { submitted: true, id: d?.id, status: d?.status, publicUrl: d?.publicUrl || null });
|
|
27320
|
+
}));
|
|
27321
|
+
server.registerTool('list_gallery_submissions', {
|
|
27322
|
+
title: 'List gallery submissions',
|
|
27323
|
+
description: "This brand's submissions to the public Hermoso gallery: each one's id, status (pending review, approved with its public page, rejected) and file. Free.",
|
|
27324
|
+
inputSchema: { all: z.boolean().optional().describe('include withdrawn ones') },
|
|
27325
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
27326
|
+
}, wrap(async ({ all }) => {
|
|
27327
|
+
const d = await apiGet('/api/gallery/mine', all ? { all: '1' } : {});
|
|
27328
|
+
const rows = d?.submissions || [];
|
|
27329
|
+
if (!rows.length) return ok('Nothing from this brand is in the gallery or waiting for review. submit_to_gallery adds one when the user asks.', { submissions: [] });
|
|
27330
|
+
return ok(rows.map((r) => `${r.id} · ${r.status}${r.publicUrl ? ` · ${r.publicUrl}` : ''} · ${r.title} · ${abs(r.url)}`).join('\n') + '\nwithdraw_from_gallery takes one down.', { submissions: rows });
|
|
27331
|
+
}));
|
|
27332
|
+
server.registerTool('withdraw_from_gallery', {
|
|
27333
|
+
title: 'Withdraw from the gallery',
|
|
27334
|
+
description: 'Take a submission off the public Hermoso gallery at once (its page stops working), whether pending or approved. Pass the submission id from list_gallery_submissions, or the file link. Free.',
|
|
27335
|
+
inputSchema: { id: z.string().optional().describe('submission id (g_…)'), url: z.string().optional().describe('or the file link') },
|
|
27336
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: true },
|
|
27337
|
+
}, wrap(async ({ id, url }) => {
|
|
27338
|
+
if (!id && !url) return ok('Pass the submission id (list_gallery_submissions) or the file link. Nothing was changed.', { withdrawn: [] });
|
|
27339
|
+
const d = await apiPost('/api/gallery/withdraw', { ...(id ? { id } : {}), ...(url ? { url } : {}) });
|
|
27340
|
+
return ok(d?.message || 'Withdrawn.', { withdrawn: d?.withdrawn || [] });
|
|
27341
|
+
}));
|
|
27342
|
+
|
|
27292
27343
|
server.registerTool('fetch_asset', {
|
|
27293
27344
|
title: 'Fetch asset',
|
|
27294
27345
|
description: 'Resolve a generated asset reference (a /generated/… path or any URL) to a clickable absolute URL + a direct download URL.',
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermoso",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.531",
|
|
4
4
|
"mcpName": "io.github.hermoso-ai/hermoso",
|
|
5
|
-
"description": "AI marketing agent and AI ad generator, run from your own AI agent.
|
|
5
|
+
"description": "AI marketing agent and AI ad generator, run from your own AI agent. 1198 tools. No markup on models on Starter and up. Publishing, scheduling, ad campaign management, comments, DMs and analytics cost no credits on any plan; Free includes 5 posts a month and every paid plan posts without a limit. AD PLATFORMS: Meta, Google Ads, TikTok Ads, LinkedIn Ads, Reddit Ads, X Ads, Pinterest Ads, Snapchat Ads, Microsoft Advertising, Apple Search Ads, ChatGPT Ads and AppLovin Ads, plus product feeds in Google Merchant Center. PUBLISHING AND SCHEDULING: Facebook, Instagram, Threads, TikTok, YouTube, X, LinkedIn, Pinterest, Bluesky, Telegram, WordPress, Discord, Slack, Whop and Google Business Profile. INSTAGRAM DM AUTOMATIONS: a keyword comment, a DM, a story reply or an ig.me link gets an automatic private reply from the brand. AD RESEARCH: the Meta, Google and LinkedIn ad libraries plus organic TikTok, Instagram, YouTube, Threads and Reddit. ANALYTICS: Google Analytics 4, Google Search Console and every connected platform's own post and campaign insights. Also brand onboarding, 50+ image and video generation models, ad scoring, competitor teardowns, Google Drive and OneDrive, a CLI and installable Claude skills.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"hermoso": "bin/hermoso.mjs"
|