@kolbo/mcp 1.84.1 → 1.84.2
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/index.js +11 -0
- package/src/apps/widgets/mediaGrid.js +48 -11
- package/src/tools/_shared.js +12 -0
- package/src/tools/generate.js +8 -0
- package/src/tools/media.js +11 -1
package/package.json
CHANGED
package/src/apps/index.js
CHANGED
|
@@ -88,6 +88,17 @@ const WIDGET_CSP = {
|
|
|
88
88
|
'https://assets.sketchfab.com',
|
|
89
89
|
'https://sketchfab-prod-media.s3.amazonaws.com',
|
|
90
90
|
|
|
91
|
+
// Voice PREVIEW audio hosts. list_voices ships every voice with a
|
|
92
|
+
// preview_url and the card renders a real <audio> for it, but 150 of the
|
|
93
|
+
// 864 production voices store that preview on a provider host rather than a
|
|
94
|
+
// Kolbo bucket: 138 google voices on storage.googleapis.com and 12 on
|
|
95
|
+
// api.us.elevenlabs.io. media-src blocked both, so every google voice — the
|
|
96
|
+
// entire Hebrew set — rendered a player stuck at 0:00 / 0:00 with no error
|
|
97
|
+
// anywhere. The Spaces-hosted previews come free via HOST_MAP above; these
|
|
98
|
+
// two do not, because they are not ours.
|
|
99
|
+
'https://storage.googleapis.com',
|
|
100
|
+
'https://api.us.elevenlabs.io',
|
|
101
|
+
|
|
91
102
|
// Default SYNCI catalog project. Any production override must be reviewed
|
|
92
103
|
// and added here as an exact hostname before deployment.
|
|
93
104
|
'https://gfbpxdkripkbbrcvoyeh.supabase.co',
|
|
@@ -48,17 +48,17 @@ function boot(sc) {
|
|
|
48
48
|
var audioItems = sc.items.filter(function (i) { return i.media_type === 'audio'; });
|
|
49
49
|
var visualItems = sc.items.filter(function (i) { return i.media_type !== 'audio'; });
|
|
50
50
|
var h = '';
|
|
51
|
+
// Render everything currently in state — each PAGE is already capped
|
|
52
|
+
// server-side (GRID_CAP), so this grows one page per Load more instead of
|
|
53
|
+
// being pinned forever. The old hard slices (24 visual / 12 audio) meant an
|
|
54
|
+
// appended page could never actually appear, and the count below tallied all
|
|
55
|
+
// items while only 36 were drawn, so the button also lied about the total.
|
|
51
56
|
if (visualItems.length) {
|
|
52
|
-
h += '<div class="k-grid">' + visualItems.
|
|
57
|
+
h += '<div class="k-grid">' + visualItems.map(cellHTML).join('') + '</div>';
|
|
53
58
|
}
|
|
54
59
|
if (audioItems.length) {
|
|
55
|
-
h += audioItems.
|
|
60
|
+
h += audioItems.map(audioRowHTML).join('');
|
|
56
61
|
}
|
|
57
|
-
// Only a fixed page ever renders here (24 visual + 12 audio) — with a library
|
|
58
|
-
// in the thousands there was no way to reach the rest short of asking in
|
|
59
|
-
// chat. A visible "Load more" turns that into one click; it sends a message
|
|
60
|
-
// rather than calling the tool directly, since the widget has no host API
|
|
61
|
-
// to invoke a tool itself — same mechanism every other "Use" action here uses.
|
|
62
62
|
var shown = visualItems.length + audioItems.length;
|
|
63
63
|
if (sc.total != null && sc.total > shown) {
|
|
64
64
|
h += '<button class="k-btn" id="load-more" style="width:100%;margin-top:10px">Load more (' +
|
|
@@ -145,13 +145,50 @@ function wire() {
|
|
|
145
145
|
});
|
|
146
146
|
var loadMore = el('load-more');
|
|
147
147
|
if (loadMore) {
|
|
148
|
-
loadMore.onclick = function () {
|
|
149
|
-
window.kolbo.sendMessage('Show me the next page of this same media search (already saw ' +
|
|
150
|
-
(state.items.length) + ' of ' + state.total + ' results).');
|
|
151
|
-
};
|
|
148
|
+
loadMore.onclick = function () { fetchNextPage(loadMore); };
|
|
152
149
|
}
|
|
153
150
|
}
|
|
154
151
|
|
|
152
|
+
// Fetch the next page IN the widget and append it.
|
|
153
|
+
//
|
|
154
|
+
// This used to sendMessage() a request for "the next page of this same media
|
|
155
|
+
// search", on the stated belief that a widget has no way to invoke a tool. It
|
|
156
|
+
// does — window.kolbo.callTool, the same bridge call every generation card
|
|
157
|
+
// polls status with. And the message could not have worked anyway: the payload
|
|
158
|
+
// carried no page number and none of the filters, so the model had nothing to
|
|
159
|
+
// reconstruct the query from and would re-run page 1 or something else. The
|
|
160
|
+
// button appeared to do nothing.
|
|
161
|
+
function fetchNextPage(btn) {
|
|
162
|
+
if (!state || !state.page_tool || btn.disabled) return;
|
|
163
|
+
var next = (state.page || 1) + 1;
|
|
164
|
+
btn.disabled = true;
|
|
165
|
+
var label = btn.textContent;
|
|
166
|
+
btn.innerHTML = '<span class="k-spin"></span> Loading';
|
|
167
|
+
var args = {};
|
|
168
|
+
var q = state.query || {};
|
|
169
|
+
for (var k in q) { if (q[k] !== undefined && q[k] !== null && q[k] !== '') args[k] = q[k]; }
|
|
170
|
+
args.page = next;
|
|
171
|
+
if (state.page_size) args.page_size = state.page_size;
|
|
172
|
+
|
|
173
|
+
window.kolbo.callTool(state.page_tool, args).then(function (res) {
|
|
174
|
+
var sc = structured(res);
|
|
175
|
+
var more = (sc && sc.items) || [];
|
|
176
|
+
if (!more.length) {
|
|
177
|
+
// Nothing came back: say so rather than restoring a button that still
|
|
178
|
+
// looks like it has pages behind it.
|
|
179
|
+
btn.textContent = 'No more results';
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
state.items = (state.items || []).concat(more);
|
|
183
|
+
state.page = (sc && sc.page) || next;
|
|
184
|
+
if (sc && sc.total != null) state.total = sc.total;
|
|
185
|
+
boot(state); // re-renders the grid + a fresh Load more button
|
|
186
|
+
}).catch(function () {
|
|
187
|
+
btn.disabled = false;
|
|
188
|
+
btn.textContent = label;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
155
192
|
function useItem(i) {
|
|
156
193
|
var item = state.items[i];
|
|
157
194
|
if (!item || !item.id) return;
|
package/src/tools/_shared.js
CHANGED
|
@@ -851,6 +851,18 @@ async function uiCompleted(p, textPayload, extraContent) {
|
|
|
851
851
|
// above which assume everything finished together. Only set when the
|
|
852
852
|
// caller actually has this shape; every existing caller is unaffected.
|
|
853
853
|
...(Array.isArray(p.items) ? { items: p.items } : {}),
|
|
854
|
+
// Transcription payload. get_generation_status is the ONLY way the live
|
|
855
|
+
// transcript widget learns its result, and it reads text/srt_url/txt_url off
|
|
856
|
+
// this object — but uiCompleted is shaped for the generation card and
|
|
857
|
+
// dropped every one, so a finished transcription rendered "(empty
|
|
858
|
+
// transcript)" with no SRT/TXT buttons while the text sat in the status
|
|
859
|
+
// response. structuredContent SHADOWS the text block on widget hosts, so
|
|
860
|
+
// omitting a field here is the same as deleting it.
|
|
861
|
+
...(typeof p.text === 'string' ? { text: p.text } : {}),
|
|
862
|
+
...(p.srt_url ? { srt_url: p.srt_url } : {}),
|
|
863
|
+
...(p.word_by_word_srt_url ? { word_by_word_srt_url: p.word_by_word_srt_url } : {}),
|
|
864
|
+
...(p.txt_url ? { txt_url: p.txt_url } : {}),
|
|
865
|
+
...(p.audio_url ? { audio_url: p.audio_url } : {}),
|
|
854
866
|
// The voice, by name and portrait. uiGenerating has carried this since the
|
|
855
867
|
// chips were introduced; uiCompleted never did, so it silently dropped a
|
|
856
868
|
// resolved voice its caller had already looked up — every FINISHED speech
|
package/src/tools/generate.js
CHANGED
|
@@ -1118,6 +1118,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1118
1118
|
state: single.state,
|
|
1119
1119
|
urls: done ? urls : undefined,
|
|
1120
1120
|
thumbnail_url: res.thumbnail_url,
|
|
1121
|
+
// Transcription results ride the same status tool as media
|
|
1122
|
+
// generations; without these the transcript widget merges a payload
|
|
1123
|
+
// with no transcript in it and renders "(empty transcript)".
|
|
1124
|
+
text: typeof res.text === 'string' ? res.text : undefined,
|
|
1125
|
+
srt_url: res.srt_url || undefined,
|
|
1126
|
+
word_by_word_srt_url: res.word_by_word_srt_url || undefined,
|
|
1127
|
+
txt_url: res.txt_url || undefined,
|
|
1128
|
+
audio_url: res.audio_url || undefined,
|
|
1121
1129
|
// The refs the server actually conditioned on (reference_details) —
|
|
1122
1130
|
// the live card merges this payload over its submit-time state, so
|
|
1123
1131
|
// the finished card shows every reference, including server-side
|
package/src/tools/media.js
CHANGED
|
@@ -303,7 +303,17 @@ function registerMediaTools(server, client, options = {}) {
|
|
|
303
303
|
title: 'Media Library',
|
|
304
304
|
items,
|
|
305
305
|
total: totalItems != null ? totalItems : media.length,
|
|
306
|
-
shown: Math.min(media.length, GRID_CAP)
|
|
306
|
+
shown: Math.min(media.length, GRID_CAP),
|
|
307
|
+
// Everything "Load more" needs to fetch page N+1 ITSELF. The button used
|
|
308
|
+
// to send a chat message asking the model to run the next page, on the
|
|
309
|
+
// belief that a widget cannot invoke a tool — it can
|
|
310
|
+
// (window.kolbo.callTool, the same call every generation card polls
|
|
311
|
+
// with). Worse, the payload carried no page and no filters, so the model
|
|
312
|
+
// could not reconstruct the query either and typically re-ran page 1.
|
|
313
|
+
page_tool: 'list_media',
|
|
314
|
+
page: page || 1,
|
|
315
|
+
page_size: page_size || 50,
|
|
316
|
+
query: { project_id, folder_id, type, category, source_type, sort, search }
|
|
307
317
|
});
|
|
308
318
|
}
|
|
309
319
|
);
|