@pixeldojo/mcp 0.30.0 → 0.34.1
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 +8 -1
- package/dist/cli.cjs +144 -61
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +144 -61
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +144 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +144 -61
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -248,6 +248,14 @@ async function snapAspectRatio(apiId, requested, client, opts = {}) {
|
|
|
248
248
|
if (!field.enum || field.enum.length === 0) return requested;
|
|
249
249
|
return nearestAspectFromEnum(requested, field.enum);
|
|
250
250
|
}
|
|
251
|
+
async function snapImageSizePreset(apiId, requested, client) {
|
|
252
|
+
if (!requested) return void 0;
|
|
253
|
+
const props2 = await getFieldConstraints(apiId, client);
|
|
254
|
+
const values = props2?.image_size?.enum;
|
|
255
|
+
if (!values || props2?.aspect_ratio) return void 0;
|
|
256
|
+
const key = requested.trim().replace(":", "_");
|
|
257
|
+
return values.find((v) => String(v).endsWith(`_${key}`));
|
|
258
|
+
}
|
|
251
259
|
async function resolveMediaSlot(apiId, kind, client) {
|
|
252
260
|
const info = await getModelInfo(apiId, client);
|
|
253
261
|
if (info === null) return void 0;
|
|
@@ -506,20 +514,24 @@ async function run(input, ctx) {
|
|
|
506
514
|
}
|
|
507
515
|
}
|
|
508
516
|
let refField;
|
|
517
|
+
let imageSizePreset;
|
|
509
518
|
let audioSlot;
|
|
510
519
|
if (!VIDEO_INPUT_MODELS.has(apiId)) {
|
|
511
|
-
const [aspect_ratio, duration, resolution, ref, audio] = await Promise.all([
|
|
520
|
+
const [aspect_ratio, imageSize, duration, resolution, ref, audio] = await Promise.all([
|
|
512
521
|
snapAspectRatio(apiId, resolved.aspect_ratio, ctx.client),
|
|
522
|
+
snapImageSizePreset(apiId, resolved.aspect_ratio, ctx.client),
|
|
513
523
|
snapDuration(apiId, resolved.duration, ctx.client),
|
|
514
524
|
snapResolution(apiId, resolved.resolution, ctx.client),
|
|
515
525
|
src.url ? resolveMediaSlot(apiId, src.isClip ? "video" : "image", ctx.client) : Promise.resolve(void 0),
|
|
516
526
|
src.audioUrl ? resolveMediaSlot(apiId, "audio", ctx.client) : Promise.resolve(void 0)
|
|
517
527
|
]);
|
|
518
528
|
resolved = { ...resolved, aspect_ratio, duration, resolution };
|
|
529
|
+
imageSizePreset = imageSize;
|
|
519
530
|
refField = ref === void 0 && src.url ? fallbackSlot(apiId, src.isClip ? "video" : "image") : ref;
|
|
520
531
|
audioSlot = audio === void 0 && src.audioUrl ? fallbackSlot(apiId, "audio") : audio;
|
|
521
532
|
}
|
|
522
533
|
const body = buildPayload(apiId, resolved, src, refField, audioSlot);
|
|
534
|
+
if (imageSizePreset) body.image_size = imageSizePreset;
|
|
523
535
|
const paramsNote = applyParams(body, input.params, input.model, apiId);
|
|
524
536
|
const note = [routeNote, paramsNote].filter(Boolean).join(" ");
|
|
525
537
|
const submitted = await ctx.client.run(apiId, body);
|
|
@@ -551,7 +563,7 @@ var init_generate = __esm({
|
|
|
551
563
|
InputSchema = zod.z.object({
|
|
552
564
|
prompt: zod.z.string().min(1).max(8e3).describe('Prompt describing what to generate. Write @Name to use a character or element the user saved in Character Studio ("@Mara on a beach"): its photos are attached automatically on models that take reference images. pixeldojo_library source=characters lists them.'),
|
|
553
565
|
model: zod.z.string().optional().describe(
|
|
554
|
-
`Model apiId. Recommended (the models the PixelDojo studios use): "seedream-5" for images (the default), "seedance-2-5" for video (prompt only or a starting image), "wan-3-0-video" for video the others refuse. Use another model only when the user names one. Full catalog: https://pixeldojo.ai/api/v1/models; one model's fields: https://pixeldojo.ai/llm/{apiId}.txt. Omit for seedream-5, which makes still images only; name a video model to get a video.`
|
|
566
|
+
`Model apiId. Recommended (the models the PixelDojo studios use): "seedream-5" for images (the default), "seedance-2-5" for video (prompt only or a starting image), "kling-4-0" for a whole scene up to 30 s written as a shot list (dialogue in quotes, exact on-screen text), "minimax-h3-turbo" for the cheapest video from a prompt alone, a photo or up to 9 reference images, "wan-3-0-video" for video the others refuse. Use another model only when the user names one. Full catalog: https://pixeldojo.ai/api/v1/models; one model's fields: https://pixeldojo.ai/llm/{apiId}.txt. Omit for seedream-5, which makes still images only; name a video model to get a video.`
|
|
555
567
|
),
|
|
556
568
|
preset: zod.z.string().optional().describe(
|
|
557
569
|
"Preset slug that seeds the running model's settings; explicit fields and params override it. Each preset belongs to one model (browse them by model at https://pixeldojo.ai/presets), so set `model` to that preset's model: a slug the running model has no preset for is rejected with a 400 before any charge."
|
|
@@ -590,7 +602,7 @@ var init_generate = __esm({
|
|
|
590
602
|
prompt: { type: "string", description: 'Prompt describing what to generate. Write @Name to use a character or element the user saved in Character Studio ("@Mara on a beach"): its photos are attached automatically on models that take reference images. pixeldojo_library source=characters lists them.' },
|
|
591
603
|
model: {
|
|
592
604
|
type: "string",
|
|
593
|
-
description: `Model apiId. Recommended (the models the PixelDojo studios use): "seedream-5" for images (the default), "seedance-2-5" for video (prompt only or a starting image), "wan-3-0-video" for video the others refuse. Use another model only when the user names one. Full catalog: https://pixeldojo.ai/api/v1/models; one model's fields: https://pixeldojo.ai/llm/{apiId}.txt. Omit for seedream-5, which makes still images only; name a video model to get a video.`
|
|
605
|
+
description: `Model apiId. Recommended (the models the PixelDojo studios use): "seedream-5" for images (the default), "seedance-2-5" for video (prompt only or a starting image), "kling-4-0" for a whole scene up to 30 s written as a shot list (dialogue in quotes, exact on-screen text), "minimax-h3-turbo" for the cheapest video from a prompt alone, a photo or up to 9 reference images, "wan-3-0-video" for video the others refuse. Use another model only when the user names one. Full catalog: https://pixeldojo.ai/api/v1/models; one model's fields: https://pixeldojo.ai/llm/{apiId}.txt. Omit for seedream-5, which makes still images only; name a video model to get a video.`
|
|
594
606
|
},
|
|
595
607
|
preset: {
|
|
596
608
|
type: "string",
|
|
@@ -638,8 +650,8 @@ var init_generate = __esm({
|
|
|
638
650
|
};
|
|
639
651
|
generateSkill = {
|
|
640
652
|
name: "pixeldojo_generate",
|
|
641
|
-
description: "Generate an image or video from a prompt with any model in the PixelDojo catalog. With no `model`, a prompt runs on seedream-5, which makes still images only. For a video, name seedance-2-5, which works from a prompt alone or a starting image. If a provider refuses the content, retry once on wan-3-0-video (video) or seedream-5 (images), the least-restricted models. For a multi-shot film or a music video synced to a song use pixeldojo_film; to change, move or extend an existing clip use pixeldojo_video. These are the models the PixelDojo studios use; name another only when the user asks for it. References: `image_url`/`image_urls` for stills, `video_url` for a source clip, `image_path`/`image_paths` for absolute local files (uploaded to 24h temp storage first). A clip or an audio track URL with no `model` runs on seedance-2-reference; a named model that cannot read a clip is swapped for it and the result says so, while a named model with no audio input drops the track. Model-specific settings go in `params` alongside an explicit `model`. Returns asset URLs, or a jobId for pixeldojo_status when the job outlasts the 30s wait.",
|
|
642
|
-
hostedDescription: "Generate an image or video from a prompt with any model in the PixelDojo catalog. With no `model`, a prompt runs on seedream-5, which makes still images only. For a video, name seedance-2-5, which works from a prompt alone or a starting image. If a provider refuses the content, retry once on wan-3-0-video (video) or seedream-5 (images), the least-restricted models. For a multi-shot film or a music video synced to a song use pixeldojo_film; to change, move or extend an existing clip use pixeldojo_video. These are the models the PixelDojo studios use; name another only when the user asks for it. References: `image_url`/`image_urls` for stills and `video_url` for a source clip, all public http(s) URLs. A clip or an audio track URL with no `model` runs on seedance-2-reference; a named model that cannot read a clip is swapped for it and the result says so, while a named model with no audio input drops the track. Model-specific settings go in `params` alongside an explicit `model`. Returns asset URLs, or a jobId for pixeldojo_status when the job outlasts the 30s wait.",
|
|
653
|
+
description: "Generate an image or video from a prompt with any model in the PixelDojo catalog. With no `model`, a prompt runs on seedream-5, which makes still images only. For a video, name seedance-2-5, which works from a prompt alone or a starting image; kling-4-0 for a multi-shot scene up to 30 s with dialogue; minimax-h3-turbo for the lowest price, from a prompt alone, a photo or reference images. If a provider refuses the content, retry once on wan-3-0-video (video) or seedream-5 (images), the least-restricted models. For a multi-shot film or a music video synced to a song use pixeldojo_film; to change, move or extend an existing clip use pixeldojo_video. These are the models the PixelDojo studios use; name another only when the user asks for it. References: `image_url`/`image_urls` for stills, `video_url` for a source clip, `image_path`/`image_paths` for absolute local files (uploaded to 24h temp storage first). A clip or an audio track URL with no `model` runs on seedance-2-reference; a named model that cannot read a clip is swapped for it and the result says so, while a named model with no audio input drops the track. Model-specific settings go in `params` alongside an explicit `model`. Returns asset URLs, or a jobId for pixeldojo_status when the job outlasts the 30s wait.",
|
|
654
|
+
hostedDescription: "Generate an image or video from a prompt with any model in the PixelDojo catalog. With no `model`, a prompt runs on seedream-5, which makes still images only. For a video, name seedance-2-5, which works from a prompt alone or a starting image; kling-4-0 for a multi-shot scene up to 30 s with dialogue; minimax-h3-turbo for the lowest price, from a prompt alone, a photo or reference images. If a provider refuses the content, retry once on wan-3-0-video (video) or seedream-5 (images), the least-restricted models. For a multi-shot film or a music video synced to a song use pixeldojo_film; to change, move or extend an existing clip use pixeldojo_video. These are the models the PixelDojo studios use; name another only when the user asks for it. References: `image_url`/`image_urls` for stills and `video_url` for a source clip, all public http(s) URLs. A clip or an audio track URL with no `model` runs on seedance-2-reference; a named model that cannot read a clip is swapped for it and the result says so, while a named model with no audio input drops the track. Model-specific settings go in `params` alongside an explicit `model`. Returns asset URLs, or a jobId for pixeldojo_status when the job outlasts the 30s wait.",
|
|
643
655
|
inputZod: InputSchema,
|
|
644
656
|
inputJsonSchema: InputJsonSchema,
|
|
645
657
|
allowedModels: null,
|
|
@@ -925,7 +937,8 @@ var init_character = __esm({
|
|
|
925
937
|
"google-nano-banana",
|
|
926
938
|
"wan-2.7-image-edit",
|
|
927
939
|
"qwen-3-pro",
|
|
928
|
-
"qwen-image-2.0-pro"
|
|
940
|
+
"qwen-image-2.0-pro",
|
|
941
|
+
"p-h3-image"
|
|
929
942
|
];
|
|
930
943
|
DEFAULT_MODEL3 = "seedream-5";
|
|
931
944
|
MAX_REFERENCES = 9;
|
|
@@ -937,7 +950,8 @@ var init_character = __esm({
|
|
|
937
950
|
"google-nano-banana": "image_input",
|
|
938
951
|
"wan-2.7-image-edit": "image_urls",
|
|
939
952
|
"qwen-3-pro": "image",
|
|
940
|
-
"qwen-image-2.0-pro": "reference_images"
|
|
953
|
+
"qwen-image-2.0-pro": "reference_images",
|
|
954
|
+
"p-h3-image": "reference_images"
|
|
941
955
|
};
|
|
942
956
|
InputSchema3 = zod.z.object({
|
|
943
957
|
prompt: zod.z.string().min(1).max(8e3),
|
|
@@ -1053,6 +1067,8 @@ var init_storyboard = __esm({
|
|
|
1053
1067
|
ALLOWED2 = [
|
|
1054
1068
|
"veo-3.1-fast",
|
|
1055
1069
|
"veo-3.1-standard",
|
|
1070
|
+
// Kling 4.0 (2026-10-24): a brief written as a shot list renders as one clip, up to 30 s.
|
|
1071
|
+
"kling-4-0",
|
|
1056
1072
|
"kling-video-v3-standard-text",
|
|
1057
1073
|
"seedance-2-high",
|
|
1058
1074
|
VIDEO_REFERENCE_MODEL
|
|
@@ -1679,7 +1695,7 @@ async function filmApi(ctx, method, path, body) {
|
|
|
1679
1695
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
1680
1696
|
"Content-Type": "application/json",
|
|
1681
1697
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
1682
|
-
"x-pixeldojo-skill": "
|
|
1698
|
+
"x-pixeldojo-skill": "pixeldojo_film"
|
|
1683
1699
|
},
|
|
1684
1700
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
1685
1701
|
});
|
|
@@ -2008,7 +2024,7 @@ It is saved in the Library folder "Film: ${film.title}".`,
|
|
|
2008
2024
|
}
|
|
2009
2025
|
const startExport = async () => {
|
|
2010
2026
|
const r = await filmApi(ctx, "POST", `/api/films/${filmId}/export`, {});
|
|
2011
|
-
return r.status === 200 || r.status === 409 ? null : r.data.error ?? `HTTP ${r.status}`;
|
|
2027
|
+
return r.status === 200 || r.status === 409 && r.data.code === "export-running" ? null : r.data.error ?? `HTTP ${r.status}`;
|
|
2012
2028
|
};
|
|
2013
2029
|
if (film.exportError && all.length > 0 && all.every((sh) => sh.status === "clip-ready")) {
|
|
2014
2030
|
const again = await startExport();
|
|
@@ -2438,17 +2454,47 @@ function buildVideoPayload(verb, apiId, i) {
|
|
|
2438
2454
|
...vd !== void 0 ? { source_duration_seconds: vd } : {}
|
|
2439
2455
|
}
|
|
2440
2456
|
};
|
|
2441
|
-
case "flux-video-edit":
|
|
2442
|
-
return { body: { prompt, video: i.videoUrl, video_duration: Math.ceil(vd) }, note: droppedImages };
|
|
2443
2457
|
case "xai-video-edit":
|
|
2444
2458
|
return { body: { prompt, video_url: i.videoUrl, video_duration: vd }, note: droppedImages };
|
|
2445
2459
|
case "happyhorse-1.0-video-edit":
|
|
2446
2460
|
return { body: { prompt, video_url: i.videoUrl, video_duration: vd, reference_urls: i.images } };
|
|
2461
|
+
case "kling-4-0":
|
|
2462
|
+
return {
|
|
2463
|
+
body: {
|
|
2464
|
+
prompt: /@video\s*1/i.test(prompt) ? prompt : `Edit @Video1: ${prompt}`,
|
|
2465
|
+
video: i.videoUrl,
|
|
2466
|
+
reference_images: i.images,
|
|
2467
|
+
duration: clamp(Math.ceil(vd), 3, 30),
|
|
2468
|
+
resolution: "1080p"
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2471
|
+
case "minimax-h3-turbo":
|
|
2472
|
+
return {
|
|
2473
|
+
body: {
|
|
2474
|
+
prompt: `Recreate <Video 1> exactly: the same people, the same motion and timing, the same camera move and framing, with one change: ${prompt}`,
|
|
2475
|
+
reference_videos: [i.videoUrl],
|
|
2476
|
+
reference_video_audio: true,
|
|
2477
|
+
resolution: "720p",
|
|
2478
|
+
duration: clamp(Math.ceil(vd ?? 5), 5, 15)
|
|
2479
|
+
},
|
|
2480
|
+
note: droppedImages
|
|
2481
|
+
};
|
|
2447
2482
|
default:
|
|
2448
2483
|
return { body: { prompt, video_url: i.videoUrl, video_duration: vd, image_urls: i.images } };
|
|
2449
2484
|
}
|
|
2450
2485
|
}
|
|
2451
2486
|
if (verb === "move") {
|
|
2487
|
+
if (apiId === "p-video-2-pro-replace") {
|
|
2488
|
+
return {
|
|
2489
|
+
body: {
|
|
2490
|
+
prompt: "",
|
|
2491
|
+
video: i.videoUrl,
|
|
2492
|
+
images: i.images.slice(0, 2),
|
|
2493
|
+
video_duration: vd,
|
|
2494
|
+
...prompt ? { instruction_prompt: prompt } : {}
|
|
2495
|
+
}
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2452
2498
|
if (apiId === "wan-video-character-swap") {
|
|
2453
2499
|
return { body: { prompt: "", image_url: i.images[0], video_url: i.videoUrl, video_duration: vd } };
|
|
2454
2500
|
}
|
|
@@ -2570,30 +2616,31 @@ var init_video = __esm({
|
|
|
2570
2616
|
VIDEO_STUDIO_ENGINES = {
|
|
2571
2617
|
change: [
|
|
2572
2618
|
"seedance-2-5-video-edit",
|
|
2573
|
-
"
|
|
2574
|
-
"
|
|
2619
|
+
"kling-4-0",
|
|
2620
|
+
"minimax-h3-turbo",
|
|
2575
2621
|
"wan-video-edit",
|
|
2576
2622
|
"seedance-video-edit",
|
|
2577
2623
|
"happyhorse-1.0-video-edit",
|
|
2578
2624
|
"xai-video-edit"
|
|
2579
2625
|
],
|
|
2580
|
-
move: ["kling-motion-control", "wan-video-character-swap"],
|
|
2626
|
+
move: ["p-video-2-pro-replace", "kling-motion-control", "wan-video-character-swap"],
|
|
2581
2627
|
extend: ["seedance-2-5-video-edit", "wan-2.7-i2v", "grok-video-extend"]
|
|
2582
2628
|
};
|
|
2583
2629
|
VERBS = ["change", "move", "extend"];
|
|
2584
2630
|
BACKWARD_ENGINES = /* @__PURE__ */ new Set(["seedance-2-5-video-edit"]);
|
|
2585
2631
|
clamp = (n, min, max) => Math.min(max, Math.max(min, Math.round(n)));
|
|
2586
2632
|
NEEDS_VIDEO_DURATION = /* @__PURE__ */ new Set([
|
|
2587
|
-
"flux-video-edit",
|
|
2588
|
-
"kling-video-edit",
|
|
2589
2633
|
"wan-video-edit",
|
|
2590
2634
|
"seedance-video-edit",
|
|
2591
2635
|
"happyhorse-1.0-video-edit",
|
|
2592
2636
|
"xai-video-edit",
|
|
2593
2637
|
"kling-motion-control",
|
|
2594
|
-
"wan-video-character-swap"
|
|
2638
|
+
"wan-video-character-swap",
|
|
2639
|
+
"kling-4-0",
|
|
2640
|
+
// Its schema defaults the length, but the price is per second: a missing length would under-charge.
|
|
2641
|
+
"p-video-2-pro-replace"
|
|
2595
2642
|
]);
|
|
2596
|
-
NO_IMAGE_ENGINES = /* @__PURE__ */ new Set(["
|
|
2643
|
+
NO_IMAGE_ENGINES = /* @__PURE__ */ new Set(["xai-video-edit", "minimax-h3-turbo"]);
|
|
2597
2644
|
InputSchema11 = zod.z.object({
|
|
2598
2645
|
verb: zod.z.enum(VERBS),
|
|
2599
2646
|
prompt: zod.z.string().max(8e3).optional(),
|
|
@@ -2619,7 +2666,7 @@ var init_video = __esm({
|
|
|
2619
2666
|
},
|
|
2620
2667
|
prompt: {
|
|
2621
2668
|
type: "string",
|
|
2622
|
-
description: "What to change, how the character should move, or what happens next. Required for change and extend. Optional for move (wan-video-character-swap ignores it). @Name uses a character or element the user saved in Character Studio (photos attached automatically)."
|
|
2669
|
+
description: "What to change, how the character should move, or what happens next. Required for change and extend. Optional for move (p-video-2-pro-replace reads it as who becomes whom; wan-video-character-swap ignores it). @Name uses a character or element the user saved in Character Studio (photos attached automatically)."
|
|
2623
2670
|
},
|
|
2624
2671
|
video_url: {
|
|
2625
2672
|
type: "string",
|
|
@@ -2685,7 +2732,7 @@ async function episodeApi(ctx, method, path, body) {
|
|
|
2685
2732
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
2686
2733
|
"Content-Type": "application/json",
|
|
2687
2734
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
2688
|
-
"x-pixeldojo-skill": "
|
|
2735
|
+
"x-pixeldojo-skill": "pixeldojo_episode"
|
|
2689
2736
|
},
|
|
2690
2737
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
2691
2738
|
});
|
|
@@ -2926,7 +2973,7 @@ async function dramaApi(ctx, method, path, body) {
|
|
|
2926
2973
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
2927
2974
|
"Content-Type": "application/json",
|
|
2928
2975
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
2929
|
-
"x-pixeldojo-skill": "
|
|
2976
|
+
"x-pixeldojo-skill": "pixeldojo_drama"
|
|
2930
2977
|
},
|
|
2931
2978
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
2932
2979
|
});
|
|
@@ -2940,14 +2987,23 @@ function describeDrama(v, o = DRAMA_OPTS) {
|
|
|
2940
2987
|
const next2 = (action) => `${o.tool} with {"${o.idField}": "${id}", "action": "${action}"}`;
|
|
2941
2988
|
const music = o.unit === "section";
|
|
2942
2989
|
const what = music ? "music video" : "episode";
|
|
2990
|
+
if (v.status === "failed" && v.error?.startsWith("Prohibited content")) return { kind: "text", text: `${v.error} Tell the user this idea is prohibited content; do not rewrite it to get around the refusal.` };
|
|
2943
2991
|
if (v.status === "failed") return { kind: "text", text: `The ${what} stopped: ${v.error ?? "unknown error"}. Each render that failed was refunded.${v.beats.some((b) => b.url) ? ` Re-film ${o.unit}s with action "redo".` : ""}` };
|
|
2944
2992
|
if (v.status === "quote") {
|
|
2945
|
-
const cost = music ? `Filming costs about ${v.estimate_credits} credits (cast portraits and ${v.sections?.length ?? "several"} sections lip-synced to the song).` : `Filming costs about ${v.estimate_credits} credits (cast portraits,
|
|
2993
|
+
const cost = music ? `Filming costs about ${v.estimate_credits} credits (cast portraits and ${v.sections?.length ?? "several"} sections lip-synced to the song).` : `Filming costs about ${v.estimate_credits} credits (cast portraits, scenes of up to 30 seconds with their dialogue and sound${v.score === false ? ", no music" : ", and one score over the finished edit"}); every scene is checked, and a scene that drops a line or shows a clear fault waits for the user's OK before it is filmed again, at the scene's own price (a render that fails is tried again free).`;
|
|
2946
2994
|
return {
|
|
2947
2995
|
kind: "text",
|
|
2948
2996
|
text: [`Planned (${o.idField}: ${id}), ${v.format === "9:16" ? "vertical 9:16" : "widescreen 16:9"} (to switch, create it again in the other format before producing):`, v.plan ?? "", "", `Nothing has been charged yet. ${cost} Show this to the user and, once they agree, call ${next2("produce")}. (In Sensei: put it in pixeldojo_plan as ONE step with skill "${music ? "music_video" : "drama"}" and params {"${o.idField}": "${id}"}, which prices it from this quote.)`].join("\n")
|
|
2949
2997
|
};
|
|
2950
2998
|
}
|
|
2999
|
+
const gist = (note) => {
|
|
3000
|
+
const first = note.split(/(?<=\.) /)[0];
|
|
3001
|
+
return first.length > 160 ? `${first.slice(0, 157).trimEnd()}...` : first;
|
|
3002
|
+
};
|
|
3003
|
+
const rewrites = (b) => {
|
|
3004
|
+
const shots2 = Array.from(new Set(Array.from((b.redo_films ?? "").matchAll(/Shot (\d+) \(/g), (m) => m[1])));
|
|
3005
|
+
return shots2.length ? ` (the redo rewrites shot${shots2.length > 1 ? "s" : ""} ${shots2.join(", ")})` : "";
|
|
3006
|
+
};
|
|
2951
3007
|
if (v.status === "notes") {
|
|
2952
3008
|
const flagged = v.beats.filter((b) => b.note && (b.needs_redo ?? true));
|
|
2953
3009
|
const other = v.beats.filter((b) => b.note && b.needs_redo === false);
|
|
@@ -2955,17 +3011,17 @@ function describeDrama(v, o = DRAMA_OPTS) {
|
|
|
2955
3011
|
kind: "text",
|
|
2956
3012
|
text: [
|
|
2957
3013
|
`Every ${o.unit} is filmed. Before the cut, the review flagged ${o.unit}s ${flagged.map((b) => b.beat).join(", ")}:`,
|
|
2958
|
-
...flagged.map((b) => `- ${o.unit} ${b.beat}: ${b.note}${b
|
|
2959
|
-
other.length ? `Also noted, no redo needed: ${other.map((b) => `${o.unit} ${b.beat}: ${b.note}`).join(" ")}` : "",
|
|
3014
|
+
...flagged.map((b) => `- ${o.unit} ${b.beat}: ${gist(b.note)}${rewrites(b)}`),
|
|
3015
|
+
other.length ? `Also noted, no redo needed: ${other.map((b) => `${o.unit} ${b.beat}: ${gist(b.note)}`).join(" ")}` : "",
|
|
2960
3016
|
simplify,
|
|
2961
|
-
`Show these to the user and ask which they want: redo those ${o.unit}s with
|
|
3017
|
+
`Show these to the user and ask which they want: redo those ${o.unit}s with the review's fixes (${o.tool} with {"${o.idField}": "${id}", "action": "redo", "beats": [${flagged.map((b) => b.beat).join(", ")}]}, no notes needed, each at its own price; add notes only for the user's own changes), or cut it as it is (action "cut", free). Nothing more is filmed until they choose.`
|
|
2962
3018
|
].filter(Boolean).join("\n")
|
|
2963
3019
|
};
|
|
2964
3020
|
}
|
|
2965
3021
|
if (v.status === "done" && v.final_url) {
|
|
2966
3022
|
const redo = v.beats.filter((b) => (b.note || b.missing_lines.length) && (b.needs_redo ?? true));
|
|
2967
|
-
const notes = redo.map((b) => `${o.unit} ${b.beat}: ${b.note
|
|
2968
|
-
const other = v.beats.filter((b) => b.note && b.needs_redo === false).map((b) => `${o.unit} ${b.beat}: ${b.note}`);
|
|
3023
|
+
const notes = redo.map((b) => `${o.unit} ${b.beat}: ${b.note ? gist(b.note) : `did not say ${b.missing_lines.map((l) => `"${l}"`).join(", ")}`}`);
|
|
3024
|
+
const other = v.beats.filter((b) => b.note && b.needs_redo === false).map((b) => `${o.unit} ${b.beat}: ${gist(b.note)}`);
|
|
2969
3025
|
return {
|
|
2970
3026
|
kind: "assets",
|
|
2971
3027
|
text: [
|
|
@@ -2981,7 +3037,7 @@ function describeDrama(v, o = DRAMA_OPTS) {
|
|
|
2981
3037
|
const doing = music ? { scripting: "listening to the song and writing the plan", shots: "filming the sections", cutting: "cutting it to the song" }[v.status] ?? STEP[v.status] ?? v.status : STEP[v.status] ?? v.status;
|
|
2982
3038
|
const ready = v.beats.filter((b) => b.url).length;
|
|
2983
3039
|
const total = v.beats.length || (music ? v.sections?.length ?? 0 : 5);
|
|
2984
|
-
const again = v.rendering.map((n) => v.beats.find((b) => b.beat === n)).filter((b) => Boolean(b?.url)).map((b) => `${o.unit} ${b.beat} is being filmed again${b.missing_lines.length ? ` (it dropped the line "${b.missing_lines[0]}")` : b.note ? ` (the review asked: ${b.note
|
|
3040
|
+
const again = v.rendering.map((n) => v.beats.find((b) => b.beat === n)).filter((b) => Boolean(b?.url)).map((b) => `${o.unit} ${b.beat} is being filmed again${b.filming_note ? ` (your note: ${gist(b.filming_note)})` : b.missing_lines.length ? ` (it dropped the line "${b.missing_lines[0]}")` : b.note ? ` (the review asked: ${gist(b.note)})` : ""}`);
|
|
2985
3041
|
return {
|
|
2986
3042
|
kind: "text",
|
|
2987
3043
|
text: `Still ${doing}${v.status === "shots" ? ` (${ready} of ${total} ${o.unit}s ready${v.rendering.length ? `, filming ${o.unit} ${v.rendering.join(", ")}` : ""})` : ""}.${again.length ? ` ${again.join("; ")}.` : ""} It takes about 10 to 15 minutes in all. Call ${next2("status")} in about a minute.`,
|
|
@@ -3017,9 +3073,11 @@ var init_drama = __esm({
|
|
|
3017
3073
|
end_text: zod.z.string().max(60).optional(),
|
|
3018
3074
|
brand_color: zod.z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
3019
3075
|
logo_url: zod.z.string().url().optional(),
|
|
3020
|
-
cast: zod.z.array(zod.z.object({ name: zod.z.string().min(1).max(40), image_url: zod.z.string().url() })).max(5).optional(),
|
|
3076
|
+
cast: zod.z.array(zod.z.object({ name: zod.z.string().min(1).max(40), image_url: zod.z.string().url(), outfit_image_url: zod.z.string().url().optional() })).max(5).optional(),
|
|
3077
|
+
length_sec: zod.z.number().int().min(24).max(180).multipleOf(6).optional(),
|
|
3021
3078
|
scenes: zod.z.number().int().min(1).max(15).optional(),
|
|
3022
3079
|
score: zod.z.boolean().optional(),
|
|
3080
|
+
engine: zod.z.enum(["seedance-2-5", "wan-3-0-video", "kling-4-0"]).optional(),
|
|
3023
3081
|
drama_id: zod.z.string().max(60).optional(),
|
|
3024
3082
|
beats: zod.z.array(zod.z.number().int().min(1).max(15)).min(1).max(15).optional(),
|
|
3025
3083
|
notes: zod.z.array(zod.z.string().max(300)).max(15).optional()
|
|
@@ -3030,7 +3088,7 @@ var init_drama = __esm({
|
|
|
3030
3088
|
action: {
|
|
3031
3089
|
type: "string",
|
|
3032
3090
|
enum: ["create", "produce", "status", "redo", "cut"],
|
|
3033
|
-
description: "create (default, free): writes the
|
|
3091
|
+
description: "create (default, free): writes the plan (30 seconds unless length_sec says, cast, lines) and returns drama_id and the price. Show the plan and price to the user and wait for their OK. produce (charged): films it. status (free): progress; call every ~60s until it returns the episode. redo (charged): re-film chosen beats of a finished episode or one waiting at the review, then it cuts again. cut (free): when the review flagged beats and the user wants it as it is, cut it now."
|
|
3034
3092
|
},
|
|
3035
3093
|
idea: { type: "string", description: "Create: the story in a line or two (who, the conflict, the twist)." },
|
|
3036
3094
|
format: { type: "string", enum: ["9:16", "16:9"], description: "Create: vertical 9:16 (default) or widescreen 16:9." },
|
|
@@ -3038,7 +3096,7 @@ var init_drama = __esm({
|
|
|
3038
3096
|
kind: {
|
|
3039
3097
|
type: "string",
|
|
3040
3098
|
enum: [...KINDS],
|
|
3041
|
-
description: "Create: micro-drama (default: episode one with a hook and a cliffhanger), short-film (a complete
|
|
3099
|
+
description: "Create: micro-drama (default: episode one with a hook and a cliffhanger), short-film (a complete story) or trailer (sells a film that does not exist, never shows the ending)."
|
|
3042
3100
|
},
|
|
3043
3101
|
look: { type: "string", enum: [...LOOKS2], description: "Create (optional): the visual style and genre. Default live-action (a micro-drama story type brings its own)." },
|
|
3044
3102
|
story_type: {
|
|
@@ -3058,13 +3116,16 @@ var init_drama = __esm({
|
|
|
3058
3116
|
type: "object",
|
|
3059
3117
|
properties: {
|
|
3060
3118
|
name: { type: "string", description: "The character's name as the story uses it." },
|
|
3061
|
-
image_url: { type: "string", description:
|
|
3119
|
+
image_url: { type: "string", description: `A clear front-facing portrait on the PixelDojo CDN (a saved character's first "for video" picture when it has one).` },
|
|
3120
|
+
outfit_image_url: { type: "string", description: `Optional: the saved character's outfit picture (the second "for video" picture from pixeldojo_library). The scenes then keep their clothes closer.` }
|
|
3062
3121
|
},
|
|
3063
3122
|
required: ["name", "image_url"]
|
|
3064
3123
|
},
|
|
3065
|
-
description:
|
|
3124
|
+
description: 'Create (optional): up to 5 characters to star (people, animals or creatures), each with a portrait on the PixelDojo CDN (a saved character from pixeldojo_library; pass its "for video" face and outfit pictures when it lists them). Others get a portrait made for them.'
|
|
3066
3125
|
},
|
|
3067
|
-
|
|
3126
|
+
length_sec: { type: "integer", minimum: 24, maximum: 180, multipleOf: 6, description: "Create (optional): the film's length in seconds, 24 to 180 in steps of 6. Default 30. If the user has not said how long, ask (30 seconds, 1, 2 or 3 minutes; the price grows with the length) or leave it out for 30 seconds. The writer splits the length into scenes of up to 30 s, one per place and cast." },
|
|
3127
|
+
scenes: { type: "integer", minimum: 1, maximum: 15, description: "Create (optional, older): the length in 12-second units (5 = 60 s). Prefer length_sec." },
|
|
3128
|
+
engine: { type: "string", enum: ["seedance-2-5", "wan-3-0-video", "kling-4-0"], description: "Create (optional): the video model every scene films on, from the cast pictures. seedance-2-5 (default), wan-3-0-video (about a third of the price), kling-4-0. Pass it only when the user names one. Adult work always runs on wan-3-0-video." },
|
|
3068
3129
|
score: { type: "boolean", description: "Create (optional): one score laid over the finished edit, on by default and included in the price. Pass false only when the user wants no music (dialogue and ambience only)." },
|
|
3069
3130
|
drama_id: { type: "string", description: "From create. Required for produce, status and redo." },
|
|
3070
3131
|
beats: { type: "array", items: { type: "integer", minimum: 1, maximum: 15 }, description: "Redo: the beat numbers to film again." },
|
|
@@ -3081,7 +3142,7 @@ var init_drama = __esm({
|
|
|
3081
3142
|
DRAMA_OPTS = { tool: "pixeldojo_drama", idField: "drama_id", unit: "beat" };
|
|
3082
3143
|
dramaSkill = {
|
|
3083
3144
|
name: "pixeldojo_drama",
|
|
3084
|
-
description: "Make a
|
|
3145
|
+
description: "Make a micro-drama episode (30 seconds by default, up to 3 minutes with length_sec; hook, twist, cliffhanger; optionally a classic genre such as billionaire, werewolf or mafia), short film (a complete story) or movie trailer from an idea, vertical 9:16 or 16:9, in any of Film Studio's looks (live-action, anime, 3D animation, noir, horror, sci-fi, western, romance, comedy and more). Scenes of up to 30 seconds (one per place and cast), each filmed in one pass with several cuts, on Seedance 2.5, WAN 3 or Kling 4, the cast's faces kept from portraits and every line spoken and lip-synced, cut together with their own sound and one score over the finished edit, with free motion graphics (title card, name tags, end screen; each can be turned off), and saved to the Library. Not for music videos (pixeldojo_music_video) create is free and returns the plan and the exact price (about 190 credits for a regular 30 second film, about 380 for a minute; less on the wan-3-0-video engine and for mature work); produce films it; then call status until it is finished (10-15 minutes).",
|
|
3085
3146
|
inputZod: InputSchema13,
|
|
3086
3147
|
inputJsonSchema: InputJsonSchema13,
|
|
3087
3148
|
allowedModels: ["seedance-2-5", "seedream-4"],
|
|
@@ -3096,7 +3157,9 @@ var init_drama = __esm({
|
|
|
3096
3157
|
...input.mature ? { mature: true } : {},
|
|
3097
3158
|
...input.look ? { look: input.look } : {},
|
|
3098
3159
|
...input.story_type ? { story_type: input.story_type } : {},
|
|
3160
|
+
...input.length_sec ? { length_sec: input.length_sec } : {},
|
|
3099
3161
|
...input.scenes ? { scenes: input.scenes } : {},
|
|
3162
|
+
...input.engine ? { engine: input.engine } : {},
|
|
3100
3163
|
...input.score === false ? { score: false } : {},
|
|
3101
3164
|
...Object.fromEntries(
|
|
3102
3165
|
["title_card", "name_tags", "end_screen", "end_text", "brand_color", "logo_url"].filter((k) => input[k] !== void 0).map((k) => [k, input[k]])
|
|
@@ -3125,7 +3188,7 @@ async function api(ctx, method, path, body) {
|
|
|
3125
3188
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
3126
3189
|
"Content-Type": "application/json",
|
|
3127
3190
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
3128
|
-
"x-pixeldojo-skill": "
|
|
3191
|
+
"x-pixeldojo-skill": "pixeldojo_music_video"
|
|
3129
3192
|
},
|
|
3130
3193
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
3131
3194
|
});
|
|
@@ -3254,7 +3317,7 @@ async function kataApi(ctx, method, path, body) {
|
|
|
3254
3317
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
3255
3318
|
"Content-Type": "application/json",
|
|
3256
3319
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
3257
|
-
"x-pixeldojo-skill": "
|
|
3320
|
+
"x-pixeldojo-skill": "pixeldojo_kata"
|
|
3258
3321
|
},
|
|
3259
3322
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
3260
3323
|
});
|
|
@@ -3333,7 +3396,7 @@ var init_kata = __esm({
|
|
|
3333
3396
|
},
|
|
3334
3397
|
photos: {
|
|
3335
3398
|
type: "array",
|
|
3336
|
-
items: { type: "object", properties: { url: { type: "string" }, note: { type: "string", description: 'What it is (e.g. "the product").' } }, required: ["url"] },
|
|
3399
|
+
items: { type: "object", properties: { url: { type: "string", description: "Public URL of the photo." }, note: { type: "string", description: 'What it is (e.g. "the product").' } }, required: ["url"] },
|
|
3337
3400
|
description: "Create: up to 4 products or photos to put in the edit, on the PixelDojo CDN."
|
|
3338
3401
|
},
|
|
3339
3402
|
instructions: { type: "string", description: "Create (optional): what to change, e.g. the setting, the words on screen, where the product goes." },
|
|
@@ -3418,7 +3481,7 @@ async function run13(input, ctx) {
|
|
|
3418
3481
|
aspect_ratio: input.aspect_ratio,
|
|
3419
3482
|
duration: input.duration,
|
|
3420
3483
|
reference_video_url: input.reference_video_url,
|
|
3421
|
-
brand_kit: input.brand_kit
|
|
3484
|
+
brand_kit: input.brand_kit === false ? false : input.brand_kit_id ?? input.brand_kit
|
|
3422
3485
|
};
|
|
3423
3486
|
const client = ctx.client;
|
|
3424
3487
|
const submitted = await client.runAd(body);
|
|
@@ -3463,7 +3526,8 @@ var init_ad = __esm({
|
|
|
3463
3526
|
aspect_ratio: zod.z.enum(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]).optional(),
|
|
3464
3527
|
duration: zod.z.number().int().min(4).max(15).optional(),
|
|
3465
3528
|
reference_video_url: zod.z.string().url().optional(),
|
|
3466
|
-
brand_kit: zod.z.boolean().optional()
|
|
3529
|
+
brand_kit: zod.z.boolean().optional(),
|
|
3530
|
+
brand_kit_id: zod.z.string().max(80).optional()
|
|
3467
3531
|
}).refine(
|
|
3468
3532
|
(v) => v.product_url || (v.product_image_urls?.length || v.product_image_paths?.length) && v.product_name,
|
|
3469
3533
|
{
|
|
@@ -3557,7 +3621,11 @@ var init_ad = __esm({
|
|
|
3557
3621
|
},
|
|
3558
3622
|
brand_kit: {
|
|
3559
3623
|
type: "boolean",
|
|
3560
|
-
description: "The account's brand kit (palette, voice, selling points; see pixeldojo_brand_kit) rides on every ad. false skips it."
|
|
3624
|
+
description: "The account's default brand kit (palette, voice, selling points; see pixeldojo_brand_kit) rides on every ad. false skips it."
|
|
3625
|
+
},
|
|
3626
|
+
brand_kit_id: {
|
|
3627
|
+
type: "string",
|
|
3628
|
+
description: "Use this saved brand kit instead of the default (ids listed by pixeldojo_brand_kit)."
|
|
3561
3629
|
}
|
|
3562
3630
|
}
|
|
3563
3631
|
// "product_url OR product_name+images" is enforced by the server and the
|
|
@@ -3898,7 +3966,8 @@ async function run18(input, ctx) {
|
|
|
3898
3966
|
}
|
|
3899
3967
|
const lines2 = characters.map(
|
|
3900
3968
|
(c) => `- ${c.mention} (${c.kind})${c.description ? `: ${c.description.slice(0, 100)}` : ""}
|
|
3901
|
-
images: ${c.image_urls.slice(0, 4).join(" ")}`
|
|
3969
|
+
images: ${c.image_urls.slice(0, 4).join(" ")}${c.video_pair && c.video_image_urls?.length === 2 ? `
|
|
3970
|
+
for video (face, outfit; pass both to pixeldojo_drama cast as image_url + outfit_image_url): ${c.video_image_urls.join(" ")}` : ""}`
|
|
3902
3971
|
);
|
|
3903
3972
|
return {
|
|
3904
3973
|
kind: "text",
|
|
@@ -4121,7 +4190,8 @@ async function effectRun(input, ctx) {
|
|
|
4121
4190
|
});
|
|
4122
4191
|
const data = await res.json().catch(() => ({}));
|
|
4123
4192
|
if (!res.ok || !data.jobId) {
|
|
4124
|
-
|
|
4193
|
+
const err = typeof data.error === "string" ? data.error : data.error?.message;
|
|
4194
|
+
return { kind: "text", text: `Effect not started (nothing charged): ${err ?? `HTTP ${res.status}`}` };
|
|
4125
4195
|
}
|
|
4126
4196
|
const result = await pollJobUntilDoneOrHandoff(data.jobId, (id) => ctx.client.getJob(id), ctx.buildStatusUrl, {
|
|
4127
4197
|
now: ctx.pollOverrides?.now,
|
|
@@ -4253,7 +4323,15 @@ ${describeKit(r2.data.brand_kit)}` };
|
|
|
4253
4323
|
}
|
|
4254
4324
|
const r = await call2(ctx, "pixeldojo_brand_kit", path);
|
|
4255
4325
|
if (!r.ok) return { kind: "text", text: `Could not read the brand kit: ${r.error}` };
|
|
4256
|
-
|
|
4326
|
+
const all = r.data.brand_kits ?? [];
|
|
4327
|
+
const others = all.filter((k) => !k.isDefault);
|
|
4328
|
+
return {
|
|
4329
|
+
kind: "text",
|
|
4330
|
+
text: [
|
|
4331
|
+
describeKit(r.data.brand_kit ?? null),
|
|
4332
|
+
...others.length ? [`Other brand kits (pass brand_kit_id on a run to use one): ${others.map((k) => `${k.name || "(no name)"} (id ${k.id})`).join("; ")}`] : []
|
|
4333
|
+
].join("\n")
|
|
4334
|
+
};
|
|
4257
4335
|
}
|
|
4258
4336
|
async function templatesRun(input, ctx) {
|
|
4259
4337
|
const q = new URLSearchParams();
|
|
@@ -4299,7 +4377,7 @@ async function imageRun(input, ctx) {
|
|
|
4299
4377
|
engine: input.engine,
|
|
4300
4378
|
count: input.count,
|
|
4301
4379
|
reference_ad_url: input.reference_ad_url,
|
|
4302
|
-
brand_kit: input.brand_kit
|
|
4380
|
+
brand_kit: input.brand_kit === false ? false : input.brand_kit_id ?? input.brand_kit
|
|
4303
4381
|
}
|
|
4304
4382
|
});
|
|
4305
4383
|
if (!r.ok) return { kind: "text", text: `Images not started: ${r.error}` };
|
|
@@ -4369,7 +4447,7 @@ async function motionRun(input, ctx) {
|
|
|
4369
4447
|
video_url: input.video_url,
|
|
4370
4448
|
brand_name: input.brand_name,
|
|
4371
4449
|
colors: input.colors?.map((c) => c.trim().toLowerCase()),
|
|
4372
|
-
brand_kit: input.brand_kit
|
|
4450
|
+
brand_kit: input.brand_kit === false ? false : input.brand_kit_id ?? input.brand_kit
|
|
4373
4451
|
}
|
|
4374
4452
|
});
|
|
4375
4453
|
if (!r.ok) return { kind: "text", text: `Not started: ${r.error}` };
|
|
@@ -4424,11 +4502,11 @@ var init_marketing = __esm({
|
|
|
4424
4502
|
action: { type: "string", enum: ["get", "import", "update"], description: "Default get." },
|
|
4425
4503
|
url: { type: "string", description: "import: the brand website, e.g. yourbrand.com." },
|
|
4426
4504
|
save: { type: "boolean", description: "import: false returns the kit without saving it. Default true." },
|
|
4427
|
-
name: { type: "string" },
|
|
4428
|
-
tagline: { type: "string" },
|
|
4505
|
+
name: { type: "string", description: "Brand name." },
|
|
4506
|
+
tagline: { type: "string", description: "Short brand tagline." },
|
|
4429
4507
|
voice: { type: "string", description: "How the brand talks, one or two sentences." },
|
|
4430
4508
|
colors: { type: "array", items: { type: "string" }, maxItems: 5, description: "#RRGGBB, lead color first." },
|
|
4431
|
-
fonts: { type: "array", items: { type: "string" }, maxItems: 2 },
|
|
4509
|
+
fonts: { type: "array", items: { type: "string" }, maxItems: 2, description: "Up to two brand font names." },
|
|
4432
4510
|
selling_points: { type: "array", items: { type: "string" }, maxItems: 5, description: "Short product claims, 2-7 words each." },
|
|
4433
4511
|
logo_url: { type: "string", format: "uri", description: "A logo on PixelDojo (upload it first); PNG with transparency is best." }
|
|
4434
4512
|
}
|
|
@@ -4466,7 +4544,8 @@ var init_marketing = __esm({
|
|
|
4466
4544
|
motion_id: zod.z.string().max(80).optional(),
|
|
4467
4545
|
brand_name: zod.z.string().max(60).optional(),
|
|
4468
4546
|
colors: zod.z.array(zod.z.string()).max(5).optional(),
|
|
4469
|
-
brand_kit: zod.z.boolean().optional()
|
|
4547
|
+
brand_kit: zod.z.boolean().optional(),
|
|
4548
|
+
brand_kit_id: zod.z.string().max(80).optional()
|
|
4470
4549
|
});
|
|
4471
4550
|
props = {
|
|
4472
4551
|
action: {
|
|
@@ -4481,8 +4560,8 @@ var init_marketing = __esm({
|
|
|
4481
4560
|
description: `image: an image template id from templates (e.g. stacked-shout, pure-white, ice-float). motion: ${MOTION.join(", ")}.`
|
|
4482
4561
|
},
|
|
4483
4562
|
product_url: { type: "string", format: "uri", description: "image: product page; name, description and photos are read from it." },
|
|
4484
|
-
product_name: { type: "string" },
|
|
4485
|
-
product_description: { type: "string" },
|
|
4563
|
+
product_name: { type: "string", description: "Product name when there is no product_url (with product_image_urls)." },
|
|
4564
|
+
product_description: { type: "string", description: "Short product description when there is no product_url." },
|
|
4486
4565
|
product_image_urls: { type: "array", items: { type: "string", format: "uri" }, maxItems: 5, description: "Product photos. motion uses the first, cut out automatically." },
|
|
4487
4566
|
product_image_paths: { type: "array", items: { type: "string" }, maxItems: 5, description: "Local product photos instead of URLs; uploaded first." },
|
|
4488
4567
|
character_image_urls: { type: "array", items: { type: "string", format: "uri" }, maxItems: 2, description: "image: your own character (e.g. from pixeldojo_library source characters) for templates with a person." },
|
|
@@ -4502,7 +4581,8 @@ var init_marketing = __esm({
|
|
|
4502
4581
|
motion_id: { type: "string", description: "status: the id a motion or end_card call returned." },
|
|
4503
4582
|
brand_name: { type: "string", description: "motion: the brand shown when there is no logo. Default: the brand kit." },
|
|
4504
4583
|
colors: { type: "array", items: { type: "string" }, maxItems: 5, description: "motion: #RRGGBB, lead color first. Default: the brand kit." },
|
|
4505
|
-
brand_kit: { type: "boolean", description: "false skips the brand kit for this call." }
|
|
4584
|
+
brand_kit: { type: "boolean", description: "false skips the brand kit for this call." },
|
|
4585
|
+
brand_kit_id: { type: "string", description: "Use this saved brand kit instead of the default (ids listed by pixeldojo_brand_kit)." }
|
|
4506
4586
|
};
|
|
4507
4587
|
marketingSkill = {
|
|
4508
4588
|
name: "pixeldojo_marketing",
|
|
@@ -5030,7 +5110,7 @@ var init_skills = __esm({
|
|
|
5030
5110
|
}
|
|
5031
5111
|
};
|
|
5032
5112
|
});
|
|
5033
|
-
render = (title) => ({ title, readOnlyHint: false, destructiveHint: false, openWorldHint:
|
|
5113
|
+
render = (title) => ({ title, readOnlyHint: false, destructiveHint: false, openWorldHint: true });
|
|
5034
5114
|
read = (title) => ({ title, readOnlyHint: true, destructiveHint: false, openWorldHint: false });
|
|
5035
5115
|
exports.TOOL_ANNOTATIONS = {
|
|
5036
5116
|
pixeldojo_generate: render("Generate image or video"),
|
|
@@ -5045,22 +5125,22 @@ var init_skills = __esm({
|
|
|
5045
5125
|
pixeldojo_effect: render("Run one-click effect"),
|
|
5046
5126
|
pixeldojo_video: render("Change, animate or extend video"),
|
|
5047
5127
|
pixeldojo_ad: render("Make video ad"),
|
|
5048
|
-
pixeldojo_brand_kit: render("Brand kit from website"),
|
|
5128
|
+
pixeldojo_brand_kit: { ...render("Brand kit from website"), destructiveHint: true },
|
|
5049
5129
|
pixeldojo_marketing: render("Image ads, motion graphics and templates"),
|
|
5050
5130
|
pixeldojo_campaign: render("Make product launch campaign"),
|
|
5051
|
-
pixeldojo_film: render("Make short film"),
|
|
5131
|
+
pixeldojo_film: { ...render("Make short film"), destructiveHint: true },
|
|
5052
5132
|
pixeldojo_episode: render("Make faceless video"),
|
|
5053
5133
|
pixeldojo_drama: render("Make micro-drama, short film or trailer"),
|
|
5054
5134
|
pixeldojo_music_video: render("Make music video for a song"),
|
|
5055
5135
|
pixeldojo_kata: render("Recreate an edit with your cast"),
|
|
5056
5136
|
pixeldojo_run_workflow: render("Run saved workflow"),
|
|
5057
5137
|
pixeldojo_upload: render("Upload local file"),
|
|
5058
|
-
pixeldojo_save_workflow: { ...render("Save workflow"), destructiveHint: true },
|
|
5138
|
+
pixeldojo_save_workflow: { ...render("Save workflow"), destructiveHint: true, openWorldHint: false },
|
|
5059
5139
|
pixeldojo_status: read("Check job status"),
|
|
5060
5140
|
pixeldojo_campaign_status: read("Check campaign status"),
|
|
5061
5141
|
pixeldojo_library: read("Search media library"),
|
|
5062
|
-
pixeldojo_save: render("Save to My Media"),
|
|
5063
|
-
pixeldojo_save_character: render("Save character or element"),
|
|
5142
|
+
pixeldojo_save: { ...render("Save to My Media"), openWorldHint: false },
|
|
5143
|
+
pixeldojo_save_character: { ...render("Save character or element"), openWorldHint: false },
|
|
5064
5144
|
pixeldojo_build_character: render("Build AI character from traits"),
|
|
5065
5145
|
pixeldojo_perform: render("Make character dance or do a trend"),
|
|
5066
5146
|
pixeldojo_list_workflows: read("List saved workflows"),
|
|
@@ -5119,7 +5199,7 @@ function makeRedactedLogger(target = console) {
|
|
|
5119
5199
|
}
|
|
5120
5200
|
|
|
5121
5201
|
// src/server.ts
|
|
5122
|
-
var PACKAGE_VERSION = "0.
|
|
5202
|
+
var PACKAGE_VERSION = "0.34.1" ;
|
|
5123
5203
|
var SERVER_INSTRUCTIONS = "Pixel Dojo generates images, video, audio and short films from one catalog of AI models, billed in credits from the connected Pixel Dojo account. A job that runs past the 30-second wait returns a jobId to check later; check it rather than submitting again, since every new submission is charged. Generated asset URLs are deleted one hour after they are created: pixeldojo_save keeps one in the user's My Media permanently (after a safety check), and finished films stay in the account library. In any prompt, @Name uses a character, product, outfit, location, prop or style the user saved in Character Studio: its photos are attached automatically. pixeldojo_library source=characters lists them, and pixeldojo_save_character saves a new one from 3 to 5 photos.";
|
|
5124
5204
|
function buildServer(options) {
|
|
5125
5205
|
if (!options.apiKey) {
|
|
@@ -5237,7 +5317,10 @@ function errorToActionableMessage(err) {
|
|
|
5237
5317
|
return "Authentication failed. Check PIXELDOJO_API_KEY. Get a key at https://pixeldojo.ai/api-platform/api-keys.";
|
|
5238
5318
|
}
|
|
5239
5319
|
if (e.status === 402 || e.code === "insufficient_credits") {
|
|
5240
|
-
return
|
|
5320
|
+
return (
|
|
5321
|
+
// ponytail: no checkout link, ChatGPT's plugin review bans linking to a purchase page.
|
|
5322
|
+
"Not enough credits for this. Add credits in your Pixel Dojo account, then try again."
|
|
5323
|
+
);
|
|
5241
5324
|
}
|
|
5242
5325
|
if (e.status === 429 || e.code === "rate_limit") {
|
|
5243
5326
|
return "Rate limit hit. Try again in a few seconds.";
|