@kolbo/mcp 1.76.4 → 1.76.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 +1 -1
- package/src/apps/widgets/generation.js +13 -7
- package/src/tools/_shared.js +9 -0
- package/src/tools/generate.js +12 -4
package/package.json
CHANGED
|
@@ -668,15 +668,21 @@ function renderAudio(sc, urls) {
|
|
|
668
668
|
var titleBase = track.title || sc.title || (TOOL_TITLES[sc.tool] || 'Audio');
|
|
669
669
|
var title = titleBase + (urls.length > 1 ? ' — Track ' + (i + 1) : '');
|
|
670
670
|
var duration = track.duration != null ? track.duration : sc.duration;
|
|
671
|
-
|
|
671
|
+
// The voice's own portrait is the artwork for speech — a generic note glyph
|
|
672
|
+
// told the user nothing about the one thing that defines the take.
|
|
673
|
+
var artwork = track.thumbnail_url || sc.thumbnail_url || sc.voice_thumbnail;
|
|
674
|
+
var placeholder = sc.tool === 'generate_speech' ? ICONS.mic : ICONS.audio;
|
|
672
675
|
return '<div class="k-audio-row k-generated-audio">' +
|
|
673
|
-
(artwork ? '<img class="k-audio-art" src="' + esc(artwork) + '" alt="" loading="lazy">' :
|
|
674
|
-
'<div class="k-audio-art k-audio-placeholder">' +
|
|
676
|
+
(artwork ? '<img class="k-audio-art" src="' + esc(artwork) + '" alt="" loading="lazy" onerror="this.style.display=\\'none\\'">' :
|
|
677
|
+
'<div class="k-audio-art k-audio-placeholder">' + placeholder + '</div>') +
|
|
675
678
|
'<div class="k-audio-meta"><div class="k-audio-title">' + esc(title) + '</div>' +
|
|
676
|
-
//
|
|
677
|
-
//
|
|
678
|
-
|
|
679
|
-
|
|
679
|
+
// Voice FIRST where there is one — on a speech row, who is speaking is the
|
|
680
|
+
// thing that defines the take; the engine is secondary. Resolved names
|
|
681
|
+
// only: a per-track model field is the raw id, and every track in one
|
|
682
|
+
// generation came from the same model anyway.
|
|
683
|
+
'<div class="k-audio-sub">' +
|
|
684
|
+
[voiceLabel(sc), modelLabel(sc) || track.model, duration ? fmtDur(duration) : '']
|
|
685
|
+
.filter(Boolean).map(esc).join(' · ') + '</div></div>' +
|
|
680
686
|
'<button class="k-btn k-audio-download" data-audio-download="' + esc(u) +
|
|
681
687
|
'" aria-label="Download ' + esc(title) + '">' + ICONS.download + ' Download</button>' +
|
|
682
688
|
'<audio class="k-audio-player" src="' + esc(u) + '" controls preload="none" aria-label="Play ' +
|
package/src/tools/_shared.js
CHANGED
|
@@ -611,6 +611,7 @@ async function uiGenerating(p) {
|
|
|
611
611
|
? { failed_submissions: p.failed_submissions } : {}),
|
|
612
612
|
...(p.warning ? { _warning: p.warning } : {}),
|
|
613
613
|
_widget_note: 'A live Kolbo widget is rendering this generation for the user (progress + final result + action buttons). Tell the user it is generating and the card above will update — do NOT poll in a loop. If you need the output URLs (e.g. for a follow-up edit or a report), call get_generation_status ONCE with wait=true — it blocks until done. Tracking several generations? Pass ALL their ids in generation_ids in that one call.',
|
|
614
|
+
_paid_note: 'This generation is RUNNING and the user is paying for it. If you now realize the tool, model, or parameters were wrong, call cancel_generation with this generation_id FIRST, then start the replacement — never leave a wrong generation running alongside its retry (the user gets two cards and two charges).',
|
|
614
615
|
}, null, 2);
|
|
615
616
|
return uiResult(UI.generation, text, structured);
|
|
616
617
|
}
|
|
@@ -659,6 +660,14 @@ async function uiCompleted(p, textPayload, extraContent) {
|
|
|
659
660
|
// above which assume everything finished together. Only set when the
|
|
660
661
|
// caller actually has this shape; every existing caller is unaffected.
|
|
661
662
|
...(Array.isArray(p.items) ? { items: p.items } : {}),
|
|
663
|
+
// The voice, by name and portrait. uiGenerating has carried this since the
|
|
664
|
+
// chips were introduced; uiCompleted never did, so it silently dropped a
|
|
665
|
+
// resolved voice its caller had already looked up — every FINISHED speech
|
|
666
|
+
// card fell back to `settings.voice`, printing a raw ElevenLabs id where the
|
|
667
|
+
// name belongs and rendering the generic note placeholder instead of the
|
|
668
|
+
// voice's face. Exactly the "never show a raw id on a card" rule, broken on
|
|
669
|
+
// the one path the user actually ends up looking at.
|
|
670
|
+
...(p.voice ? { voice_name: p.voice.name, voice_thumbnail: p.voice.thumbnail } : {}),
|
|
662
671
|
// The RAW generation state, when the caller has one. `phase` above is
|
|
663
672
|
// hardcoded 'completed' — it means "this tool call finished", not "the
|
|
664
673
|
// generation finished" — so a status check on a still-running job looked
|
package/src/tools/generate.js
CHANGED
|
@@ -541,7 +541,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
541
541
|
// retired textToVideoGeneration path and was stale.
|
|
542
542
|
server.tool(
|
|
543
543
|
'generate_video',
|
|
544
|
-
'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.',
|
|
544
|
+
'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. ROUTE BEFORE CALLING: when reference images anchor IDENTITY (specific characters, a specific product, a location that must match) — especially 2+ of them — that is generate_elements, not this tool; reference_images here are loose style/composition hints. Decide the right tool FIRST: a mis-routed call still starts a PAID generation, and switching tools afterwards without cancel_generation leaves the user paying for both. Returns the final video URL when complete.',
|
|
545
545
|
{
|
|
546
546
|
prompt: z.string().optional().describe('Text description of the video to generate. Required unless `prompts` is provided.'),
|
|
547
547
|
prompts: promptsField('videos'),
|
|
@@ -855,11 +855,19 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
855
855
|
if (poll.timedOut) return poll.timedOut;
|
|
856
856
|
const result = poll.result;
|
|
857
857
|
|
|
858
|
+
// What ACTUALLY ran, not what was asked for. The status result reports the
|
|
859
|
+
// engine's own choice (`model: "google_tts"`, `voice: "he-IL-Chirp3-HD-Kore"`)
|
|
860
|
+
// and for an omitted model that is the ONLY place the real answer appears —
|
|
861
|
+
// the card was labelling those "Smart Select", which is not even a text-to-
|
|
862
|
+
// speech option, and naming the voice the caller typed rather than the one
|
|
863
|
+
// that spoke. Same resolution addDisplayNames does for the polling path.
|
|
864
|
+
const ranVoice = (await voiceInfo(client, result.result?.voice).catch(() => null)) || voiceRecord;
|
|
858
865
|
return uiCompleted({
|
|
859
|
-
tool: 'generate_speech', kind: 'audio', gen, client,
|
|
860
|
-
|
|
866
|
+
tool: 'generate_speech', kind: 'audio', gen, client, prompt: text,
|
|
867
|
+
model: result.result?.model || model,
|
|
868
|
+
voice: ranVoice,
|
|
861
869
|
settings: {
|
|
862
|
-
voice: voice || 'Rachel',
|
|
870
|
+
voice: (ranVoice && ranVoice.name) || voice || 'Rachel',
|
|
863
871
|
style: selected_style || emotion || style_instructions_preset_id || style_instructions,
|
|
864
872
|
speaking_speed,
|
|
865
873
|
language,
|