@kolbo/mcp 1.82.2 → 1.82.5
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
CHANGED
|
@@ -280,8 +280,12 @@ function renderChips(sc) {
|
|
|
280
280
|
var s = sc.settings || {};
|
|
281
281
|
var kind = displayKind(sc);
|
|
282
282
|
if (kind) h += chip(iconFor(kind) + ' ' + kind);
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
// Shot count when we know it, otherwise just say multishot is on — the
|
|
284
|
+
// provider picks the count in that case, and showing nothing made an
|
|
285
|
+
// enabled toggle look like it had not applied.
|
|
286
|
+
var shotLabel = s.shots > 1 ? (s.shots + ' shots') : (s.multi_shot ? 'multishot' : '');
|
|
287
|
+
if (s.duration) h += chip(ICONS.clock + ' ' + fmtDur(s.duration) + (shotLabel ? ' · ' + shotLabel : ''));
|
|
288
|
+
else if (shotLabel) h += chip(shotLabel);
|
|
285
289
|
if (s.resolution) h += chip(esc(s.resolution));
|
|
286
290
|
if (s.aspect_ratio) h += chip(esc(s.aspect_ratio));
|
|
287
291
|
if (s.quality) h += chip(esc(s.quality) + ' quality');
|
|
@@ -790,7 +794,7 @@ function fillBatchCell(sc, i, g) {
|
|
|
790
794
|
// the user is meant to watch, and without it the tile was a muted poster with
|
|
791
795
|
// no way to play, seek or unmute until the whole batch finished and repainted.
|
|
792
796
|
cell.innerHTML = (sc.kind === 'video'
|
|
793
|
-
? '<video class="k-cell-fill" src="' + esc(
|
|
797
|
+
? '<video class="k-cell-fill" src="' + esc(playableAt(r, r.urls || [], 0)) + '"' + (r.thumbnail_url ? ' poster="' + esc(r.thumbnail_url) + '"' : '') + ' controls playsinline preload="metadata"></video>'
|
|
794
798
|
: '<img class="k-cell-fill" src="' + esc(u) + '" alt="">') + cap;
|
|
795
799
|
window.kolbo.notifySize();
|
|
796
800
|
}
|
|
@@ -858,10 +862,28 @@ function renderImages(sc, urls) {
|
|
|
858
862
|
});
|
|
859
863
|
}
|
|
860
864
|
|
|
865
|
+
/**
|
|
866
|
+
* The url to PLAY, which is not always the url to DOWNLOAD.
|
|
867
|
+
*
|
|
868
|
+
* Seedance 2.5 at 1080p returns HEVC Main 10 (10-bit). Chrome and Edge decode HEVC in
|
|
869
|
+
* hardware only — with no software fallback — and Firefox on Windows not at all, so the
|
|
870
|
+
* widget showed a black frame with sound. The API therefore returns playback_urls
|
|
871
|
+
* alongside urls whenever it had to build an H.264 proxy.
|
|
872
|
+
*
|
|
873
|
+
* urls stays the MASTER and is what every download button must keep using: handing
|
|
874
|
+
* someone the 8-bit proxy for a file they paid the 1080p multiplier for is a silent
|
|
875
|
+
* quality downgrade. Backend: kolbo-api/src/services/webPlaybackProxy.js
|
|
876
|
+
*/
|
|
877
|
+
function playableAt(src, urls, i) {
|
|
878
|
+
var proxies = (src && src.playback_urls) || [];
|
|
879
|
+
return proxies[i] || (urls || [])[i];
|
|
880
|
+
}
|
|
881
|
+
|
|
861
882
|
function renderVideo(sc, urls) {
|
|
862
883
|
// preload="none" behind a poster: the card shows the still until the user
|
|
863
884
|
// hits play, instead of pulling the video header on mount.
|
|
864
|
-
|
|
885
|
+
// PLAY the proxy when there is one; the download button below keeps urls[0] (master).
|
|
886
|
+
el('stage').innerHTML = '<div class="k-viewer"><video id="main-video" src="' + esc(playableAt(sc, urls, 0)) + '"' +
|
|
865
887
|
(sc.thumbnail_url ? ' poster="' + esc(sc.thumbnail_url) + '" preload="none"' : ' preload="metadata"') + ' controls playsinline></video>' +
|
|
866
888
|
dlBtnHTML(urls[0]) + '</div>';
|
|
867
889
|
wireDlButtons(el('stage'));
|
package/src/tools/generate.js
CHANGED
|
@@ -89,7 +89,7 @@ async function pollBatch(client, batch, { interval, timeout }, toolName) {
|
|
|
89
89
|
const polls = await Promise.all(batch.ids.map((id) => pollOrTimedOut(client, id, { interval, timeout })));
|
|
90
90
|
const generations = polls.map((p, i) => p.timedOut
|
|
91
91
|
? { prompt: batch.ok[i].prompt, generation_id: batch.ids[i], status: 'processing', note: 'Still running — call get_generation_status with wait=true to collect it.' }
|
|
92
|
-
: { prompt: batch.ok[i].prompt, generation_id: batch.ids[i], status: 'completed', ...creditFields(polls[i].result), urls: p.result.result.urls });
|
|
92
|
+
: { prompt: batch.ok[i].prompt, generation_id: batch.ids[i], status: 'completed', ...creditFields(polls[i].result), urls: p.result.result.urls, playback_urls: p.result.result.playback_urls });
|
|
93
93
|
const text = JSON.stringify({
|
|
94
94
|
batch: true,
|
|
95
95
|
session_id: batch.ok[0].gen.session_id,
|
|
@@ -186,6 +186,9 @@ const videoSettings = (a = {}) => ({
|
|
|
186
186
|
// echoed back on start, then to per-shot × shots.
|
|
187
187
|
duration: a.duration ?? a.reported_duration ?? (a.shot_duration && a.shots ? a.shot_duration * a.shots : undefined),
|
|
188
188
|
...(a.shots > 1 ? { shots: a.shots } : {}),
|
|
189
|
+
// Multishot with no explicit count: the provider decides how many, so there
|
|
190
|
+
// is no number to show — but the card still has to say the toggle applied.
|
|
191
|
+
...(a.multi_shot ? { multi_shot: true } : {}),
|
|
189
192
|
resolution: a.resolution,
|
|
190
193
|
aspect_ratio: a.aspect_ratio,
|
|
191
194
|
...(a.mode ? { mode: a.mode } : {}),
|
|
@@ -287,11 +290,13 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
287
290
|
// input arg is only what the caller happened to name.
|
|
288
291
|
reference_images: result.result.reference_images || reference_images,
|
|
289
292
|
urls: result.result.urls,
|
|
293
|
+
playback_urls: result.result.playback_urls,
|
|
290
294
|
credits_used: creditFields(result).credits_used,
|
|
291
295
|
}, JSON.stringify({
|
|
292
296
|
...creditFields(result),
|
|
293
297
|
session_id: gen.session_id,
|
|
294
298
|
urls: result.result.urls,
|
|
299
|
+
playback_urls: result.result.playback_urls,
|
|
295
300
|
model: result.result.model,
|
|
296
301
|
prompt_used: result.result.prompt_used,
|
|
297
302
|
_followup_hint: 'If the user asks to edit/change/modify this image next (scene, lighting, objects, style, color — any content edit), pass urls[0] to generate_image_edit. Use edit_image ONLY for mechanical ops (upscale/reframe/removebg/enhance_skin). Do NOT call generate_image again.'
|
|
@@ -377,11 +382,13 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
377
382
|
reference_images: result.result.reference_images
|
|
378
383
|
|| [...(source_images || []), ...(reference_images || [])],
|
|
379
384
|
urls: result.result.urls,
|
|
385
|
+
playback_urls: result.result.playback_urls,
|
|
380
386
|
credits_used: creditFields(result).credits_used,
|
|
381
387
|
}, JSON.stringify({
|
|
382
388
|
...creditFields(result),
|
|
383
389
|
session_id: gen.session_id,
|
|
384
390
|
urls: result.result.urls,
|
|
391
|
+
playback_urls: result.result.playback_urls,
|
|
385
392
|
model: result.result.model,
|
|
386
393
|
prompt_used: result.result.prompt_used,
|
|
387
394
|
_followup_hint: 'If the user asks for another edit on this output, pass urls[0] back into generate_image_edit as source_images. For targeted ops (upscale/reframe/removebg/enhance_skin) use edit_image instead. Do NOT call generate_image from scratch.'
|
|
@@ -624,6 +631,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
624
631
|
settings: videoSettings(shared),
|
|
625
632
|
reference_images,
|
|
626
633
|
urls: result.result.urls,
|
|
634
|
+
playback_urls: result.result.playback_urls,
|
|
627
635
|
thumbnail_url: result.result.thumbnail_url,
|
|
628
636
|
duration: result.result.duration,
|
|
629
637
|
credits_used: creditFields(result).credits_used,
|
|
@@ -631,6 +639,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
631
639
|
...creditFields(result),
|
|
632
640
|
session_id: gen.session_id,
|
|
633
641
|
urls: result.result.urls,
|
|
642
|
+
playback_urls: result.result.playback_urls,
|
|
634
643
|
model: result.result.model,
|
|
635
644
|
duration: result.result.duration,
|
|
636
645
|
thumbnail_url: result.result.thumbnail_url,
|
|
@@ -711,6 +720,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
711
720
|
settings: videoSettings({ duration, resolution, aspect_ratio, enhance_prompt, visual_dna_ids }),
|
|
712
721
|
reference_images: [image_url],
|
|
713
722
|
urls: result.result.urls,
|
|
723
|
+
playback_urls: result.result.playback_urls,
|
|
714
724
|
thumbnail_url: result.result.thumbnail_url,
|
|
715
725
|
duration: result.result.duration,
|
|
716
726
|
credits_used: creditFields(result).credits_used,
|
|
@@ -718,6 +728,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
718
728
|
...creditFields(result),
|
|
719
729
|
session_id: gen.session_id,
|
|
720
730
|
urls: result.result.urls,
|
|
731
|
+
playback_urls: result.result.playback_urls,
|
|
721
732
|
model: result.result.model,
|
|
722
733
|
duration: result.result.duration,
|
|
723
734
|
thumbnail_url: result.result.thumbnail_url,
|
|
@@ -778,6 +789,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
778
789
|
tool: 'generate_music', kind: 'audio', gen, client, model: model || 'Suno', prompt,
|
|
779
790
|
settings: { mode: instrumental ? 'instrumental' : (style || undefined), preset_id },
|
|
780
791
|
urls: result.result.urls,
|
|
792
|
+
playback_urls: result.result.playback_urls,
|
|
781
793
|
title: result.result.title,
|
|
782
794
|
duration: result.result.duration,
|
|
783
795
|
credits_used: creditFields(result).credits_used,
|
|
@@ -785,6 +797,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
785
797
|
...creditFields(result),
|
|
786
798
|
session_id: gen.session_id,
|
|
787
799
|
urls: result.result.urls,
|
|
800
|
+
playback_urls: result.result.playback_urls,
|
|
788
801
|
title: result.result.title,
|
|
789
802
|
duration: result.result.duration,
|
|
790
803
|
lyrics: result.result.lyrics
|
|
@@ -896,12 +909,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
896
909
|
language,
|
|
897
910
|
},
|
|
898
911
|
urls: result.result.urls,
|
|
912
|
+
playback_urls: result.result.playback_urls,
|
|
899
913
|
duration: result.result.duration,
|
|
900
914
|
credits_used: creditFields(result).credits_used,
|
|
901
915
|
}, JSON.stringify({
|
|
902
916
|
...creditFields(result),
|
|
903
917
|
session_id: gen.session_id,
|
|
904
918
|
urls: result.result.urls,
|
|
919
|
+
playback_urls: result.result.playback_urls,
|
|
905
920
|
voice: result.result.voice,
|
|
906
921
|
duration: result.result.duration,
|
|
907
922
|
...(unknownVoice ? { _warning: unknownVoice } : {})
|
|
@@ -961,12 +976,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
961
976
|
settings: { duration },
|
|
962
977
|
reference_images: seed_reference_image_url ? [seed_reference_image_url] : [],
|
|
963
978
|
urls: result.result.urls,
|
|
979
|
+
playback_urls: result.result.playback_urls,
|
|
964
980
|
duration: result.result.duration,
|
|
965
981
|
credits_used: creditFields(result).credits_used,
|
|
966
982
|
}, JSON.stringify({
|
|
967
983
|
...creditFields(result),
|
|
968
984
|
session_id: gen.session_id,
|
|
969
985
|
urls: result.result.urls,
|
|
986
|
+
playback_urls: result.result.playback_urls,
|
|
970
987
|
duration: result.result.duration
|
|
971
988
|
}, null, 2));
|
|
972
989
|
}
|
|
@@ -1374,7 +1391,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1374
1391
|
settings: videoSettings({
|
|
1375
1392
|
duration,
|
|
1376
1393
|
reported_duration: startResponse?.duration ?? startResponse?.result?.duration,
|
|
1377
|
-
|
|
1394
|
+
// `multi_shots` is a boolean (z.boolean()); the old
|
|
1395
|
+
// `Array.isArray(multi_shots) ? multi_shots.length : undefined`
|
|
1396
|
+
// branch could never be true, so enabling multishot WITHOUT an
|
|
1397
|
+
// explicit count left shots undefined and the card silently showed
|
|
1398
|
+
// no multishot indicator at all. Carry the flag so the chip can
|
|
1399
|
+
// render even when the shot count is the provider's to decide.
|
|
1400
|
+
shots: multi_shot_count,
|
|
1401
|
+
multi_shot: multi_shots === true || undefined,
|
|
1378
1402
|
resolution, aspect_ratio, enhance_prompt, visual_dna_ids, preset_id,
|
|
1379
1403
|
}),
|
|
1380
1404
|
// Already bucketed and deduped above, so a URL handed to `files`
|
|
@@ -1396,7 +1420,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1396
1420
|
settings: videoSettings({
|
|
1397
1421
|
duration,
|
|
1398
1422
|
reported_duration: result.result?.duration,
|
|
1399
|
-
|
|
1423
|
+
// `multi_shots` is a boolean (z.boolean()); the old
|
|
1424
|
+
// `Array.isArray(multi_shots) ? multi_shots.length : undefined`
|
|
1425
|
+
// branch could never be true, so enabling multishot WITHOUT an
|
|
1426
|
+
// explicit count left shots undefined and the card silently showed
|
|
1427
|
+
// no multishot indicator at all. Carry the flag so the chip can
|
|
1428
|
+
// render even when the shot count is the provider's to decide.
|
|
1429
|
+
shots: multi_shot_count,
|
|
1430
|
+
multi_shot: multi_shots === true || undefined,
|
|
1400
1431
|
resolution, aspect_ratio, enhance_prompt, visual_dna_ids, preset_id,
|
|
1401
1432
|
}),
|
|
1402
1433
|
reference_images: [...urlsOf('image'), ...(keyframes || []).map((keyframe) => keyframe.image_url)],
|
package/src/tools/visual_dna.js
CHANGED
|
@@ -102,7 +102,7 @@ function registerVisualDnaTools(server, client, options = {}) {
|
|
|
102
102
|
{
|
|
103
103
|
scope: z.enum(['all', 'personal', 'global', 'organization']).optional().describe('Default: "personal" — the user\'s own DNAs (plus a shared project\'s when project_id is set). "global" = the ~1000 system cast/preset DNAs, for browsing when the user needs a character and has none of their own. "organization" = org-shared. "all" = everything, rarely wanted.'),
|
|
104
104
|
search: z.string().optional().describe('Search by name, tags, or description (case-insensitive). Matches at WORD STARTS, so "man" finds "Man"/"Manager" but not "woman" or "romantic". Name matches are ranked first.'),
|
|
105
|
-
collection: z.string().optional().describe('Filter global presets by collection: cast, influencers, props, locations, styles,
|
|
105
|
+
collection: z.string().optional().describe('Filter global presets by collection: cast, influencers, props, locations, styles, street'),
|
|
106
106
|
tags: z.string().optional().describe('Comma-separated tags to filter by (OR logic)'),
|
|
107
107
|
page: z.number().optional().describe('Page number, 1-indexed. Default: 1. Needed to reach the global cast beyond the first page.'),
|
|
108
108
|
limit: z.number().optional().describe('Results per page, max 100. Default: 50'),
|