@kolbo/mcp 1.75.8 → 1.76.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/package.json +1 -1
- package/src/tools/_shared.js +7 -0
- package/src/tools/generate.js +52 -15
package/package.json
CHANGED
package/src/tools/_shared.js
CHANGED
|
@@ -655,6 +655,13 @@ async function uiCompleted(p, textPayload, extraContent) {
|
|
|
655
655
|
// above which assume everything finished together. Only set when the
|
|
656
656
|
// caller actually has this shape; every existing caller is unaffected.
|
|
657
657
|
...(Array.isArray(p.items) ? { items: p.items } : {}),
|
|
658
|
+
// The RAW generation state, when the caller has one. `phase` above is
|
|
659
|
+
// hardcoded 'completed' — it means "this tool call finished", not "the
|
|
660
|
+
// generation finished" — so a status check on a still-running job looked
|
|
661
|
+
// done to every reader. A live generation card polls get_generation_status
|
|
662
|
+
// from its own iframe and reads `state` FIRST; without it, a processing job
|
|
663
|
+
// resolved as completed-with-no-media and painted a red failure card.
|
|
664
|
+
...(p.state ? { state: p.state } : {}),
|
|
658
665
|
credits_used: p.credits_used,
|
|
659
666
|
open_url: buildOpenUrl(p.tool, p.gen),
|
|
660
667
|
};
|
package/src/tools/generate.js
CHANGED
|
@@ -108,6 +108,17 @@ async function pollBatch(client, batch, { interval, timeout }, toolName) {
|
|
|
108
108
|
}, text);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// Same extension sniff the generation widget already does (kindFromTool in
|
|
112
|
+
// apps/widgets/generation.js) — a status check knows a url came back, not what
|
|
113
|
+
// kind of media it is, and the card needs the media kind to pick a renderer.
|
|
114
|
+
function mediaKind(url) {
|
|
115
|
+
const u = String(url || '').split('?')[0].toLowerCase();
|
|
116
|
+
if (/\.(mp4|mov|webm|mkv)$/.test(u)) return 'video';
|
|
117
|
+
if (/\.(mp3|wav|m4a|aac|ogg|flac)$/.test(u)) return 'audio';
|
|
118
|
+
if (/\.(glb|gltf|fbx|obj|usdz)$/.test(u)) return '3d';
|
|
119
|
+
return 'image';
|
|
120
|
+
}
|
|
121
|
+
|
|
111
122
|
// ─── Widget settings block ──────────────────────────────────────────────────
|
|
112
123
|
// What the CALLER actually asked for, for the generation card AND for the model
|
|
113
124
|
// reading the tool result. Undefined/false keys are dropped by JSON.stringify, so
|
|
@@ -508,13 +519,13 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
508
519
|
);
|
|
509
520
|
|
|
510
521
|
// ─── generate_video ────────────────────────────────────────
|
|
511
|
-
//
|
|
512
|
-
//
|
|
513
|
-
//
|
|
514
|
-
//
|
|
522
|
+
// Text-to-video is now a MODE inside videoGeneration/controller.js (sdk/controller.js
|
|
523
|
+
// posts mode:'text_to_video'), and that controller DOES read visualDnaIds — so Visual
|
|
524
|
+
// DNA works here. The old "text-to-video never reads visualDnaIds" note described the
|
|
525
|
+
// retired textToVideoGeneration path and was stale.
|
|
515
526
|
server.tool(
|
|
516
527
|
'generate_video',
|
|
517
|
-
'Generate a video from a text prompt using Kolbo AI. For SEVERAL different videos, pass all their prompts in `prompts` in ONE call (one combined widget) — never a series of separate calls. For animating an existing still image into motion, use generate_video_from_image instead. For a coordinated multi-scene video campaign, use generate_creative_director with workflow_type="video". Supports reference images (for style/composition guidance)
|
|
528
|
+
'Generate a video from a text prompt using Kolbo AI. For SEVERAL different videos, pass all their prompts in `prompts` in ONE call (one combined widget) — never a series of separate calls. For animating an existing still image into motion, use generate_video_from_image instead. For a coordinated multi-scene video campaign, use generate_creative_director with workflow_type="video". Supports reference images (for style/composition guidance) and Visual DNA for character consistency. Returns the final video URL when complete.',
|
|
518
529
|
{
|
|
519
530
|
prompt: z.string().optional().describe('Text description of the video to generate. Required unless `prompts` is provided.'),
|
|
520
531
|
prompts: promptsField('videos'),
|
|
@@ -525,16 +536,17 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
525
536
|
reference_images: z.array(z.string()).optional().describe('Array of image URLs used as visual references (style / composition / subject). **Cap: pass at most `max_reference_images` URLs from list_models for the chosen model — exceeding it is a deterministic 400.**'),
|
|
526
537
|
resolution: z.string().optional().describe('Video resolution tier (vertical pixels): "720p" / "1080p" / "1440p" / "2160p". Some models use labels like "512P"/"1024P"/"768P"/"1080P". Model-dependent — call list_models and read supported_resolutions. Read resolution_multipliers to predict cost.'),
|
|
527
538
|
preset_id: z.string().optional().describe('Preset ID from list_presets type="video" to apply a saved motion/style preset to this generation.'),
|
|
539
|
+
visual_dna_ids: z.array(z.string()).optional().describe('Array of Visual DNA profile IDs to apply for character/style consistency. Every DNA passed here MUST also be tagged in the prompt as @ExactDNAName. **Cap: pass at most `max_visual_dna` IDs from list_models for the chosen model; if `supports_visual_dna: false`, DNA is silently ignored.**'),
|
|
528
540
|
sound_enabled: z.boolean().optional().describe('Enable (`true`) or disable (`false`) AI-generated synced audio on the output video. Honored by `sound_generation_type: "native"` models (Veo 3.1, Kling V3/2.6, PixVerse V6). Seedance 2.x reports type "none" (no toggle) but `sound_baked_in: true` — those still emit real audio; do not tell the user the model is silent. Omit to use `sound_enabled_by_default`. Pass `false` only when the user asks for silent AND the model is native (not baked-in). Enabling sound may apply `sound_credit_multiplier` to cost.'),
|
|
529
541
|
skip_color_palette: z.boolean().optional().describe('Opt this single call OUT of the account\'s active Color DNA palette (see list_color_palettes / activate_color_palette). By default, if the user has an active palette it strict-grades every generation automatically — pass true only when the user explicitly wants this one video ungraded.'),
|
|
530
542
|
project_id: projectIdField,
|
|
531
543
|
session_id: sessionIdField
|
|
532
544
|
},
|
|
533
|
-
async ({ prompt, prompts, model, aspect_ratio, duration, enhance_prompt = false, reference_images, resolution, preset_id, sound_enabled, skip_color_palette, project_id, session_id }) => {
|
|
545
|
+
async ({ prompt, prompts, model, aspect_ratio, duration, enhance_prompt = false, reference_images, resolution, preset_id, visual_dna_ids, sound_enabled, skip_color_palette, project_id, session_id }) => {
|
|
534
546
|
if (!prompt && !(prompts && prompts.length)) throw new Error('Provide prompt or prompts');
|
|
535
547
|
model = await canonicalModelId(client, model, 'text_to_video'); // lenient id resolution ("z-image" → "z-image/turbo")
|
|
536
548
|
const shared = {
|
|
537
|
-
model, aspect_ratio, duration, enhance_prompt, reference_images, resolution, preset_id, sound_enabled, skip_color_palette, project_id, session_id
|
|
549
|
+
model, aspect_ratio, duration, enhance_prompt, reference_images, resolution, preset_id, visual_dna_ids, sound_enabled, skip_color_palette, project_id, session_id
|
|
538
550
|
};
|
|
539
551
|
|
|
540
552
|
// Batch mode: N different prompts, one widget owning all generation ids.
|
|
@@ -1015,10 +1027,29 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1015
1027
|
: pendingHint;
|
|
1016
1028
|
const singleText = JSON.stringify(single, null, 2);
|
|
1017
1029
|
const res = single.result || {};
|
|
1030
|
+
// A live generation card polls THIS branch from inside its own iframe,
|
|
1031
|
+
// and it reads structuredContent — never the text (apps/html.js
|
|
1032
|
+
// structured() returns structuredContent first and only falls back to
|
|
1033
|
+
// parsing content[].text). So preserving the flat TEXT shape, as the
|
|
1034
|
+
// comment above intended, protected nothing: the card does
|
|
1035
|
+
// `r = st.result || st` then `r.urls`, found only `items`, and painted
|
|
1036
|
+
// "No output received / Failed" over a generation that had completed
|
|
1037
|
+
// and billed. Every card rendered before v1.74 keeps that old iframe JS
|
|
1038
|
+
// forever, so the flat fields have to live in structuredContent too.
|
|
1039
|
+
const urls = Array.isArray(res.urls) ? res.urls : [];
|
|
1040
|
+
const done = single.state === 'completed' && urls.length > 0;
|
|
1018
1041
|
return uiCompleted({
|
|
1019
|
-
tool: 'get_generation_status', kind: 'status', client,
|
|
1020
|
-
model
|
|
1042
|
+
tool: 'get_generation_status', kind: done ? mediaKind(urls[0]) : 'status', client,
|
|
1043
|
+
// The model that ACTUALLY ran. A single-id check resolves one
|
|
1044
|
+
// generation, so 'Generations' here overwrote the real model name on
|
|
1045
|
+
// the finished card the moment the live widget merged this payload in.
|
|
1046
|
+
model: res.model || 'Generations', gen: { generation_id: single.generation_id },
|
|
1021
1047
|
settings: {},
|
|
1048
|
+
state: single.state,
|
|
1049
|
+
urls: done ? urls : undefined,
|
|
1050
|
+
thumbnail_url: res.thumbnail_url,
|
|
1051
|
+
prompt: res.prompt_used || res.prompt || undefined,
|
|
1052
|
+
credits_used: creditFields(single).credits_used,
|
|
1022
1053
|
items: [{
|
|
1023
1054
|
id: single.generation_id,
|
|
1024
1055
|
state: single.state,
|
|
@@ -1147,6 +1178,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1147
1178
|
enhance_prompt: z.boolean().optional().describe('Enhance the prompt. Default: false — only pass true if the user explicitly asks to enhance/improve the prompt.'),
|
|
1148
1179
|
visual_dna_ids: z.array(z.string()).optional().describe('Array of Visual DNA profile IDs to apply for character/style consistency across outputs. **Cap: pass at most `max_visual_dna` IDs from list_models for the chosen model.**'),
|
|
1149
1180
|
resolution: z.string().optional().describe('Video resolution tier (vertical pixels): "720p" / "1080p" / "1440p" / "2160p". Model-dependent — call list_models and read supported_resolutions.'),
|
|
1181
|
+
sound_enabled: z.boolean().optional().describe('Enable (`true`) or disable (`false`) AI-generated synced audio on the output video. Honored by `sound_generation_type: "native"` models (Kling O3/V3, Veo 3.1, PixVerse V6). Omit to use `sound_enabled_by_default`. Enabling sound may apply `sound_credit_multiplier` to cost.'),
|
|
1150
1182
|
keyframes: z.array(z.object({
|
|
1151
1183
|
image_url: z.string().describe('Public URL of the keyframe image'),
|
|
1152
1184
|
timestamp_seconds: z.number().describe('Moment on the OUTPUT timeline (seconds, 0 = first frame) where this image is pinned')
|
|
@@ -1157,7 +1189,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1157
1189
|
project_id: projectIdField,
|
|
1158
1190
|
session_id: sessionIdField
|
|
1159
1191
|
},
|
|
1160
|
-
async ({ prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, files, duration, aspect_ratio, motion, preset_id, enhance_prompt = false, visual_dna_ids, resolution, keyframes, multi_shots, multi_shot_count, session_name, project_id, session_id }) => {
|
|
1192
|
+
async ({ prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, files, duration, aspect_ratio, motion, preset_id, enhance_prompt = false, visual_dna_ids, resolution, sound_enabled, keyframes, multi_shots, multi_shot_count, session_name, project_id, session_id }) => {
|
|
1161
1193
|
model = await canonicalModelId(client, model, 'elements'); // lenient id resolution ("z-image" → "z-image/turbo")
|
|
1162
1194
|
if (!prompt) throw new Error('prompt is required');
|
|
1163
1195
|
|
|
@@ -1179,6 +1211,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1179
1211
|
if (reference_audio_urls) form.append('reference_audio_urls', JSON.stringify(reference_audio_urls));
|
|
1180
1212
|
if (audio_url) form.append('audio_url', audio_url);
|
|
1181
1213
|
if (resolution) form.append('resolution', resolution);
|
|
1214
|
+
if (sound_enabled !== undefined) form.append('sound_enabled', String(sound_enabled));
|
|
1182
1215
|
if (keyframes) form.append('keyframes', JSON.stringify(keyframes));
|
|
1183
1216
|
if (multi_shots !== undefined) form.append('multi_shots', String(multi_shots));
|
|
1184
1217
|
if (multi_shot_count !== undefined) form.append('multi_shot_count', String(multi_shot_count));
|
|
@@ -1192,7 +1225,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1192
1225
|
} else {
|
|
1193
1226
|
// URL-only mode: plain JSON.
|
|
1194
1227
|
startResponse = await client.post('/v1/generate/elements', {
|
|
1195
|
-
prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, duration, aspect_ratio, motion, preset_id, enhance_prompt, visual_dna_ids, resolution, keyframes, multi_shots, multi_shot_count, session_name, project_id, session_id
|
|
1228
|
+
prompt, model, reference_images, reference_videos, reference_audio_urls, audio_url, duration, aspect_ratio, motion, preset_id, enhance_prompt, visual_dna_ids, resolution, sound_enabled, keyframes, multi_shots, multi_shot_count, session_name, project_id, session_id
|
|
1196
1229
|
});
|
|
1197
1230
|
}
|
|
1198
1231
|
|
|
@@ -1269,10 +1302,11 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1269
1302
|
enhance_prompt: z.boolean().optional().describe('Enhance the prompt. Default: false — only pass true if the user explicitly asks to enhance/improve the prompt.'),
|
|
1270
1303
|
visual_dna_ids: z.array(z.string()).optional().describe('Array of Visual DNA profile IDs to apply. **Cap: pass at most `max_visual_dna` IDs from list_models for the chosen model; if `supports_visual_dna: false`, DNA is silently ignored.**'),
|
|
1271
1304
|
resolution: z.string().optional().describe('Video resolution tier (vertical pixels): "720p" / "1080p" / "1440p" / "2160p". Model-dependent — call list_models and read supported_resolutions.'),
|
|
1305
|
+
sound_enabled: z.boolean().optional().describe('Enable (`true`) or disable (`false`) AI-generated synced audio on the output video. Honored by `sound_generation_type: "native"` models (Kling O3/V3, Veo 3.1, PixVerse V6). Omit to use `sound_enabled_by_default`. Enabling sound may apply `sound_credit_multiplier` to cost.'),
|
|
1272
1306
|
project_id: projectIdField,
|
|
1273
1307
|
session_id: sessionIdField
|
|
1274
1308
|
},
|
|
1275
|
-
async ({ first_frame_url, last_frame_url, first_frame, last_frame, prompt, model, duration, aspect_ratio, enhance_prompt = false, visual_dna_ids, resolution, project_id, session_id }) => {
|
|
1309
|
+
async ({ first_frame_url, last_frame_url, first_frame, last_frame, prompt, model, duration, aspect_ratio, enhance_prompt = false, visual_dna_ids, resolution, sound_enabled, project_id, session_id }) => {
|
|
1276
1310
|
model = await canonicalModelId(client, model, 'firstlastgenerations'); // lenient id resolution ("z-image" → "z-image/turbo")
|
|
1277
1311
|
const urlMode = first_frame_url && last_frame_url;
|
|
1278
1312
|
const fileMode = first_frame && last_frame;
|
|
@@ -1299,12 +1333,13 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1299
1333
|
if (enhance_prompt !== undefined) form.append('enhance_prompt', String(enhance_prompt));
|
|
1300
1334
|
if (visual_dna_ids) form.append('visual_dna_ids', JSON.stringify(visual_dna_ids));
|
|
1301
1335
|
if (resolution) form.append('resolution', resolution);
|
|
1336
|
+
if (sound_enabled !== undefined) form.append('sound_enabled', String(sound_enabled));
|
|
1302
1337
|
if (project_id) form.append('project_id', project_id);
|
|
1303
1338
|
if (session_id) form.append('session_id', session_id);
|
|
1304
1339
|
startResponse = await client.postMultipart('/v1/generate/first-last-frame', form);
|
|
1305
1340
|
} else {
|
|
1306
1341
|
startResponse = await client.post('/v1/generate/first-last-frame', {
|
|
1307
|
-
first_frame_url, last_frame_url, prompt, model, duration, aspect_ratio, enhance_prompt, visual_dna_ids, resolution, project_id, session_id
|
|
1342
|
+
first_frame_url, last_frame_url, prompt, model, duration, aspect_ratio, enhance_prompt, visual_dna_ids, resolution, sound_enabled, project_id, session_id
|
|
1308
1343
|
});
|
|
1309
1344
|
}
|
|
1310
1345
|
|
|
@@ -1477,6 +1512,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1477
1512
|
reference_images: z.array(z.string()).optional().describe('Array of reference image URLs for models that support additional image inputs. **Cap: pass at most `max_images` URLs from list_models — if `max_images === 0` the model does not accept image refs.** Examples: character reference images for Kling O1/O3, style reference for Aleph/gen4_aleph, character image for WAN VACE video-edit.'),
|
|
1478
1513
|
reference_videos: z.array(z.string()).optional().describe('Array of additional reference video URLs for models that support multiple video inputs. **Cap: pass at most `max_videos` URLs from list_models — if `max_videos <= 1` only the source_video is accepted.** Example: WAN 2.6 reference-to-video accepts 1–3 reference videos.'),
|
|
1479
1514
|
elements: z.array(z.string()).optional().describe('Array of element image URLs. **Cap: pass at most `max_elements` URLs from list_models — if `max_elements === 0` the model does not accept elements.** Elements are style or character reference assets alongside the main video.'),
|
|
1515
|
+
sound_enabled: z.boolean().optional().describe('Enable (`true`) or disable (`false`) AI-generated synced audio on the output video. Honored by `sound_generation_type: "native"` models (Kling O3/V3, Veo 3.1, PixVerse V6). Omit to use `sound_enabled_by_default`. Enabling sound may apply `sound_credit_multiplier` to cost.'),
|
|
1480
1516
|
// VEED Subtitles (model: veed/subtitles) — burns styled subtitles into the video
|
|
1481
1517
|
preset: z.string().optional().describe('VEED Subtitles only: caption style preset (e.g. "glass", "whisper", "fusion", "simple", "vegas"). Call list_models type="video_to_video" for the veed/subtitles model. Ignored by other models.'),
|
|
1482
1518
|
source_language: z.string().optional().describe('VEED Subtitles only: BCP-47 code of the spoken language to improve transcription accuracy (e.g. "en-US", "es-ES", "he-IL"). Omit to auto-detect.'),
|
|
@@ -1498,7 +1534,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1498
1534
|
project_id: projectIdField,
|
|
1499
1535
|
session_id: sessionIdField
|
|
1500
1536
|
},
|
|
1501
|
-
async ({ source_video, prompt, model, aspect_ratio, duration, enhance_prompt = false, visual_dna_ids, resolution, reference_images, reference_videos, elements, preset, source_language, translation_language, srt_content, srt_file_url, vocabulary, customization, project_id, session_id }) => {
|
|
1537
|
+
async ({ source_video, prompt, model, aspect_ratio, duration, enhance_prompt = false, visual_dna_ids, resolution, sound_enabled, reference_images, reference_videos, elements, preset, source_language, translation_language, srt_content, srt_file_url, vocabulary, customization, project_id, session_id }) => {
|
|
1502
1538
|
model = await canonicalModelId(client, model, 'video_to_video'); // lenient id resolution ("z-image" → "z-image/turbo")
|
|
1503
1539
|
if (!source_video) throw new Error('source_video is required');
|
|
1504
1540
|
|
|
@@ -1506,7 +1542,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1506
1542
|
let startResponse;
|
|
1507
1543
|
if (isUrl) {
|
|
1508
1544
|
startResponse = await client.post('/v1/generate/video-from-video', {
|
|
1509
|
-
video_url: source_video, prompt, model, aspect_ratio, duration, enhance_prompt, visual_dna_ids, resolution,
|
|
1545
|
+
video_url: source_video, prompt, model, aspect_ratio, duration, enhance_prompt, visual_dna_ids, resolution, sound_enabled,
|
|
1510
1546
|
reference_images, reference_videos, elements, preset, source_language, translation_language,
|
|
1511
1547
|
srt_content, srt_file_url, vocabulary, customization, project_id, session_id
|
|
1512
1548
|
});
|
|
@@ -1528,6 +1564,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1528
1564
|
if (enhance_prompt !== undefined) form.append('enhance_prompt', String(enhance_prompt));
|
|
1529
1565
|
if (visual_dna_ids) form.append('visual_dna_ids', JSON.stringify(visual_dna_ids));
|
|
1530
1566
|
if (resolution) form.append('resolution', resolution);
|
|
1567
|
+
if (sound_enabled !== undefined) form.append('sound_enabled', String(sound_enabled));
|
|
1531
1568
|
if (reference_images) form.append('reference_images', JSON.stringify(reference_images));
|
|
1532
1569
|
if (reference_videos) form.append('reference_videos', JSON.stringify(reference_videos));
|
|
1533
1570
|
if (elements) form.append('elements', JSON.stringify(elements));
|