@pixeldojo/mcp 0.31.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 +98 -49
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +98 -49
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +98 -49
- 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 +98 -49
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -246,6 +246,14 @@ async function snapAspectRatio(apiId, requested, client, opts = {}) {
|
|
|
246
246
|
if (!field.enum || field.enum.length === 0) return requested;
|
|
247
247
|
return nearestAspectFromEnum(requested, field.enum);
|
|
248
248
|
}
|
|
249
|
+
async function snapImageSizePreset(apiId, requested, client) {
|
|
250
|
+
if (!requested) return void 0;
|
|
251
|
+
const props2 = await getFieldConstraints(apiId, client);
|
|
252
|
+
const values = props2?.image_size?.enum;
|
|
253
|
+
if (!values || props2?.aspect_ratio) return void 0;
|
|
254
|
+
const key = requested.trim().replace(":", "_");
|
|
255
|
+
return values.find((v) => String(v).endsWith(`_${key}`));
|
|
256
|
+
}
|
|
249
257
|
async function resolveMediaSlot(apiId, kind, client) {
|
|
250
258
|
const info = await getModelInfo(apiId, client);
|
|
251
259
|
if (info === null) return void 0;
|
|
@@ -504,20 +512,24 @@ async function run(input, ctx) {
|
|
|
504
512
|
}
|
|
505
513
|
}
|
|
506
514
|
let refField;
|
|
515
|
+
let imageSizePreset;
|
|
507
516
|
let audioSlot;
|
|
508
517
|
if (!VIDEO_INPUT_MODELS.has(apiId)) {
|
|
509
|
-
const [aspect_ratio, duration, resolution, ref, audio] = await Promise.all([
|
|
518
|
+
const [aspect_ratio, imageSize, duration, resolution, ref, audio] = await Promise.all([
|
|
510
519
|
snapAspectRatio(apiId, resolved.aspect_ratio, ctx.client),
|
|
520
|
+
snapImageSizePreset(apiId, resolved.aspect_ratio, ctx.client),
|
|
511
521
|
snapDuration(apiId, resolved.duration, ctx.client),
|
|
512
522
|
snapResolution(apiId, resolved.resolution, ctx.client),
|
|
513
523
|
src.url ? resolveMediaSlot(apiId, src.isClip ? "video" : "image", ctx.client) : Promise.resolve(void 0),
|
|
514
524
|
src.audioUrl ? resolveMediaSlot(apiId, "audio", ctx.client) : Promise.resolve(void 0)
|
|
515
525
|
]);
|
|
516
526
|
resolved = { ...resolved, aspect_ratio, duration, resolution };
|
|
527
|
+
imageSizePreset = imageSize;
|
|
517
528
|
refField = ref === void 0 && src.url ? fallbackSlot(apiId, src.isClip ? "video" : "image") : ref;
|
|
518
529
|
audioSlot = audio === void 0 && src.audioUrl ? fallbackSlot(apiId, "audio") : audio;
|
|
519
530
|
}
|
|
520
531
|
const body = buildPayload(apiId, resolved, src, refField, audioSlot);
|
|
532
|
+
if (imageSizePreset) body.image_size = imageSizePreset;
|
|
521
533
|
const paramsNote = applyParams(body, input.params, input.model, apiId);
|
|
522
534
|
const note = [routeNote, paramsNote].filter(Boolean).join(" ");
|
|
523
535
|
const submitted = await ctx.client.run(apiId, body);
|
|
@@ -549,7 +561,7 @@ var init_generate = __esm({
|
|
|
549
561
|
InputSchema = z.object({
|
|
550
562
|
prompt: 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.'),
|
|
551
563
|
model: z.string().optional().describe(
|
|
552
|
-
`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 photo or up to 9 reference images
|
|
564
|
+
`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.`
|
|
553
565
|
),
|
|
554
566
|
preset: z.string().optional().describe(
|
|
555
567
|
"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."
|
|
@@ -588,7 +600,7 @@ var init_generate = __esm({
|
|
|
588
600
|
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.' },
|
|
589
601
|
model: {
|
|
590
602
|
type: "string",
|
|
591
|
-
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 photo or up to 9 reference images
|
|
603
|
+
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.`
|
|
592
604
|
},
|
|
593
605
|
preset: {
|
|
594
606
|
type: "string",
|
|
@@ -636,8 +648,8 @@ var init_generate = __esm({
|
|
|
636
648
|
};
|
|
637
649
|
generateSkill = {
|
|
638
650
|
name: "pixeldojo_generate",
|
|
639
|
-
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
|
|
640
|
-
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
|
|
651
|
+
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.",
|
|
652
|
+
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.",
|
|
641
653
|
inputZod: InputSchema,
|
|
642
654
|
inputJsonSchema: InputJsonSchema,
|
|
643
655
|
allowedModels: null,
|
|
@@ -923,7 +935,8 @@ var init_character = __esm({
|
|
|
923
935
|
"google-nano-banana",
|
|
924
936
|
"wan-2.7-image-edit",
|
|
925
937
|
"qwen-3-pro",
|
|
926
|
-
"qwen-image-2.0-pro"
|
|
938
|
+
"qwen-image-2.0-pro",
|
|
939
|
+
"p-h3-image"
|
|
927
940
|
];
|
|
928
941
|
DEFAULT_MODEL3 = "seedream-5";
|
|
929
942
|
MAX_REFERENCES = 9;
|
|
@@ -935,7 +948,8 @@ var init_character = __esm({
|
|
|
935
948
|
"google-nano-banana": "image_input",
|
|
936
949
|
"wan-2.7-image-edit": "image_urls",
|
|
937
950
|
"qwen-3-pro": "image",
|
|
938
|
-
"qwen-image-2.0-pro": "reference_images"
|
|
951
|
+
"qwen-image-2.0-pro": "reference_images",
|
|
952
|
+
"p-h3-image": "reference_images"
|
|
939
953
|
};
|
|
940
954
|
InputSchema3 = z.object({
|
|
941
955
|
prompt: z.string().min(1).max(8e3),
|
|
@@ -1679,7 +1693,7 @@ async function filmApi(ctx, method, path, body) {
|
|
|
1679
1693
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
1680
1694
|
"Content-Type": "application/json",
|
|
1681
1695
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
1682
|
-
"x-pixeldojo-skill": "
|
|
1696
|
+
"x-pixeldojo-skill": "pixeldojo_film"
|
|
1683
1697
|
},
|
|
1684
1698
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
1685
1699
|
});
|
|
@@ -2008,7 +2022,7 @@ It is saved in the Library folder "Film: ${film.title}".`,
|
|
|
2008
2022
|
}
|
|
2009
2023
|
const startExport = async () => {
|
|
2010
2024
|
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}`;
|
|
2025
|
+
return r.status === 200 || r.status === 409 && r.data.code === "export-running" ? null : r.data.error ?? `HTTP ${r.status}`;
|
|
2012
2026
|
};
|
|
2013
2027
|
if (film.exportError && all.length > 0 && all.every((sh) => sh.status === "clip-ready")) {
|
|
2014
2028
|
const again = await startExport();
|
|
@@ -2438,8 +2452,6 @@ function buildVideoPayload(verb, apiId, i) {
|
|
|
2438
2452
|
...vd !== void 0 ? { source_duration_seconds: vd } : {}
|
|
2439
2453
|
}
|
|
2440
2454
|
};
|
|
2441
|
-
case "flux-video-edit":
|
|
2442
|
-
return { body: { prompt, video: i.videoUrl, video_duration: Math.ceil(vd) }, note: droppedImages };
|
|
2443
2455
|
case "xai-video-edit":
|
|
2444
2456
|
return { body: { prompt, video_url: i.videoUrl, video_duration: vd }, note: droppedImages };
|
|
2445
2457
|
case "happyhorse-1.0-video-edit":
|
|
@@ -2470,6 +2482,17 @@ function buildVideoPayload(verb, apiId, i) {
|
|
|
2470
2482
|
}
|
|
2471
2483
|
}
|
|
2472
2484
|
if (verb === "move") {
|
|
2485
|
+
if (apiId === "p-video-2-pro-replace") {
|
|
2486
|
+
return {
|
|
2487
|
+
body: {
|
|
2488
|
+
prompt: "",
|
|
2489
|
+
video: i.videoUrl,
|
|
2490
|
+
images: i.images.slice(0, 2),
|
|
2491
|
+
video_duration: vd,
|
|
2492
|
+
...prompt ? { instruction_prompt: prompt } : {}
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2473
2496
|
if (apiId === "wan-video-character-swap") {
|
|
2474
2497
|
return { body: { prompt: "", image_url: i.images[0], video_url: i.videoUrl, video_duration: vd } };
|
|
2475
2498
|
}
|
|
@@ -2591,8 +2614,6 @@ var init_video = __esm({
|
|
|
2591
2614
|
VIDEO_STUDIO_ENGINES = {
|
|
2592
2615
|
change: [
|
|
2593
2616
|
"seedance-2-5-video-edit",
|
|
2594
|
-
"flux-video-edit",
|
|
2595
|
-
"kling-video-edit",
|
|
2596
2617
|
"kling-4-0",
|
|
2597
2618
|
"minimax-h3-turbo",
|
|
2598
2619
|
"wan-video-edit",
|
|
@@ -2600,24 +2621,24 @@ var init_video = __esm({
|
|
|
2600
2621
|
"happyhorse-1.0-video-edit",
|
|
2601
2622
|
"xai-video-edit"
|
|
2602
2623
|
],
|
|
2603
|
-
move: ["kling-motion-control", "wan-video-character-swap"],
|
|
2624
|
+
move: ["p-video-2-pro-replace", "kling-motion-control", "wan-video-character-swap"],
|
|
2604
2625
|
extend: ["seedance-2-5-video-edit", "wan-2.7-i2v", "grok-video-extend"]
|
|
2605
2626
|
};
|
|
2606
2627
|
VERBS = ["change", "move", "extend"];
|
|
2607
2628
|
BACKWARD_ENGINES = /* @__PURE__ */ new Set(["seedance-2-5-video-edit"]);
|
|
2608
2629
|
clamp = (n, min, max) => Math.min(max, Math.max(min, Math.round(n)));
|
|
2609
2630
|
NEEDS_VIDEO_DURATION = /* @__PURE__ */ new Set([
|
|
2610
|
-
"flux-video-edit",
|
|
2611
|
-
"kling-video-edit",
|
|
2612
2631
|
"wan-video-edit",
|
|
2613
2632
|
"seedance-video-edit",
|
|
2614
2633
|
"happyhorse-1.0-video-edit",
|
|
2615
2634
|
"xai-video-edit",
|
|
2616
2635
|
"kling-motion-control",
|
|
2617
2636
|
"wan-video-character-swap",
|
|
2618
|
-
"kling-4-0"
|
|
2637
|
+
"kling-4-0",
|
|
2638
|
+
// Its schema defaults the length, but the price is per second: a missing length would under-charge.
|
|
2639
|
+
"p-video-2-pro-replace"
|
|
2619
2640
|
]);
|
|
2620
|
-
NO_IMAGE_ENGINES = /* @__PURE__ */ new Set(["
|
|
2641
|
+
NO_IMAGE_ENGINES = /* @__PURE__ */ new Set(["xai-video-edit", "minimax-h3-turbo"]);
|
|
2621
2642
|
InputSchema11 = z.object({
|
|
2622
2643
|
verb: z.enum(VERBS),
|
|
2623
2644
|
prompt: z.string().max(8e3).optional(),
|
|
@@ -2643,7 +2664,7 @@ var init_video = __esm({
|
|
|
2643
2664
|
},
|
|
2644
2665
|
prompt: {
|
|
2645
2666
|
type: "string",
|
|
2646
|
-
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)."
|
|
2667
|
+
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)."
|
|
2647
2668
|
},
|
|
2648
2669
|
video_url: {
|
|
2649
2670
|
type: "string",
|
|
@@ -2709,7 +2730,7 @@ async function episodeApi(ctx, method, path, body) {
|
|
|
2709
2730
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
2710
2731
|
"Content-Type": "application/json",
|
|
2711
2732
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
2712
|
-
"x-pixeldojo-skill": "
|
|
2733
|
+
"x-pixeldojo-skill": "pixeldojo_episode"
|
|
2713
2734
|
},
|
|
2714
2735
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
2715
2736
|
});
|
|
@@ -2950,7 +2971,7 @@ async function dramaApi(ctx, method, path, body) {
|
|
|
2950
2971
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
2951
2972
|
"Content-Type": "application/json",
|
|
2952
2973
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
2953
|
-
"x-pixeldojo-skill": "
|
|
2974
|
+
"x-pixeldojo-skill": "pixeldojo_drama"
|
|
2954
2975
|
},
|
|
2955
2976
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
2956
2977
|
});
|
|
@@ -2964,9 +2985,10 @@ function describeDrama(v, o = DRAMA_OPTS) {
|
|
|
2964
2985
|
const next2 = (action) => `${o.tool} with {"${o.idField}": "${id}", "action": "${action}"}`;
|
|
2965
2986
|
const music = o.unit === "section";
|
|
2966
2987
|
const what = music ? "music video" : "episode";
|
|
2988
|
+
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.` };
|
|
2967
2989
|
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".` : ""}` };
|
|
2968
2990
|
if (v.status === "quote") {
|
|
2969
|
-
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,
|
|
2991
|
+
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).`;
|
|
2970
2992
|
return {
|
|
2971
2993
|
kind: "text",
|
|
2972
2994
|
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")
|
|
@@ -3049,9 +3071,11 @@ var init_drama = __esm({
|
|
|
3049
3071
|
end_text: z.string().max(60).optional(),
|
|
3050
3072
|
brand_color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
3051
3073
|
logo_url: z.string().url().optional(),
|
|
3052
|
-
cast: z.array(z.object({ name: z.string().min(1).max(40), image_url: z.string().url() })).max(5).optional(),
|
|
3074
|
+
cast: z.array(z.object({ name: z.string().min(1).max(40), image_url: z.string().url(), outfit_image_url: z.string().url().optional() })).max(5).optional(),
|
|
3075
|
+
length_sec: z.number().int().min(24).max(180).multipleOf(6).optional(),
|
|
3053
3076
|
scenes: z.number().int().min(1).max(15).optional(),
|
|
3054
3077
|
score: z.boolean().optional(),
|
|
3078
|
+
engine: z.enum(["seedance-2-5", "wan-3-0-video", "kling-4-0"]).optional(),
|
|
3055
3079
|
drama_id: z.string().max(60).optional(),
|
|
3056
3080
|
beats: z.array(z.number().int().min(1).max(15)).min(1).max(15).optional(),
|
|
3057
3081
|
notes: z.array(z.string().max(300)).max(15).optional()
|
|
@@ -3062,7 +3086,7 @@ var init_drama = __esm({
|
|
|
3062
3086
|
action: {
|
|
3063
3087
|
type: "string",
|
|
3064
3088
|
enum: ["create", "produce", "status", "redo", "cut"],
|
|
3065
|
-
description: "create (default, free): writes the
|
|
3089
|
+
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."
|
|
3066
3090
|
},
|
|
3067
3091
|
idea: { type: "string", description: "Create: the story in a line or two (who, the conflict, the twist)." },
|
|
3068
3092
|
format: { type: "string", enum: ["9:16", "16:9"], description: "Create: vertical 9:16 (default) or widescreen 16:9." },
|
|
@@ -3070,7 +3094,7 @@ var init_drama = __esm({
|
|
|
3070
3094
|
kind: {
|
|
3071
3095
|
type: "string",
|
|
3072
3096
|
enum: [...KINDS],
|
|
3073
|
-
description: "Create: micro-drama (default: episode one with a hook and a cliffhanger), short-film (a complete
|
|
3097
|
+
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)."
|
|
3074
3098
|
},
|
|
3075
3099
|
look: { type: "string", enum: [...LOOKS2], description: "Create (optional): the visual style and genre. Default live-action (a micro-drama story type brings its own)." },
|
|
3076
3100
|
story_type: {
|
|
@@ -3090,13 +3114,16 @@ var init_drama = __esm({
|
|
|
3090
3114
|
type: "object",
|
|
3091
3115
|
properties: {
|
|
3092
3116
|
name: { type: "string", description: "The character's name as the story uses it." },
|
|
3093
|
-
image_url: { type: "string", description:
|
|
3117
|
+
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).` },
|
|
3118
|
+
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.` }
|
|
3094
3119
|
},
|
|
3095
3120
|
required: ["name", "image_url"]
|
|
3096
3121
|
},
|
|
3097
|
-
description:
|
|
3122
|
+
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.'
|
|
3098
3123
|
},
|
|
3099
|
-
|
|
3124
|
+
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." },
|
|
3125
|
+
scenes: { type: "integer", minimum: 1, maximum: 15, description: "Create (optional, older): the length in 12-second units (5 = 60 s). Prefer length_sec." },
|
|
3126
|
+
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." },
|
|
3100
3127
|
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)." },
|
|
3101
3128
|
drama_id: { type: "string", description: "From create. Required for produce, status and redo." },
|
|
3102
3129
|
beats: { type: "array", items: { type: "integer", minimum: 1, maximum: 15 }, description: "Redo: the beat numbers to film again." },
|
|
@@ -3113,7 +3140,7 @@ var init_drama = __esm({
|
|
|
3113
3140
|
DRAMA_OPTS = { tool: "pixeldojo_drama", idField: "drama_id", unit: "beat" };
|
|
3114
3141
|
dramaSkill = {
|
|
3115
3142
|
name: "pixeldojo_drama",
|
|
3116
|
-
description: "Make a
|
|
3143
|
+
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).",
|
|
3117
3144
|
inputZod: InputSchema13,
|
|
3118
3145
|
inputJsonSchema: InputJsonSchema13,
|
|
3119
3146
|
allowedModels: ["seedance-2-5", "seedream-4"],
|
|
@@ -3128,7 +3155,9 @@ var init_drama = __esm({
|
|
|
3128
3155
|
...input.mature ? { mature: true } : {},
|
|
3129
3156
|
...input.look ? { look: input.look } : {},
|
|
3130
3157
|
...input.story_type ? { story_type: input.story_type } : {},
|
|
3158
|
+
...input.length_sec ? { length_sec: input.length_sec } : {},
|
|
3131
3159
|
...input.scenes ? { scenes: input.scenes } : {},
|
|
3160
|
+
...input.engine ? { engine: input.engine } : {},
|
|
3132
3161
|
...input.score === false ? { score: false } : {},
|
|
3133
3162
|
...Object.fromEntries(
|
|
3134
3163
|
["title_card", "name_tags", "end_screen", "end_text", "brand_color", "logo_url"].filter((k) => input[k] !== void 0).map((k) => [k, input[k]])
|
|
@@ -3157,7 +3186,7 @@ async function api(ctx, method, path, body) {
|
|
|
3157
3186
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
3158
3187
|
"Content-Type": "application/json",
|
|
3159
3188
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
3160
|
-
"x-pixeldojo-skill": "
|
|
3189
|
+
"x-pixeldojo-skill": "pixeldojo_music_video"
|
|
3161
3190
|
},
|
|
3162
3191
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
3163
3192
|
});
|
|
@@ -3286,7 +3315,7 @@ async function kataApi(ctx, method, path, body) {
|
|
|
3286
3315
|
Authorization: `Bearer ${ctx.apiKey}`,
|
|
3287
3316
|
"Content-Type": "application/json",
|
|
3288
3317
|
"x-pixeldojo-source": `mcp/${ctx.mcpVersion}`,
|
|
3289
|
-
"x-pixeldojo-skill": "
|
|
3318
|
+
"x-pixeldojo-skill": "pixeldojo_kata"
|
|
3290
3319
|
},
|
|
3291
3320
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
3292
3321
|
});
|
|
@@ -3450,7 +3479,7 @@ async function run13(input, ctx) {
|
|
|
3450
3479
|
aspect_ratio: input.aspect_ratio,
|
|
3451
3480
|
duration: input.duration,
|
|
3452
3481
|
reference_video_url: input.reference_video_url,
|
|
3453
|
-
brand_kit: input.brand_kit
|
|
3482
|
+
brand_kit: input.brand_kit === false ? false : input.brand_kit_id ?? input.brand_kit
|
|
3454
3483
|
};
|
|
3455
3484
|
const client = ctx.client;
|
|
3456
3485
|
const submitted = await client.runAd(body);
|
|
@@ -3495,7 +3524,8 @@ var init_ad = __esm({
|
|
|
3495
3524
|
aspect_ratio: z.enum(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]).optional(),
|
|
3496
3525
|
duration: z.number().int().min(4).max(15).optional(),
|
|
3497
3526
|
reference_video_url: z.string().url().optional(),
|
|
3498
|
-
brand_kit: z.boolean().optional()
|
|
3527
|
+
brand_kit: z.boolean().optional(),
|
|
3528
|
+
brand_kit_id: z.string().max(80).optional()
|
|
3499
3529
|
}).refine(
|
|
3500
3530
|
(v) => v.product_url || (v.product_image_urls?.length || v.product_image_paths?.length) && v.product_name,
|
|
3501
3531
|
{
|
|
@@ -3589,7 +3619,11 @@ var init_ad = __esm({
|
|
|
3589
3619
|
},
|
|
3590
3620
|
brand_kit: {
|
|
3591
3621
|
type: "boolean",
|
|
3592
|
-
description: "The account's brand kit (palette, voice, selling points; see pixeldojo_brand_kit) rides on every ad. false skips it."
|
|
3622
|
+
description: "The account's default brand kit (palette, voice, selling points; see pixeldojo_brand_kit) rides on every ad. false skips it."
|
|
3623
|
+
},
|
|
3624
|
+
brand_kit_id: {
|
|
3625
|
+
type: "string",
|
|
3626
|
+
description: "Use this saved brand kit instead of the default (ids listed by pixeldojo_brand_kit)."
|
|
3593
3627
|
}
|
|
3594
3628
|
}
|
|
3595
3629
|
// "product_url OR product_name+images" is enforced by the server and the
|
|
@@ -3930,7 +3964,8 @@ async function run18(input, ctx) {
|
|
|
3930
3964
|
}
|
|
3931
3965
|
const lines2 = characters.map(
|
|
3932
3966
|
(c) => `- ${c.mention} (${c.kind})${c.description ? `: ${c.description.slice(0, 100)}` : ""}
|
|
3933
|
-
images: ${c.image_urls.slice(0, 4).join(" ")}`
|
|
3967
|
+
images: ${c.image_urls.slice(0, 4).join(" ")}${c.video_pair && c.video_image_urls?.length === 2 ? `
|
|
3968
|
+
for video (face, outfit; pass both to pixeldojo_drama cast as image_url + outfit_image_url): ${c.video_image_urls.join(" ")}` : ""}`
|
|
3934
3969
|
);
|
|
3935
3970
|
return {
|
|
3936
3971
|
kind: "text",
|
|
@@ -4153,7 +4188,8 @@ async function effectRun(input, ctx) {
|
|
|
4153
4188
|
});
|
|
4154
4189
|
const data = await res.json().catch(() => ({}));
|
|
4155
4190
|
if (!res.ok || !data.jobId) {
|
|
4156
|
-
|
|
4191
|
+
const err = typeof data.error === "string" ? data.error : data.error?.message;
|
|
4192
|
+
return { kind: "text", text: `Effect not started (nothing charged): ${err ?? `HTTP ${res.status}`}` };
|
|
4157
4193
|
}
|
|
4158
4194
|
const result = await pollJobUntilDoneOrHandoff(data.jobId, (id) => ctx.client.getJob(id), ctx.buildStatusUrl, {
|
|
4159
4195
|
now: ctx.pollOverrides?.now,
|
|
@@ -4285,7 +4321,15 @@ ${describeKit(r2.data.brand_kit)}` };
|
|
|
4285
4321
|
}
|
|
4286
4322
|
const r = await call2(ctx, "pixeldojo_brand_kit", path);
|
|
4287
4323
|
if (!r.ok) return { kind: "text", text: `Could not read the brand kit: ${r.error}` };
|
|
4288
|
-
|
|
4324
|
+
const all = r.data.brand_kits ?? [];
|
|
4325
|
+
const others = all.filter((k) => !k.isDefault);
|
|
4326
|
+
return {
|
|
4327
|
+
kind: "text",
|
|
4328
|
+
text: [
|
|
4329
|
+
describeKit(r.data.brand_kit ?? null),
|
|
4330
|
+
...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("; ")}`] : []
|
|
4331
|
+
].join("\n")
|
|
4332
|
+
};
|
|
4289
4333
|
}
|
|
4290
4334
|
async function templatesRun(input, ctx) {
|
|
4291
4335
|
const q = new URLSearchParams();
|
|
@@ -4331,7 +4375,7 @@ async function imageRun(input, ctx) {
|
|
|
4331
4375
|
engine: input.engine,
|
|
4332
4376
|
count: input.count,
|
|
4333
4377
|
reference_ad_url: input.reference_ad_url,
|
|
4334
|
-
brand_kit: input.brand_kit
|
|
4378
|
+
brand_kit: input.brand_kit === false ? false : input.brand_kit_id ?? input.brand_kit
|
|
4335
4379
|
}
|
|
4336
4380
|
});
|
|
4337
4381
|
if (!r.ok) return { kind: "text", text: `Images not started: ${r.error}` };
|
|
@@ -4401,7 +4445,7 @@ async function motionRun(input, ctx) {
|
|
|
4401
4445
|
video_url: input.video_url,
|
|
4402
4446
|
brand_name: input.brand_name,
|
|
4403
4447
|
colors: input.colors?.map((c) => c.trim().toLowerCase()),
|
|
4404
|
-
brand_kit: input.brand_kit
|
|
4448
|
+
brand_kit: input.brand_kit === false ? false : input.brand_kit_id ?? input.brand_kit
|
|
4405
4449
|
}
|
|
4406
4450
|
});
|
|
4407
4451
|
if (!r.ok) return { kind: "text", text: `Not started: ${r.error}` };
|
|
@@ -4498,7 +4542,8 @@ var init_marketing = __esm({
|
|
|
4498
4542
|
motion_id: z.string().max(80).optional(),
|
|
4499
4543
|
brand_name: z.string().max(60).optional(),
|
|
4500
4544
|
colors: z.array(z.string()).max(5).optional(),
|
|
4501
|
-
brand_kit: z.boolean().optional()
|
|
4545
|
+
brand_kit: z.boolean().optional(),
|
|
4546
|
+
brand_kit_id: z.string().max(80).optional()
|
|
4502
4547
|
});
|
|
4503
4548
|
props = {
|
|
4504
4549
|
action: {
|
|
@@ -4534,7 +4579,8 @@ var init_marketing = __esm({
|
|
|
4534
4579
|
motion_id: { type: "string", description: "status: the id a motion or end_card call returned." },
|
|
4535
4580
|
brand_name: { type: "string", description: "motion: the brand shown when there is no logo. Default: the brand kit." },
|
|
4536
4581
|
colors: { type: "array", items: { type: "string" }, maxItems: 5, description: "motion: #RRGGBB, lead color first. Default: the brand kit." },
|
|
4537
|
-
brand_kit: { type: "boolean", description: "false skips the brand kit for this call." }
|
|
4582
|
+
brand_kit: { type: "boolean", description: "false skips the brand kit for this call." },
|
|
4583
|
+
brand_kit_id: { type: "string", description: "Use this saved brand kit instead of the default (ids listed by pixeldojo_brand_kit)." }
|
|
4538
4584
|
};
|
|
4539
4585
|
marketingSkill = {
|
|
4540
4586
|
name: "pixeldojo_marketing",
|
|
@@ -5062,7 +5108,7 @@ var init_skills = __esm({
|
|
|
5062
5108
|
}
|
|
5063
5109
|
};
|
|
5064
5110
|
});
|
|
5065
|
-
render = (title) => ({ title, readOnlyHint: false, destructiveHint: false, openWorldHint:
|
|
5111
|
+
render = (title) => ({ title, readOnlyHint: false, destructiveHint: false, openWorldHint: true });
|
|
5066
5112
|
read = (title) => ({ title, readOnlyHint: true, destructiveHint: false, openWorldHint: false });
|
|
5067
5113
|
TOOL_ANNOTATIONS = {
|
|
5068
5114
|
pixeldojo_generate: render("Generate image or video"),
|
|
@@ -5077,22 +5123,22 @@ var init_skills = __esm({
|
|
|
5077
5123
|
pixeldojo_effect: render("Run one-click effect"),
|
|
5078
5124
|
pixeldojo_video: render("Change, animate or extend video"),
|
|
5079
5125
|
pixeldojo_ad: render("Make video ad"),
|
|
5080
|
-
pixeldojo_brand_kit: render("Brand kit from website"),
|
|
5126
|
+
pixeldojo_brand_kit: { ...render("Brand kit from website"), destructiveHint: true },
|
|
5081
5127
|
pixeldojo_marketing: render("Image ads, motion graphics and templates"),
|
|
5082
5128
|
pixeldojo_campaign: render("Make product launch campaign"),
|
|
5083
|
-
pixeldojo_film: render("Make short film"),
|
|
5129
|
+
pixeldojo_film: { ...render("Make short film"), destructiveHint: true },
|
|
5084
5130
|
pixeldojo_episode: render("Make faceless video"),
|
|
5085
5131
|
pixeldojo_drama: render("Make micro-drama, short film or trailer"),
|
|
5086
5132
|
pixeldojo_music_video: render("Make music video for a song"),
|
|
5087
5133
|
pixeldojo_kata: render("Recreate an edit with your cast"),
|
|
5088
5134
|
pixeldojo_run_workflow: render("Run saved workflow"),
|
|
5089
5135
|
pixeldojo_upload: render("Upload local file"),
|
|
5090
|
-
pixeldojo_save_workflow: { ...render("Save workflow"), destructiveHint: true },
|
|
5136
|
+
pixeldojo_save_workflow: { ...render("Save workflow"), destructiveHint: true, openWorldHint: false },
|
|
5091
5137
|
pixeldojo_status: read("Check job status"),
|
|
5092
5138
|
pixeldojo_campaign_status: read("Check campaign status"),
|
|
5093
5139
|
pixeldojo_library: read("Search media library"),
|
|
5094
|
-
pixeldojo_save: render("Save to My Media"),
|
|
5095
|
-
pixeldojo_save_character: render("Save character or element"),
|
|
5140
|
+
pixeldojo_save: { ...render("Save to My Media"), openWorldHint: false },
|
|
5141
|
+
pixeldojo_save_character: { ...render("Save character or element"), openWorldHint: false },
|
|
5096
5142
|
pixeldojo_build_character: render("Build AI character from traits"),
|
|
5097
5143
|
pixeldojo_perform: render("Make character dance or do a trend"),
|
|
5098
5144
|
pixeldojo_list_workflows: read("List saved workflows"),
|
|
@@ -5151,7 +5197,7 @@ function makeRedactedLogger(target = console) {
|
|
|
5151
5197
|
}
|
|
5152
5198
|
|
|
5153
5199
|
// src/server.ts
|
|
5154
|
-
var PACKAGE_VERSION = "0.
|
|
5200
|
+
var PACKAGE_VERSION = "0.34.1" ;
|
|
5155
5201
|
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.";
|
|
5156
5202
|
function buildServer(options) {
|
|
5157
5203
|
if (!options.apiKey) {
|
|
@@ -5269,7 +5315,10 @@ function errorToActionableMessage(err) {
|
|
|
5269
5315
|
return "Authentication failed. Check PIXELDOJO_API_KEY. Get a key at https://pixeldojo.ai/api-platform/api-keys.";
|
|
5270
5316
|
}
|
|
5271
5317
|
if (e.status === 402 || e.code === "insufficient_credits") {
|
|
5272
|
-
return
|
|
5318
|
+
return (
|
|
5319
|
+
// ponytail: no checkout link, ChatGPT's plugin review bans linking to a purchase page.
|
|
5320
|
+
"Not enough credits for this. Add credits in your Pixel Dojo account, then try again."
|
|
5321
|
+
);
|
|
5273
5322
|
}
|
|
5274
5323
|
if (e.status === 429 || e.code === "rate_limit") {
|
|
5275
5324
|
return "Rate limit hit. Try again in a few seconds.";
|