@kolbo/mcp 1.119.2 → 1.120.0
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
|
@@ -816,6 +816,9 @@ function poll(sc) {
|
|
|
816
816
|
return renderTrackingIssue('This is still running longer than the tracking window. Do not retry it — any completed result will appear in your Kolbo library.');
|
|
817
817
|
}
|
|
818
818
|
var args = sc.status_args || { generation_id: sc.generation_id, wait: true };
|
|
819
|
+
// Host-bridged calls may not reset their timeout on progress: keep each
|
|
820
|
+
// wait window inside the common 60s request timeout.
|
|
821
|
+
if (args.wait) args = Object.assign({}, args, { wait_seconds: 45 });
|
|
819
822
|
pollInFlight = true;
|
|
820
823
|
window.kolbo.callTool(sc.poll_tool || 'get_generation_status', args).then(function (res) {
|
|
821
824
|
pollInFlight = false;
|
|
@@ -1277,9 +1280,14 @@ function renderTrackingIssue(msg) {
|
|
|
1277
1280
|
el('stage').innerHTML = '<div class="k-error">' + ICONS.clock + ' ' + esc(msg) + '</div>';
|
|
1278
1281
|
el('actions').innerHTML = '<button class="k-btn primary" id="status-btn">' + ICONS.clock + ' Check status</button>' +
|
|
1279
1282
|
'<button class="k-btn ghost" id="tracking-open">Open in Kolbo ' + ICONS.open + '</button>';
|
|
1283
|
+
// Resume tracking in place: the card re-checks the SAME generation ids
|
|
1284
|
+
// (never a resubmit). A chat message alone left the card red even after
|
|
1285
|
+
// the agent learned the job had finished.
|
|
1280
1286
|
el('status-btn').onclick = function () {
|
|
1281
|
-
|
|
1282
|
-
|
|
1287
|
+
if (!state) return;
|
|
1288
|
+
pollErrors = 0; pollStart = 0;
|
|
1289
|
+
setPhaseChip('Checking', true);
|
|
1290
|
+
schedulePoll(state);
|
|
1283
1291
|
};
|
|
1284
1292
|
el('tracking-open').onclick = function () {
|
|
1285
1293
|
window.kolbo.openLink(kolboUrl(state));
|
|
@@ -94,6 +94,8 @@ function poll() {
|
|
|
94
94
|
return trackingIssue('This transcription is still running longer than the tracking window. Do not retry it — any completed result will appear in your Kolbo library.');
|
|
95
95
|
}
|
|
96
96
|
var args = state.status_args || { generation_id: state.generation_id, wait: true };
|
|
97
|
+
// Keep each host-bridged wait inside the common 60s request timeout.
|
|
98
|
+
if (args.wait) args = Object.assign({}, args, { wait_seconds: 45 });
|
|
97
99
|
window.kolbo.callTool(state.poll_tool || 'get_generation_status', args)
|
|
98
100
|
.then(function (res) {
|
|
99
101
|
var st = structured(res) || {};
|
|
@@ -129,9 +131,12 @@ function trackingIssue(msg) {
|
|
|
129
131
|
el('stage').classList.remove('k-empty');
|
|
130
132
|
el('stage').innerHTML = '<div class="k-error">' + ICONS.clock + ' ' + esc(msg) + '</div>';
|
|
131
133
|
el('actions').innerHTML = '<button class="k-btn primary" id="transcript-status">' + ICONS.clock + ' Check status</button>';
|
|
134
|
+
// Resume tracking in place (same generation id, never a resubmit).
|
|
132
135
|
el('transcript-status').onclick = function () {
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
if (!state) return;
|
|
137
|
+
pollErrors = 0;
|
|
138
|
+
el('actions').innerHTML = '';
|
|
139
|
+
boot(Object.assign({}, state, { phase: 'generating' }));
|
|
135
140
|
};
|
|
136
141
|
window.kolbo.notifySize();
|
|
137
142
|
}
|
package/src/tools/generate.js
CHANGED
|
@@ -604,16 +604,17 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
604
604
|
'Check the status of a Creative Director batch (from generate_creative_director) by its generation_id. Returns overall state ("processing" until EVERY scene is terminal, then "completed"/"failed") plus each scene\'s number, title, per-scene status, and image_urls/video_urls. Set wait=true to block until the batch is terminal or the wait window closes, whichever comes first — a batch longer than one window returns state="processing" and you simply call again with wait=true. Prefer this over the generic get_generation_status for Creative Director ids — the generic tool now returns the same scene data (it delegates here), but this one is the direct route.',
|
|
605
605
|
{
|
|
606
606
|
generation_id: z.string().describe('The Creative Director generation_id returned by generate_creative_director.'),
|
|
607
|
-
wait: z.boolean().optional().describe(`If true, block until the batch is terminal, for at most ~${WAIT_WINDOW_S}s per call. A batch that outlives one window comes back state="processing" (not an error) — call again with wait=true until it is terminal. Always prefer this over polling with wait=false.`)
|
|
607
|
+
wait: z.boolean().optional().describe(`If true, block until the batch is terminal, for at most ~${WAIT_WINDOW_S}s per call. A batch that outlives one window comes back state="processing" (not an error) — call again with wait=true until it is terminal. Always prefer this over polling with wait=false.`),
|
|
608
|
+
wait_seconds: z.number().min(1).max(180).optional().describe('Optional cap on one wait=true window, in seconds (default and maximum: the transport window). Interactive cards pass 45 so each call fits a host 60s request timeout.')
|
|
608
609
|
},
|
|
609
|
-
async ({ generation_id, wait }) => {
|
|
610
|
+
async ({ generation_id, wait, wait_seconds }) => {
|
|
610
611
|
const statusUrl = `/v1/generate/creative-director/${encodeURIComponent(generation_id)}/status`;
|
|
611
612
|
let status;
|
|
612
613
|
if (wait) {
|
|
613
614
|
try {
|
|
614
615
|
status = await pollUntilDone(client, generation_id, {
|
|
615
616
|
interval: 15000,
|
|
616
|
-
timeout: WAIT_WINDOW_MS,
|
|
617
|
+
timeout: wait_seconds ? Math.min(wait_seconds * 1000, WAIT_WINDOW_MS) : WAIT_WINDOW_MS,
|
|
617
618
|
statusUrl
|
|
618
619
|
});
|
|
619
620
|
} catch (err) {
|
|
@@ -1348,14 +1349,20 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1348
1349
|
{
|
|
1349
1350
|
generation_id: z.string().optional().describe('A single generation ID to check'),
|
|
1350
1351
|
generation_ids: z.array(z.string()).max(MAX_STATUS_IDS).optional().describe(`Multiple generation IDs to check in ONE call (max ${MAX_STATUS_IDS}). Returns { all_done, pending, generations[] } — always prefer this over checking IDs one by one.`),
|
|
1351
|
-
wait: z.boolean().optional().describe(`If true, block until every generation reaches a terminal state (completed/failed), for at most ~${WAIT_WINDOW_S}s per call, then return whatever state they are in. Anything still processing is reported, not errored — re-issue with wait=true and only the still-pending ids. This is always better than polling with wait=false.`)
|
|
1352
|
+
wait: z.boolean().optional().describe(`If true, block until every generation reaches a terminal state (completed/failed), for at most ~${WAIT_WINDOW_S}s per call, then return whatever state they are in. Anything still processing is reported, not errored — re-issue with wait=true and only the still-pending ids. This is always better than polling with wait=false.`),
|
|
1353
|
+
wait_seconds: z.number().min(1).max(180).optional().describe('Optional cap on one wait=true window, in seconds (default and maximum: the transport window). Interactive cards pass 45 so each call fits a host 60s request timeout.')
|
|
1352
1354
|
},
|
|
1353
|
-
async ({ generation_id, generation_ids, wait }) => {
|
|
1355
|
+
async ({ generation_id, generation_ids, wait, wait_seconds }) => {
|
|
1354
1356
|
const ids = (generation_ids && generation_ids.length > 0)
|
|
1355
1357
|
? [...new Set(generation_ids)]
|
|
1356
1358
|
: (generation_id ? [generation_id] : []);
|
|
1357
1359
|
if (ids.length === 0) throw new Error('Provide generation_id or generation_ids');
|
|
1358
1360
|
if (ids.length > MAX_STATUS_IDS) throw new Error(`At most ${MAX_STATUS_IDS} generation IDs can be checked at once.`);
|
|
1361
|
+
// Widget polls arrive through the host's iframe bridge, which (unlike the
|
|
1362
|
+
// model's own calls) need not reset its request timeout on our progress
|
|
1363
|
+
// ticks — a 180s stdio window there timed out every poll, stranding cards
|
|
1364
|
+
// on Generating and then "Tracking paused". Widgets pass wait_seconds.
|
|
1365
|
+
const windowMs = wait_seconds ? Math.min(wait_seconds * 1000, WAIT_WINDOW_MS) : WAIT_WINDOW_MS;
|
|
1359
1366
|
|
|
1360
1367
|
// One status check (or blocking poll) per id. Never let one bad id
|
|
1361
1368
|
// reject the whole batch — surface it as a failed entry instead.
|
|
@@ -1366,7 +1373,7 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1366
1373
|
// completion responsive without multiplying backend traffic for
|
|
1367
1374
|
// every card left open in a host conversation. The window itself is
|
|
1368
1375
|
// bounded by the transport — see WAIT_WINDOW_MS above.
|
|
1369
|
-
const result = await pollUntilDone(client, id, { interval: 15000, timeout:
|
|
1376
|
+
const result = await pollUntilDone(client, id, { interval: 15000, timeout: windowMs });
|
|
1370
1377
|
return { generation_id: id, ...result };
|
|
1371
1378
|
}
|
|
1372
1379
|
const result = await client.get(`/v1/generate/${encodeURIComponent(id)}/status`);
|
package/src/tools/presets.js
CHANGED
|
@@ -44,16 +44,17 @@ function registerPresetTools(server, client, options = {}) {
|
|
|
44
44
|
: 'Pass search next time if you already know the name. Pass the chosen exact id as preset_id.',
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
if (lookup) return { content: [{ type: 'text', text }] };
|
|
48
|
-
|
|
49
47
|
// TOOL_WIDGETS declares mediaGrid for this tool, so hosts that mount from
|
|
50
|
-
// the declaration (Claude desktop)
|
|
51
|
-
//
|
|
52
|
-
// the
|
|
48
|
+
// the declaration (Claude desktop) prepare a grid on EVERY call — the
|
|
49
|
+
// search lookup included. A text-only lookup left that grid guessing from
|
|
50
|
+
// the compact JSON: thumbnail-less file tiles under the UNFILTERED total.
|
|
51
|
+
// structuredContent also shadows the text on those hosts, so it carries
|
|
52
|
+
// the ids, total and note the agent needs.
|
|
53
|
+
const total = search && !result.search ? presets.length : (result.count || presets.length);
|
|
53
54
|
return uiResult(UI.mediaGrid, text, {
|
|
54
55
|
widget: 'mediaGrid',
|
|
55
56
|
title: 'Presets' + (type ? ' — ' + type : ''),
|
|
56
|
-
items: presets.slice(0, 300).map(p => ({
|
|
57
|
+
items: presets.slice(0, lookup ? 8 : 300).map(p => ({
|
|
57
58
|
id: p.id,
|
|
58
59
|
title: p.name,
|
|
59
60
|
subtitle: p.category,
|
|
@@ -63,8 +64,10 @@ function registerPresetTools(server, client, options = {}) {
|
|
|
63
64
|
url: p.thumbnail_url || p.thumbnail,
|
|
64
65
|
use_hint: 'Use preset "{TITLE}" (preset_id: {ID}) for my next generation — ask me for the prompt.'
|
|
65
66
|
})),
|
|
66
|
-
total
|
|
67
|
-
has_more: presets.length > 300
|
|
67
|
+
total,
|
|
68
|
+
has_more: presets.length > (lookup ? 8 : 300),
|
|
69
|
+
...(lookup ? { _lookup: true, note: 'Pick the closest id and pass it as preset_id.' } : {}),
|
|
70
|
+
...(result.warning ? { warning: result.warning } : {}),
|
|
68
71
|
});
|
|
69
72
|
}
|
|
70
73
|
);
|