@clipform/mcp-server 1.47.1 → 1.48.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/dist/{chunk-JT7YWEQP.js → chunk-3MTEM3VC.js} +384 -45
- package/dist/{chunk-JT7YWEQP.js.map → chunk-3MTEM3VC.js.map} +1 -1
- package/dist/{chunk-PJNOCHKR.js → chunk-4CY5EJCR.js} +8 -1
- package/dist/{chunk-PJNOCHKR.js.map → chunk-4CY5EJCR.js.map} +1 -1
- package/dist/{chunk-MV27JVSL.js → chunk-BBNREY2Q.js} +2 -2
- package/dist/{chunk-UH77CDNO.js → chunk-WUORO245.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/prompts.js +2 -2
- package/dist/resources.js +2 -2
- package/dist/server.js +4 -4
- package/package.json +1 -1
- /package/dist/{chunk-MV27JVSL.js.map → chunk-BBNREY2Q.js.map} +0 -0
- /package/dist/{chunk-UH77CDNO.js.map → chunk-WUORO245.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getWorkflowText,
|
|
7
7
|
objectType,
|
|
8
8
|
registerPrompts
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BBNREY2Q.js";
|
|
10
10
|
import {
|
|
11
11
|
GUIDE_TYPES,
|
|
12
12
|
QUIZ_VARIANTS,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getGuideUri,
|
|
15
15
|
guideFallbackText,
|
|
16
16
|
registerResources
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-WUORO245.js";
|
|
18
18
|
import {
|
|
19
19
|
ACTIVE_NODE_TYPES,
|
|
20
20
|
BUSINESS,
|
|
@@ -33,8 +33,9 @@ import {
|
|
|
33
33
|
callApi,
|
|
34
34
|
errorResult,
|
|
35
35
|
resolveFormType,
|
|
36
|
+
structuredResult,
|
|
36
37
|
textResult
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-4CY5EJCR.js";
|
|
38
39
|
import {
|
|
39
40
|
__commonJS,
|
|
40
41
|
__export,
|
|
@@ -17325,6 +17326,21 @@ function registerListFormsTool(server) {
|
|
|
17325
17326
|
sort: external_exports.enum(["created_at", "updated_at"]).optional().describe("Sort field (default: created_at)"),
|
|
17326
17327
|
order: external_exports.enum(["asc", "desc"]).optional().describe("Sort order (default: desc, newest first)")
|
|
17327
17328
|
},
|
|
17329
|
+
outputSchema: {
|
|
17330
|
+
forms: external_exports.array(
|
|
17331
|
+
external_exports.object({
|
|
17332
|
+
id: external_exports.string(),
|
|
17333
|
+
title: external_exports.string(),
|
|
17334
|
+
share_id: external_exports.string(),
|
|
17335
|
+
is_live: external_exports.boolean(),
|
|
17336
|
+
has_unpublished_changes: external_exports.boolean(),
|
|
17337
|
+
created_at: external_exports.string(),
|
|
17338
|
+
updated_at: external_exports.string(),
|
|
17339
|
+
tags: external_exports.array(external_exports.object({ id: external_exports.string(), name: external_exports.string(), color: external_exports.string().nullable() }))
|
|
17340
|
+
})
|
|
17341
|
+
).describe("Matching forms (empty if none)"),
|
|
17342
|
+
next_cursor: external_exports.string().nullable().describe("Pass as cursor to fetch the next page, or null when no more")
|
|
17343
|
+
},
|
|
17328
17344
|
annotations: {
|
|
17329
17345
|
readOnlyHint: true,
|
|
17330
17346
|
destructiveHint: false,
|
|
@@ -17346,8 +17362,21 @@ function registerListFormsTool(server) {
|
|
|
17346
17362
|
return errorResult(result.error);
|
|
17347
17363
|
}
|
|
17348
17364
|
const data = result.data;
|
|
17365
|
+
const structured = {
|
|
17366
|
+
forms: data.forms.map((f) => ({
|
|
17367
|
+
id: f.id,
|
|
17368
|
+
title: f.title,
|
|
17369
|
+
share_id: f.share_id,
|
|
17370
|
+
is_live: f.is_live,
|
|
17371
|
+
has_unpublished_changes: f.has_unpublished_changes,
|
|
17372
|
+
created_at: f.created_at,
|
|
17373
|
+
updated_at: f.updated_at,
|
|
17374
|
+
tags: f.tags.map((t) => ({ id: t.id, name: t.name, color: t.color }))
|
|
17375
|
+
})),
|
|
17376
|
+
next_cursor: data.next_cursor
|
|
17377
|
+
};
|
|
17349
17378
|
if (data.forms.length === 0) {
|
|
17350
|
-
return
|
|
17379
|
+
return structuredResult("No forms found matching the criteria.", structured);
|
|
17351
17380
|
}
|
|
17352
17381
|
const lines = [`Found ${data.forms.length} form(s):
|
|
17353
17382
|
`];
|
|
@@ -17361,14 +17390,36 @@ function registerListFormsTool(server) {
|
|
|
17361
17390
|
`More results available. Pass cursor: "${data.next_cursor}" to get the next page.`
|
|
17362
17391
|
);
|
|
17363
17392
|
}
|
|
17364
|
-
return
|
|
17393
|
+
return structuredResult(lines.join("\n"), structured);
|
|
17365
17394
|
}
|
|
17366
17395
|
);
|
|
17367
17396
|
}
|
|
17368
17397
|
|
|
17369
17398
|
// src/lib/format-form.ts
|
|
17399
|
+
function getFormNodes(data) {
|
|
17400
|
+
return data.node ?? data.nodes ?? [];
|
|
17401
|
+
}
|
|
17402
|
+
function projectFormState(data) {
|
|
17403
|
+
return {
|
|
17404
|
+
form_id: String(data.form_id ?? ""),
|
|
17405
|
+
title: String(data.title ?? ""),
|
|
17406
|
+
is_live: Boolean(data.is_live),
|
|
17407
|
+
has_unpublished_changes: Boolean(data.has_unpublished_changes),
|
|
17408
|
+
nodes: getFormNodes(data).map((q) => {
|
|
17409
|
+
const options = q.node_options ?? q.options;
|
|
17410
|
+
return {
|
|
17411
|
+
id: q.id,
|
|
17412
|
+
type: q.type,
|
|
17413
|
+
prompt: q.prompt ?? "",
|
|
17414
|
+
required: Boolean(q.required),
|
|
17415
|
+
...q.config && Object.keys(q.config).length > 0 ? { config: q.config } : {},
|
|
17416
|
+
...options && options.length > 0 ? { options: options.map((o) => ({ id: o.id, content: o.content })) } : {}
|
|
17417
|
+
};
|
|
17418
|
+
})
|
|
17419
|
+
};
|
|
17420
|
+
}
|
|
17370
17421
|
function formatFormState(data) {
|
|
17371
|
-
const nodes = data
|
|
17422
|
+
const nodes = getFormNodes(data);
|
|
17372
17423
|
const lines = [
|
|
17373
17424
|
`Form: ${data.title}`,
|
|
17374
17425
|
`Form ID: ${data.form_id}`,
|
|
@@ -17408,6 +17459,22 @@ function registerGetFormTool(server) {
|
|
|
17408
17459
|
inputSchema: {
|
|
17409
17460
|
form_id: external_exports.string().uuid().describe("The form UUID (returned by clipform_create_form, not the short share_id from the URL)")
|
|
17410
17461
|
},
|
|
17462
|
+
outputSchema: {
|
|
17463
|
+
form_id: external_exports.string().describe("Form UUID"),
|
|
17464
|
+
title: external_exports.string().describe("Form title"),
|
|
17465
|
+
is_live: external_exports.boolean().describe("Whether the form is published"),
|
|
17466
|
+
has_unpublished_changes: external_exports.boolean().describe("Live form has edits not yet republished"),
|
|
17467
|
+
nodes: external_exports.array(
|
|
17468
|
+
external_exports.object({
|
|
17469
|
+
id: external_exports.string(),
|
|
17470
|
+
type: external_exports.string(),
|
|
17471
|
+
prompt: external_exports.string(),
|
|
17472
|
+
required: external_exports.boolean(),
|
|
17473
|
+
config: external_exports.record(external_exports.unknown()).optional(),
|
|
17474
|
+
options: external_exports.array(external_exports.object({ id: external_exports.string(), content: external_exports.string() })).optional()
|
|
17475
|
+
})
|
|
17476
|
+
).describe("Nodes in sequential order - IDs for update_node / upload_node_media")
|
|
17477
|
+
},
|
|
17411
17478
|
annotations: {
|
|
17412
17479
|
readOnlyHint: true,
|
|
17413
17480
|
destructiveHint: false,
|
|
@@ -17420,7 +17487,7 @@ function registerGetFormTool(server) {
|
|
|
17420
17487
|
if (!result.ok) {
|
|
17421
17488
|
return errorResult(result.error);
|
|
17422
17489
|
}
|
|
17423
|
-
return
|
|
17490
|
+
return structuredResult(formatFormState(result.data), projectFormState(result.data));
|
|
17424
17491
|
}
|
|
17425
17492
|
);
|
|
17426
17493
|
}
|
|
@@ -17597,6 +17664,10 @@ function registerAddNodeTool(server) {
|
|
|
17597
17664
|
"Insert after this node ID. Omit to append before the end screen."
|
|
17598
17665
|
)
|
|
17599
17666
|
},
|
|
17667
|
+
outputSchema: {
|
|
17668
|
+
node_id: external_exports.string().describe("ID of the created node - pass to update_node / upload_node_media"),
|
|
17669
|
+
type: external_exports.string().describe("Node type that was added")
|
|
17670
|
+
},
|
|
17600
17671
|
annotations: {
|
|
17601
17672
|
readOnlyHint: false,
|
|
17602
17673
|
destructiveHint: false,
|
|
@@ -17615,8 +17686,10 @@ function registerAddNodeTool(server) {
|
|
|
17615
17686
|
if (!result.ok) {
|
|
17616
17687
|
return errorResult(result.error);
|
|
17617
17688
|
}
|
|
17618
|
-
|
|
17619
|
-
|
|
17689
|
+
const nodeId = result.data.node_id;
|
|
17690
|
+
return structuredResult(
|
|
17691
|
+
`Node added. ID: ${nodeId} | Type: ${node.type}`,
|
|
17692
|
+
{ node_id: nodeId, type: node.type }
|
|
17620
17693
|
);
|
|
17621
17694
|
}
|
|
17622
17695
|
);
|
|
@@ -17644,6 +17717,16 @@ function registerUpdateNodeTool(server) {
|
|
|
17644
17717
|
form_id: external_exports.string().uuid().describe("The form UUID (returned by clipform_create_form, not the short share_id from the URL)"),
|
|
17645
17718
|
updates: external_exports.array(NodeUpdateSchema).min(1).max(20).describe("One or more node updates to apply")
|
|
17646
17719
|
},
|
|
17720
|
+
outputSchema: {
|
|
17721
|
+
results: external_exports.array(
|
|
17722
|
+
external_exports.object({
|
|
17723
|
+
node_id: external_exports.string(),
|
|
17724
|
+
ok: external_exports.boolean(),
|
|
17725
|
+
warnings: external_exports.array(external_exports.string()).optional(),
|
|
17726
|
+
error: external_exports.string().optional()
|
|
17727
|
+
})
|
|
17728
|
+
).describe("One result per requested update, in order")
|
|
17729
|
+
},
|
|
17647
17730
|
annotations: {
|
|
17648
17731
|
readOnlyHint: false,
|
|
17649
17732
|
destructiveHint: false,
|
|
@@ -17653,6 +17736,7 @@ function registerUpdateNodeTool(server) {
|
|
|
17653
17736
|
},
|
|
17654
17737
|
async ({ form_id, updates }) => {
|
|
17655
17738
|
const allLines = [];
|
|
17739
|
+
const results = [];
|
|
17656
17740
|
for (const { node_id, prompt, label, type, required: required2, config: config2, options } of updates) {
|
|
17657
17741
|
const body = {};
|
|
17658
17742
|
if (prompt !== void 0) body.prompt = prompt;
|
|
@@ -17667,6 +17751,7 @@ function registerUpdateNodeTool(server) {
|
|
|
17667
17751
|
);
|
|
17668
17752
|
if (!result.ok) {
|
|
17669
17753
|
allLines.push(`Node ${node_id}: FAILED \u2014 ${result.error}`);
|
|
17754
|
+
results.push({ node_id, ok: false, error: result.error });
|
|
17670
17755
|
continue;
|
|
17671
17756
|
}
|
|
17672
17757
|
const changes = [];
|
|
@@ -17682,8 +17767,9 @@ function registerUpdateNodeTool(server) {
|
|
|
17682
17767
|
if (warnings?.length) {
|
|
17683
17768
|
for (const w of warnings) allLines.push(`Node ${node_id} warning: ${w}`);
|
|
17684
17769
|
}
|
|
17770
|
+
results.push({ node_id, ok: true, ...warnings?.length ? { warnings } : {} });
|
|
17685
17771
|
}
|
|
17686
|
-
return
|
|
17772
|
+
return structuredResult(allLines.join("\n"), { results });
|
|
17687
17773
|
}
|
|
17688
17774
|
);
|
|
17689
17775
|
}
|
|
@@ -17764,6 +17850,18 @@ When a public URL is provided, the media is fetched and stored automatically. On
|
|
|
17764
17850
|
form_id: external_exports.string().uuid().describe("The form UUID (returned by clipform_create_form, not the short share_id from the URL)"),
|
|
17765
17851
|
items: external_exports.array(MediaItemSchema).min(1).max(10).describe("One or more media items to upload")
|
|
17766
17852
|
},
|
|
17853
|
+
outputSchema: {
|
|
17854
|
+
results: external_exports.array(
|
|
17855
|
+
external_exports.object({
|
|
17856
|
+
node_id: external_exports.string(),
|
|
17857
|
+
ok: external_exports.boolean(),
|
|
17858
|
+
stored: external_exports.boolean().describe("Bytes already stored (URL-based); false when an upload_url is pending"),
|
|
17859
|
+
upload_url: external_exports.string().optional(),
|
|
17860
|
+
upload_method: external_exports.string().optional(),
|
|
17861
|
+
error: external_exports.string().optional()
|
|
17862
|
+
})
|
|
17863
|
+
).describe("One result per item, in order")
|
|
17864
|
+
},
|
|
17767
17865
|
annotations: {
|
|
17768
17866
|
readOnlyHint: false,
|
|
17769
17867
|
destructiveHint: false,
|
|
@@ -17774,15 +17872,16 @@ When a public URL is provided, the media is fetched and stored automatically. On
|
|
|
17774
17872
|
async ({ form_id, items }) => {
|
|
17775
17873
|
const workspaceId = getMcpAuth()?.workspace_id;
|
|
17776
17874
|
const lines = [];
|
|
17875
|
+
const results = [];
|
|
17777
17876
|
let successCount = 0;
|
|
17778
17877
|
for (let i = 0; i < items.length; i++) {
|
|
17779
17878
|
const item = items[i];
|
|
17780
17879
|
if (items.length > 1) lines.push(`--- Item ${i + 1} (node ${item.node_id}) ---`);
|
|
17781
17880
|
if (!workspaceId) {
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
);
|
|
17881
|
+
const error2 = "no workspace in context - reconnect the MCP or set CLIPFORM_API_KEY so media can land in your library.";
|
|
17882
|
+
lines.push(`FAILED: ${error2}`);
|
|
17785
17883
|
lines.push("");
|
|
17884
|
+
results.push({ node_id: item.node_id, ok: false, stored: false, error: error2 });
|
|
17786
17885
|
continue;
|
|
17787
17886
|
}
|
|
17788
17887
|
const createBody = {
|
|
@@ -17795,12 +17894,15 @@ When a public URL is provided, the media is fetched and stored automatically. On
|
|
|
17795
17894
|
if (!created.ok) {
|
|
17796
17895
|
lines.push(`FAILED: ${created.error}`);
|
|
17797
17896
|
lines.push("");
|
|
17897
|
+
results.push({ node_id: item.node_id, ok: false, stored: false, error: created.error });
|
|
17798
17898
|
continue;
|
|
17799
17899
|
}
|
|
17800
17900
|
const mediaAssetId = created.data.media_asset_id;
|
|
17801
17901
|
if (!mediaAssetId) {
|
|
17802
|
-
|
|
17902
|
+
const error2 = `upload did not return a media asset id (route ${String(created.data.route ?? "unknown")}).`;
|
|
17903
|
+
lines.push(`FAILED: ${error2}`);
|
|
17803
17904
|
lines.push("");
|
|
17905
|
+
results.push({ node_id: item.node_id, ok: false, stored: false, error: error2 });
|
|
17804
17906
|
continue;
|
|
17805
17907
|
}
|
|
17806
17908
|
const attached = await callApi(`/forms/${form_id}/nodes/${item.node_id}/media/attach`, {
|
|
@@ -17810,6 +17912,7 @@ When a public URL is provided, the media is fetched and stored automatically. On
|
|
|
17810
17912
|
if (!attached.ok) {
|
|
17811
17913
|
lines.push(`FAILED to attach the uploaded media to the node: ${attached.error}`);
|
|
17812
17914
|
lines.push("");
|
|
17915
|
+
results.push({ node_id: item.node_id, ok: false, stored: false, error: attached.error });
|
|
17813
17916
|
continue;
|
|
17814
17917
|
}
|
|
17815
17918
|
const presentation = {};
|
|
@@ -17826,6 +17929,15 @@ When a public URL is provided, the media is fetched and stored automatically. On
|
|
|
17826
17929
|
}
|
|
17827
17930
|
}
|
|
17828
17931
|
successCount++;
|
|
17932
|
+
const uploadUrl = created.data.upload_url;
|
|
17933
|
+
const uploadMethod = created.data.upload_method;
|
|
17934
|
+
results.push({
|
|
17935
|
+
node_id: item.node_id,
|
|
17936
|
+
ok: true,
|
|
17937
|
+
stored: !uploadUrl,
|
|
17938
|
+
...uploadUrl ? { upload_url: uploadUrl } : {},
|
|
17939
|
+
...uploadUrl && uploadMethod ? { upload_method: uploadMethod } : {}
|
|
17940
|
+
});
|
|
17829
17941
|
const resultLines = [];
|
|
17830
17942
|
if (created.data.upload_url) {
|
|
17831
17943
|
resultLines.push(
|
|
@@ -17848,7 +17960,7 @@ When a public URL is provided, the media is fetched and stored automatically. On
|
|
|
17848
17960
|
`);
|
|
17849
17961
|
}
|
|
17850
17962
|
if (successCount === 0) return errorResult(lines.join("\n"));
|
|
17851
|
-
return
|
|
17963
|
+
return structuredResult(lines.join("\n"), { results });
|
|
17852
17964
|
}
|
|
17853
17965
|
);
|
|
17854
17966
|
}
|
|
@@ -17864,6 +17976,14 @@ function registerGetNodeMediaTool(server) {
|
|
|
17864
17976
|
form_id: external_exports.string().uuid().describe("The form UUID (returned by clipform_create_form, not the short share_id from the URL)"),
|
|
17865
17977
|
node_id: external_exports.string().describe("The node ID")
|
|
17866
17978
|
},
|
|
17979
|
+
outputSchema: {
|
|
17980
|
+
media: external_exports.object({
|
|
17981
|
+
media_type: external_exports.string(),
|
|
17982
|
+
status: external_exports.string(),
|
|
17983
|
+
duration: external_exports.number().optional(),
|
|
17984
|
+
transcription_status: external_exports.string().nullable().optional()
|
|
17985
|
+
}).nullable().describe("Attached media (null if the node has none)")
|
|
17986
|
+
},
|
|
17867
17987
|
annotations: {
|
|
17868
17988
|
readOnlyHint: true,
|
|
17869
17989
|
destructiveHint: false,
|
|
@@ -17880,15 +18000,22 @@ function registerGetNodeMediaTool(server) {
|
|
|
17880
18000
|
}
|
|
17881
18001
|
const media = result.data.media;
|
|
17882
18002
|
if (!media) {
|
|
17883
|
-
return
|
|
18003
|
+
return structuredResult("No media attached to this node.", { media: null });
|
|
17884
18004
|
}
|
|
17885
|
-
|
|
18005
|
+
const projected = {
|
|
18006
|
+
media_type: String(media.media_type),
|
|
18007
|
+
status: String(media.status),
|
|
18008
|
+
...typeof media.duration === "number" ? { duration: media.duration } : {},
|
|
18009
|
+
transcription_status: media.transcription_status == null ? null : String(media.transcription_status)
|
|
18010
|
+
};
|
|
18011
|
+
return structuredResult(
|
|
17886
18012
|
[
|
|
17887
18013
|
`Type: ${media.media_type}`,
|
|
17888
18014
|
`Status: ${media.status}`,
|
|
17889
18015
|
media.duration ? `Duration: ${media.duration}s` : "",
|
|
17890
18016
|
`Transcription: ${media.transcription_status}`
|
|
17891
|
-
].filter(Boolean).join("\n")
|
|
18017
|
+
].filter(Boolean).join("\n"),
|
|
18018
|
+
{ media: projected }
|
|
17892
18019
|
);
|
|
17893
18020
|
}
|
|
17894
18021
|
);
|
|
@@ -18042,6 +18169,20 @@ Returns: article title, source, author, date, URL, description, and image URL pe
|
|
|
18042
18169
|
query: external_exports.string().describe("News search query (e.g. 'Iran war 2026', 'Australian Open final', 'UK election')"),
|
|
18043
18170
|
count: external_exports.number().min(1).max(15).default(5).optional().describe("Max results per provider (default 5)")
|
|
18044
18171
|
},
|
|
18172
|
+
outputSchema: {
|
|
18173
|
+
query: external_exports.string(),
|
|
18174
|
+
articles: external_exports.array(
|
|
18175
|
+
external_exports.object({
|
|
18176
|
+
title: external_exports.string().optional(),
|
|
18177
|
+
source: external_exports.string().optional(),
|
|
18178
|
+
description: external_exports.string().optional(),
|
|
18179
|
+
author: external_exports.string().optional(),
|
|
18180
|
+
published_at: external_exports.string().optional(),
|
|
18181
|
+
url: external_exports.string(),
|
|
18182
|
+
image_url: external_exports.string().optional()
|
|
18183
|
+
})
|
|
18184
|
+
).describe("Matching articles (empty if none)")
|
|
18185
|
+
},
|
|
18045
18186
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
18046
18187
|
},
|
|
18047
18188
|
async ({ query, count }) => {
|
|
@@ -18050,7 +18191,16 @@ Returns: article title, source, author, date, URL, description, and image URL pe
|
|
|
18050
18191
|
});
|
|
18051
18192
|
if (!result.ok) return errorResult(result.error);
|
|
18052
18193
|
const results = result.data.results;
|
|
18053
|
-
if (!results.length) return
|
|
18194
|
+
if (!results.length) return structuredResult(`No news articles found for "${query}".`, { query, articles: [] });
|
|
18195
|
+
const articles = results.map((article) => ({
|
|
18196
|
+
...article.title ? { title: article.title } : {},
|
|
18197
|
+
...article.source ? { source: article.source } : {},
|
|
18198
|
+
...article.description ? { description: article.description } : {},
|
|
18199
|
+
...article.author ? { author: article.author } : {},
|
|
18200
|
+
...article.publishedAt ? { published_at: article.publishedAt } : {},
|
|
18201
|
+
url: article.url,
|
|
18202
|
+
...article.imageUrl ? { image_url: article.imageUrl } : {}
|
|
18203
|
+
}));
|
|
18054
18204
|
const lines = [`Found ${results.length} articles for "${query}":
|
|
18055
18205
|
`];
|
|
18056
18206
|
for (const article of results) {
|
|
@@ -18062,7 +18212,7 @@ Returns: article title, source, author, date, URL, description, and image URL pe
|
|
|
18062
18212
|
if (article.imageUrl) lines.push(` Image: ${article.imageUrl}`);
|
|
18063
18213
|
lines.push("");
|
|
18064
18214
|
}
|
|
18065
|
-
return
|
|
18215
|
+
return structuredResult(lines.join("\n"), { query, articles });
|
|
18066
18216
|
}
|
|
18067
18217
|
);
|
|
18068
18218
|
}
|
|
@@ -18118,6 +18268,12 @@ Supports any public YouTube video with captions enabled. Does NOT work for priva
|
|
|
18118
18268
|
}
|
|
18119
18269
|
|
|
18120
18270
|
// src/tools/generate-tts.ts
|
|
18271
|
+
var CaptionSchema = external_exports.object({
|
|
18272
|
+
start: external_exports.number(),
|
|
18273
|
+
end: external_exports.number(),
|
|
18274
|
+
text: external_exports.string(),
|
|
18275
|
+
words: external_exports.array(external_exports.object({ word: external_exports.string(), start: external_exports.number(), end: external_exports.number() })).optional()
|
|
18276
|
+
});
|
|
18121
18277
|
var TtsItemSchema = external_exports.object({
|
|
18122
18278
|
text: external_exports.string().min(1).max(5e3).describe("Narration text"),
|
|
18123
18279
|
voice: external_exports.enum(["ryan", "sonia", "andrew", "ava", "guy"]).optional().default("ryan").describe("Voice: ryan (British male, clear/articulate), sonia (British female, warm/bright), andrew (American male, smooth/neutral), ava (American female, vibrant/friendly), guy (American male, deep/authoritative). Pick based on the form's topic and audience."),
|
|
@@ -18138,6 +18294,16 @@ Pass one item or many (max 10) - multiple items run in parallel. Returns audio U
|
|
|
18138
18294
|
inputSchema: {
|
|
18139
18295
|
items: external_exports.array(TtsItemSchema).min(1).max(10).describe("One or more TTS items to generate")
|
|
18140
18296
|
},
|
|
18297
|
+
outputSchema: {
|
|
18298
|
+
results: external_exports.array(
|
|
18299
|
+
external_exports.object({
|
|
18300
|
+
ok: external_exports.boolean(),
|
|
18301
|
+
audio_url: external_exports.string().optional(),
|
|
18302
|
+
captions: external_exports.array(CaptionSchema).optional().describe("Pass as the captions param to upload_node_media"),
|
|
18303
|
+
error: external_exports.string().optional()
|
|
18304
|
+
})
|
|
18305
|
+
).describe("One result per item, in order")
|
|
18306
|
+
},
|
|
18141
18307
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
18142
18308
|
},
|
|
18143
18309
|
async ({ items }) => {
|
|
@@ -18151,6 +18317,7 @@ Pass one item or many (max 10) - multiple items run in parallel. Returns audio U
|
|
|
18151
18317
|
)
|
|
18152
18318
|
);
|
|
18153
18319
|
const lines = [];
|
|
18320
|
+
const structured = [];
|
|
18154
18321
|
let successCount = 0;
|
|
18155
18322
|
for (let i = 0; i < results.length; i++) {
|
|
18156
18323
|
const r = results[i];
|
|
@@ -18167,11 +18334,17 @@ Pass one item or many (max 10) - multiple items run in parallel. Returns audio U
|
|
|
18167
18334
|
...Array.isArray(c.words) ? { words: c.words.map((w) => ({ word: w.word, start: w.start, end: w.end })) } : {}
|
|
18168
18335
|
}));
|
|
18169
18336
|
lines.push(`Captions: ${JSON.stringify(captions)}`);
|
|
18337
|
+
structured.push({
|
|
18338
|
+
ok: true,
|
|
18339
|
+
...data.audioUrl ? { audio_url: String(data.audioUrl) } : {},
|
|
18340
|
+
captions
|
|
18341
|
+
});
|
|
18170
18342
|
} else {
|
|
18171
18343
|
const error2 = r.status === "rejected" ? r.reason?.message || String(r.reason) : r.value.error;
|
|
18172
18344
|
const status = r.status === "fulfilled" ? r.value.status : 0;
|
|
18173
18345
|
const hint = status === 500 || status === 0 ? " (transient - retrying may help)" : "";
|
|
18174
18346
|
lines.push(`FAILED: ${error2}${hint}`);
|
|
18347
|
+
structured.push({ ok: false, error: String(error2) });
|
|
18175
18348
|
}
|
|
18176
18349
|
lines.push("");
|
|
18177
18350
|
}
|
|
@@ -18181,7 +18354,7 @@ Pass one item or many (max 10) - multiple items run in parallel. Returns audio U
|
|
|
18181
18354
|
}
|
|
18182
18355
|
lines.push(`Pass the complete Captions JSON as the "captions" parameter when uploading.`);
|
|
18183
18356
|
if (successCount === 0) return errorResult(lines.join("\n"));
|
|
18184
|
-
return
|
|
18357
|
+
return structuredResult(lines.join("\n"), { results: structured });
|
|
18185
18358
|
}
|
|
18186
18359
|
);
|
|
18187
18360
|
}
|
|
@@ -18205,10 +18378,30 @@ Example: { queries: [{ query: "saturn rings" }, { query: "mars surface", count:
|
|
|
18205
18378
|
})
|
|
18206
18379
|
).min(1).max(10).describe("One or more search queries to run")
|
|
18207
18380
|
},
|
|
18381
|
+
outputSchema: {
|
|
18382
|
+
searches: external_exports.array(
|
|
18383
|
+
external_exports.object({
|
|
18384
|
+
query: external_exports.string(),
|
|
18385
|
+
kind: external_exports.enum(["image", "video"]),
|
|
18386
|
+
items: external_exports.array(
|
|
18387
|
+
external_exports.object({
|
|
18388
|
+
title: external_exports.string().optional(),
|
|
18389
|
+
url: external_exports.string(),
|
|
18390
|
+
width: external_exports.number().optional(),
|
|
18391
|
+
height: external_exports.number().optional(),
|
|
18392
|
+
duration: external_exports.number().optional(),
|
|
18393
|
+
source: external_exports.string().optional(),
|
|
18394
|
+
attribution: external_exports.string().optional()
|
|
18395
|
+
})
|
|
18396
|
+
)
|
|
18397
|
+
})
|
|
18398
|
+
).describe("Results grouped by query (items empty if a query found nothing or failed)")
|
|
18399
|
+
},
|
|
18208
18400
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
18209
18401
|
},
|
|
18210
18402
|
async ({ queries }) => {
|
|
18211
18403
|
const allLines = [];
|
|
18404
|
+
const searches = [];
|
|
18212
18405
|
for (const q of queries) {
|
|
18213
18406
|
const { query, count, orientation } = q;
|
|
18214
18407
|
const kind = q.kind ?? "image";
|
|
@@ -18218,16 +18411,32 @@ Example: { queries: [{ query: "saturn rings" }, { query: "mars surface", count:
|
|
|
18218
18411
|
if (queries.length > 1) allLines.push(`--- "${query}" (${kind}) ---`);
|
|
18219
18412
|
if (!result.ok) {
|
|
18220
18413
|
allLines.push(`FAILED: ${result.error}`, "");
|
|
18414
|
+
searches.push({ query, kind, items: [] });
|
|
18221
18415
|
continue;
|
|
18222
18416
|
}
|
|
18223
18417
|
const results = result.data.results;
|
|
18224
18418
|
if (!results.length) {
|
|
18225
18419
|
allLines.push(`No ${kind}s found.`, "");
|
|
18420
|
+
searches.push({ query, kind, items: [] });
|
|
18226
18421
|
continue;
|
|
18227
18422
|
}
|
|
18423
|
+
const shown = results.slice(0, 10);
|
|
18424
|
+
searches.push({
|
|
18425
|
+
query,
|
|
18426
|
+
kind,
|
|
18427
|
+
items: shown.map((item) => ({
|
|
18428
|
+
...item.title ? { title: item.title } : {},
|
|
18429
|
+
url: item.url,
|
|
18430
|
+
...typeof item.width === "number" ? { width: item.width } : {},
|
|
18431
|
+
...typeof item.height === "number" ? { height: item.height } : {},
|
|
18432
|
+
...kind === "video" && typeof item.duration === "number" ? { duration: item.duration } : {},
|
|
18433
|
+
...item.source ? { source: item.source } : {},
|
|
18434
|
+
...item.attribution ? { attribution: item.attribution } : {}
|
|
18435
|
+
}))
|
|
18436
|
+
});
|
|
18228
18437
|
allLines.push(`Found ${results.length} ${kind}s:
|
|
18229
18438
|
`);
|
|
18230
|
-
for (const item of
|
|
18439
|
+
for (const item of shown) {
|
|
18231
18440
|
allLines.push(`- ${item.title}`);
|
|
18232
18441
|
allLines.push(` URL: ${item.url}`);
|
|
18233
18442
|
const meta = [];
|
|
@@ -18242,7 +18451,7 @@ Example: { queries: [{ query: "saturn rings" }, { query: "mars surface", count:
|
|
|
18242
18451
|
allLines.push("");
|
|
18243
18452
|
}
|
|
18244
18453
|
}
|
|
18245
|
-
return
|
|
18454
|
+
return structuredResult(allLines.join("\n"), { searches });
|
|
18246
18455
|
}
|
|
18247
18456
|
);
|
|
18248
18457
|
}
|
|
@@ -18378,6 +18587,17 @@ For multi-render builds (e.g. one clip per quiz question), pass everything in ON
|
|
|
18378
18587
|
wait: external_exports.boolean().optional().default(true).describe("Single render only: true (default) blocks until the render is ready and returns its URL; false returns a job ID for clipform_check_render. Batch items always run fire-and-poll."),
|
|
18379
18588
|
items: external_exports.array(RenderItemSchema).min(1).max(10).optional().describe("Batch mode: multiple renders in one call. All fire in parallel; returns one job ID per item - collect with clipform_check_render (job_ids). Use this whenever rendering more than one clip.")
|
|
18380
18589
|
},
|
|
18590
|
+
outputSchema: {
|
|
18591
|
+
jobs: external_exports.array(
|
|
18592
|
+
external_exports.object({
|
|
18593
|
+
status: external_exports.enum(["rendering", "complete"]),
|
|
18594
|
+
job_id: external_exports.string().optional().describe("Present when status is 'rendering' - pass to check_render"),
|
|
18595
|
+
public_url: external_exports.string().optional().describe("Present when status is 'complete' - attach via upload_node_media (fit_media: true)"),
|
|
18596
|
+
composition_id: external_exports.string().optional(),
|
|
18597
|
+
output_format: external_exports.string().optional()
|
|
18598
|
+
})
|
|
18599
|
+
).describe("One entry per render (single or batch)")
|
|
18600
|
+
},
|
|
18381
18601
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
18382
18602
|
},
|
|
18383
18603
|
async ({ compositionId, outputFormat, inputProps, wait, items }) => {
|
|
@@ -18393,23 +18613,34 @@ For multi-render builds (e.g. one clip per quiz question), pass everything in ON
|
|
|
18393
18613
|
}
|
|
18394
18614
|
if (items?.length) {
|
|
18395
18615
|
const jobs2 = items.map((item) => ({ item, job: fireRender(item) }));
|
|
18396
|
-
return
|
|
18616
|
+
return structuredResult(
|
|
18397
18617
|
[
|
|
18398
18618
|
`${jobs2.length} renders started in parallel:`,
|
|
18399
18619
|
...jobs2.map(({ item, job }) => `- ${item.compositionId} (${item.outputFormat}): job ${job.id}`),
|
|
18400
18620
|
``,
|
|
18401
18621
|
`Collect with ONE clipform_check_render call (job_ids: [...]). Renders typically take ${RENDER_TIMING.expectedRange}.`
|
|
18402
|
-
].join("\n")
|
|
18622
|
+
].join("\n"),
|
|
18623
|
+
{
|
|
18624
|
+
jobs: jobs2.map(({ item, job }) => ({
|
|
18625
|
+
status: "rendering",
|
|
18626
|
+
job_id: job.id,
|
|
18627
|
+
composition_id: item.compositionId,
|
|
18628
|
+
output_format: item.outputFormat
|
|
18629
|
+
}))
|
|
18630
|
+
}
|
|
18403
18631
|
);
|
|
18404
18632
|
}
|
|
18405
18633
|
if (wait === false) {
|
|
18406
18634
|
const job = fireRender({ compositionId, outputFormat, inputProps });
|
|
18407
|
-
return
|
|
18635
|
+
return structuredResult(
|
|
18408
18636
|
[
|
|
18409
18637
|
`Render started (${compositionId}).`,
|
|
18410
18638
|
`Job ID: ${job.id}`,
|
|
18411
18639
|
`Fire any remaining renders now, then poll clipform_check_render. Renders typically take ${RENDER_TIMING.expectedRange}.`
|
|
18412
|
-
].join("\n")
|
|
18640
|
+
].join("\n"),
|
|
18641
|
+
{
|
|
18642
|
+
jobs: [{ status: "rendering", job_id: job.id, composition_id: compositionId, output_format: outputFormat }]
|
|
18643
|
+
}
|
|
18413
18644
|
);
|
|
18414
18645
|
}
|
|
18415
18646
|
const result = await callApi("/internal/render", {
|
|
@@ -18418,11 +18649,21 @@ For multi-render builds (e.g. one clip per quiz question), pass everything in ON
|
|
|
18418
18649
|
});
|
|
18419
18650
|
if (!result.ok) return errorResult(result.error);
|
|
18420
18651
|
const data = result.data;
|
|
18421
|
-
return
|
|
18652
|
+
return structuredResult(
|
|
18422
18653
|
[
|
|
18423
18654
|
`Render complete. Public URL: ${data.public_url}`,
|
|
18424
18655
|
`Attach via clipform_upload_node_media with fit_media: true (composed 9:16 frame - contain, never crop).`
|
|
18425
|
-
].join("\n")
|
|
18656
|
+
].join("\n"),
|
|
18657
|
+
{
|
|
18658
|
+
jobs: [
|
|
18659
|
+
{
|
|
18660
|
+
status: "complete",
|
|
18661
|
+
...data.public_url ? { public_url: data.public_url } : {},
|
|
18662
|
+
composition_id: compositionId,
|
|
18663
|
+
output_format: outputFormat
|
|
18664
|
+
}
|
|
18665
|
+
]
|
|
18666
|
+
}
|
|
18426
18667
|
);
|
|
18427
18668
|
}
|
|
18428
18669
|
);
|
|
@@ -18443,6 +18684,19 @@ function registerSearchMusicTool(server) {
|
|
|
18443
18684
|
maxDuration: external_exports.number().optional().describe("Maximum duration in seconds"),
|
|
18444
18685
|
tags: external_exports.array(external_exports.string()).optional().describe("Genre/mood tags to filter by")
|
|
18445
18686
|
},
|
|
18687
|
+
outputSchema: {
|
|
18688
|
+
query: external_exports.string(),
|
|
18689
|
+
tracks: external_exports.array(
|
|
18690
|
+
external_exports.object({
|
|
18691
|
+
title: external_exports.string().optional(),
|
|
18692
|
+
artist: external_exports.string().optional(),
|
|
18693
|
+
url: external_exports.string(),
|
|
18694
|
+
duration: external_exports.number().optional(),
|
|
18695
|
+
source: external_exports.string().optional(),
|
|
18696
|
+
license: external_exports.string().optional()
|
|
18697
|
+
})
|
|
18698
|
+
).describe("Matching tracks (empty if none); pass a url as the audio track to generate_video")
|
|
18699
|
+
},
|
|
18446
18700
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
18447
18701
|
},
|
|
18448
18702
|
async ({ query, count, instrumentalOnly, minDuration, maxDuration, tags }) => {
|
|
@@ -18451,7 +18705,15 @@ function registerSearchMusicTool(server) {
|
|
|
18451
18705
|
});
|
|
18452
18706
|
if (!result.ok) return errorResult(result.error);
|
|
18453
18707
|
const results = result.data.results;
|
|
18454
|
-
if (!results.length) return
|
|
18708
|
+
if (!results.length) return structuredResult(`No music found for "${query}".`, { query, tracks: [] });
|
|
18709
|
+
const tracks = results.map((item) => ({
|
|
18710
|
+
...item.title ? { title: item.title } : {},
|
|
18711
|
+
...item.artist ? { artist: item.artist } : {},
|
|
18712
|
+
url: item.url,
|
|
18713
|
+
...typeof item.duration === "number" ? { duration: item.duration } : {},
|
|
18714
|
+
...item.source ? { source: item.source } : {},
|
|
18715
|
+
...item.license ? { license: item.license } : {}
|
|
18716
|
+
}));
|
|
18455
18717
|
const lines = [`Found ${results.length} tracks for "${query}":
|
|
18456
18718
|
`];
|
|
18457
18719
|
for (const item of results) {
|
|
@@ -18462,7 +18724,7 @@ function registerSearchMusicTool(server) {
|
|
|
18462
18724
|
if (item.license) lines.push(` License: ${item.license}`);
|
|
18463
18725
|
lines.push("");
|
|
18464
18726
|
}
|
|
18465
|
-
return
|
|
18727
|
+
return structuredResult(lines.join("\n"), { query, tracks });
|
|
18466
18728
|
}
|
|
18467
18729
|
);
|
|
18468
18730
|
}
|
|
@@ -18503,6 +18765,19 @@ function registerListCompositionsTool(server) {
|
|
|
18503
18765
|
title: "List Compositions",
|
|
18504
18766
|
description: `Browse available video compositions and their expected props schemas. Call this before using clipform_render_composition to discover visual styles and their input props. For narrated slideshows from images, use clipform_generate_video instead.`,
|
|
18505
18767
|
inputSchema: {},
|
|
18768
|
+
outputSchema: {
|
|
18769
|
+
compositions: external_exports.array(
|
|
18770
|
+
external_exports.object({
|
|
18771
|
+
id: external_exports.string(),
|
|
18772
|
+
width: external_exports.number(),
|
|
18773
|
+
height: external_exports.number(),
|
|
18774
|
+
fps: external_exports.number(),
|
|
18775
|
+
durationInFrames: external_exports.number(),
|
|
18776
|
+
props: external_exports.string().describe("Compact props summary (name*: type)"),
|
|
18777
|
+
propsSchema: external_exports.record(external_exports.unknown()).optional().describe("Full JSON Schema for inputProps")
|
|
18778
|
+
})
|
|
18779
|
+
).describe("Available compositions - pass an id to render_composition")
|
|
18780
|
+
},
|
|
18506
18781
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
18507
18782
|
},
|
|
18508
18783
|
async () => {
|
|
@@ -18517,7 +18792,18 @@ function registerListCompositionsTool(server) {
|
|
|
18517
18792
|
}
|
|
18518
18793
|
const all = result.data.compositions;
|
|
18519
18794
|
const compositions = all.filter((c) => EXPOSED_COMPOSITIONS.includes(c.id));
|
|
18520
|
-
if (!compositions.length) return
|
|
18795
|
+
if (!compositions.length) return structuredResult("No compositions found.", { compositions: [] });
|
|
18796
|
+
const structured = {
|
|
18797
|
+
compositions: compositions.map((comp) => ({
|
|
18798
|
+
id: comp.id,
|
|
18799
|
+
width: comp.width,
|
|
18800
|
+
height: comp.height,
|
|
18801
|
+
fps: comp.fps,
|
|
18802
|
+
durationInFrames: comp.durationInFrames,
|
|
18803
|
+
props: summarizeSchema(comp.propsSchema),
|
|
18804
|
+
...comp.propsSchema ? { propsSchema: comp.propsSchema } : {}
|
|
18805
|
+
}))
|
|
18806
|
+
};
|
|
18521
18807
|
const lines = [`Available compositions (${compositions.length}):
|
|
18522
18808
|
`];
|
|
18523
18809
|
for (const comp of compositions) {
|
|
@@ -18527,7 +18813,7 @@ function registerListCompositionsTool(server) {
|
|
|
18527
18813
|
}
|
|
18528
18814
|
lines.push("");
|
|
18529
18815
|
lines.push("Use clipform_render_composition with a compositionId to render. inputProps are validated strictly against the schema - unknown or missing props fail.");
|
|
18530
|
-
return
|
|
18816
|
+
return structuredResult(lines.join("\n"), structured);
|
|
18531
18817
|
}
|
|
18532
18818
|
);
|
|
18533
18819
|
}
|
|
@@ -18542,6 +18828,11 @@ function registerListAssetsTool(server) {
|
|
|
18542
18828
|
inputSchema: {
|
|
18543
18829
|
type: external_exports.enum(["sfx", "animation", "font", "all"]).default("all").optional().describe("Asset type to list (default: all)")
|
|
18544
18830
|
},
|
|
18831
|
+
outputSchema: {
|
|
18832
|
+
sfx: external_exports.array(external_exports.object({ name: external_exports.string(), description: external_exports.string().nullable().optional(), path: external_exports.string().optional() })),
|
|
18833
|
+
animations: external_exports.array(external_exports.object({ name: external_exports.string(), description: external_exports.string().nullable().optional(), path: external_exports.string().optional() })),
|
|
18834
|
+
fonts: external_exports.array(external_exports.object({ name: external_exports.string(), weights: external_exports.array(external_exports.union([external_exports.string(), external_exports.number()])).optional() }))
|
|
18835
|
+
},
|
|
18545
18836
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
18546
18837
|
},
|
|
18547
18838
|
async ({ type }) => {
|
|
@@ -18552,6 +18843,11 @@ function registerListAssetsTool(server) {
|
|
|
18552
18843
|
if (!result.ok) return errorResult(result.error);
|
|
18553
18844
|
const data = result.data;
|
|
18554
18845
|
const lines = [];
|
|
18846
|
+
const structured = {
|
|
18847
|
+
sfx: (data.sfx ?? []).map((s) => ({ name: s.name, description: s.description ?? null, path: s.path })),
|
|
18848
|
+
animations: (data.animations ?? []).map((a) => ({ name: a.name, description: a.description ?? null, path: a.path })),
|
|
18849
|
+
fonts: (data.fonts ?? []).map((f) => ({ name: f.name, ...Array.isArray(f.weights) ? { weights: f.weights } : {} }))
|
|
18850
|
+
};
|
|
18555
18851
|
if (data.sfx?.length) {
|
|
18556
18852
|
lines.push(`## Sound Effects (${data.sfx.length})
|
|
18557
18853
|
`);
|
|
@@ -18576,7 +18872,7 @@ function registerListAssetsTool(server) {
|
|
|
18576
18872
|
}
|
|
18577
18873
|
lines.push("");
|
|
18578
18874
|
}
|
|
18579
|
-
return
|
|
18875
|
+
return structuredResult(lines.length ? lines.join("\n") : "No assets found.", structured);
|
|
18580
18876
|
}
|
|
18581
18877
|
);
|
|
18582
18878
|
}
|
|
@@ -18627,6 +18923,12 @@ For multi-question builds, pass wait: false on every render: each call returns a
|
|
|
18627
18923
|
background_color: external_exports.string().optional().describe("Background color (default '#000')"),
|
|
18628
18924
|
wait: external_exports.boolean().optional().default(true).describe("true (default) blocks until the video is ready and returns its URL. false returns a job ID immediately - fire all renders first, then poll clipform_check_render. Use false whenever rendering more than one video.")
|
|
18629
18925
|
},
|
|
18926
|
+
outputSchema: {
|
|
18927
|
+
status: external_exports.enum(["rendering", "complete"]).describe("'rendering' when wait:false (poll check_render); 'complete' with a public_url when wait:true"),
|
|
18928
|
+
job_id: external_exports.string().optional().describe("Present when status is 'rendering' - pass to check_render"),
|
|
18929
|
+
public_url: external_exports.string().optional().describe("Present when status is 'complete' - attach via upload_node_media (fit_media: true)"),
|
|
18930
|
+
duration_seconds: external_exports.number().optional()
|
|
18931
|
+
},
|
|
18630
18932
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
18631
18933
|
},
|
|
18632
18934
|
async ({ items, audio_url, background_audio_url, background_audio_volume, duration_seconds, random_effects, transition, style_preset, texture, duotone, background_color, wait }) => {
|
|
@@ -18658,30 +18960,52 @@ For multi-question builds, pass wait: false on every render: each call returns a
|
|
|
18658
18960
|
if (r.ok) completeJob(job.id, r.data);
|
|
18659
18961
|
else failJob(job.id, r.error);
|
|
18660
18962
|
}).catch((err) => failJob(job.id, err instanceof Error ? err.message : String(err)));
|
|
18661
|
-
return
|
|
18963
|
+
return structuredResult(
|
|
18662
18964
|
[
|
|
18663
18965
|
`Render started (${items.length} item${items.length > 1 ? "s" : ""}).`,
|
|
18664
18966
|
`Job ID: ${job.id}`,
|
|
18665
18967
|
`Fire any remaining renders now, then poll clipform_check_render. Renders typically take ${RENDER_TIMING.expectedRange}.`
|
|
18666
|
-
].join("\n")
|
|
18968
|
+
].join("\n"),
|
|
18969
|
+
{ status: "rendering", job_id: job.id }
|
|
18667
18970
|
);
|
|
18668
18971
|
}
|
|
18669
18972
|
const result = await apiCall();
|
|
18670
18973
|
if (!result.ok) return errorResult(result.error);
|
|
18671
18974
|
const data = result.data;
|
|
18672
|
-
return
|
|
18975
|
+
return structuredResult(
|
|
18673
18976
|
[
|
|
18674
18977
|
`Video rendered (${items.length} item${items.length > 1 ? "s" : ""}).`,
|
|
18675
18978
|
`Public URL: ${data.public_url}`,
|
|
18676
18979
|
data.duration_seconds ? `Duration: ${data.duration_seconds}s` : "",
|
|
18677
18980
|
`Attach via clipform_upload_node_media with fit_media: true (composed 9:16 frame - contain, never crop).`
|
|
18678
|
-
].filter(Boolean).join("\n")
|
|
18981
|
+
].filter(Boolean).join("\n"),
|
|
18982
|
+
{
|
|
18983
|
+
status: "complete",
|
|
18984
|
+
...data.public_url ? { public_url: data.public_url } : {},
|
|
18985
|
+
...typeof data.duration_seconds === "number" ? { duration_seconds: data.duration_seconds } : {}
|
|
18986
|
+
}
|
|
18679
18987
|
);
|
|
18680
18988
|
}
|
|
18681
18989
|
);
|
|
18682
18990
|
}
|
|
18683
18991
|
|
|
18684
18992
|
// src/tools/check-render.ts
|
|
18993
|
+
function projectJob(id, job) {
|
|
18994
|
+
if (!job) return { job_id: id, status: "not_found" };
|
|
18995
|
+
if (job.status === "rendering") {
|
|
18996
|
+
return { job_id: id, status: "rendering", elapsed_seconds: Math.round((Date.now() - job.createdAt) / 1e3) };
|
|
18997
|
+
}
|
|
18998
|
+
if (job.status === "failed") {
|
|
18999
|
+
return { job_id: id, status: "failed", ...job.error ? { error: job.error } : {} };
|
|
19000
|
+
}
|
|
19001
|
+
const data = job.result;
|
|
19002
|
+
return {
|
|
19003
|
+
job_id: id,
|
|
19004
|
+
status: "complete",
|
|
19005
|
+
...data?.public_url ? { public_url: data.public_url } : {},
|
|
19006
|
+
...typeof data?.duration_seconds === "number" ? { duration_seconds: data.duration_seconds } : {}
|
|
19007
|
+
};
|
|
19008
|
+
}
|
|
18685
19009
|
var LOST_JOB_RECOVERY = [
|
|
18686
19010
|
`Jobs expire after 30 minutes and are lost if the server restarts - the render itself may still have completed.`,
|
|
18687
19011
|
`To recover, re-run the original render call with identical arguments:`,
|
|
@@ -18718,6 +19042,18 @@ Pass job_ids to check a whole batch in ONE call - one line of status per job. Pa
|
|
|
18718
19042
|
job_id: external_exports.string().uuid().optional().describe("A single job ID returned by the render tool"),
|
|
18719
19043
|
job_ids: external_exports.array(external_exports.string().uuid()).min(1).max(20).optional().describe("Multiple job IDs - check the whole batch in one call instead of one call per job")
|
|
18720
19044
|
},
|
|
19045
|
+
outputSchema: {
|
|
19046
|
+
jobs: external_exports.array(
|
|
19047
|
+
external_exports.object({
|
|
19048
|
+
job_id: external_exports.string(),
|
|
19049
|
+
status: external_exports.enum(["rendering", "complete", "failed", "not_found"]),
|
|
19050
|
+
public_url: external_exports.string().optional(),
|
|
19051
|
+
duration_seconds: external_exports.number().optional(),
|
|
19052
|
+
elapsed_seconds: external_exports.number().optional(),
|
|
19053
|
+
error: external_exports.string().optional()
|
|
19054
|
+
})
|
|
19055
|
+
).describe("One entry per queried job; attach completed public_urls via upload_node_media")
|
|
19056
|
+
},
|
|
18721
19057
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
18722
19058
|
},
|
|
18723
19059
|
async ({ job_id, job_ids }) => {
|
|
@@ -18733,38 +19069,41 @@ Pass job_ids to check a whole batch in ONE call - one line of status per job. Pa
|
|
|
18733
19069
|
}
|
|
18734
19070
|
if (job.status === "rendering") {
|
|
18735
19071
|
const elapsed = Math.round((Date.now() - job.createdAt) / 1e3);
|
|
18736
|
-
return
|
|
19072
|
+
return structuredResult(
|
|
18737
19073
|
[
|
|
18738
19074
|
`Status: rendering (${elapsed}s elapsed)`,
|
|
18739
19075
|
`Tool: ${job.tool}`,
|
|
18740
19076
|
``,
|
|
18741
19077
|
`Still in progress. Check again in ${RENDER_TIMING.pollDelay}.`
|
|
18742
|
-
].join("\n")
|
|
19078
|
+
].join("\n"),
|
|
19079
|
+
{ jobs: [projectJob(ids[0], job)] }
|
|
18743
19080
|
);
|
|
18744
19081
|
}
|
|
18745
19082
|
if (job.status === "failed") {
|
|
18746
19083
|
return errorResult(`Render failed: ${job.error}`);
|
|
18747
19084
|
}
|
|
18748
19085
|
const data = job.result;
|
|
18749
|
-
return
|
|
19086
|
+
return structuredResult(
|
|
18750
19087
|
[
|
|
18751
19088
|
`Render complete.`,
|
|
18752
19089
|
...data.public_url ? [`Public URL: ${data.public_url}`] : [],
|
|
18753
19090
|
...data.duration_seconds ? [`Duration: ${data.duration_seconds}s`] : [],
|
|
18754
19091
|
`Attach via clipform_upload_node_media with fit_media: true (composed 9:16 frame - contain, never crop).`
|
|
18755
|
-
].join("\n")
|
|
19092
|
+
].join("\n"),
|
|
19093
|
+
{ jobs: [projectJob(ids[0], job)] }
|
|
18756
19094
|
);
|
|
18757
19095
|
}
|
|
18758
19096
|
const results = ids.map((id) => describeJob(id, getJob(id)));
|
|
18759
19097
|
const pending = results.filter((r) => !r.done).length;
|
|
18760
19098
|
const lost = results.some((r) => r.line.includes("NOT FOUND"));
|
|
18761
|
-
return
|
|
19099
|
+
return structuredResult(
|
|
18762
19100
|
[
|
|
18763
19101
|
`Render batch: ${results.length - pending}/${results.length} finished${pending ? ` - check again in ${RENDER_TIMING.pollDelay}` : ""}.`,
|
|
18764
19102
|
...results.map((r) => r.line),
|
|
18765
19103
|
...pending === 0 ? [``, `Attach completed renders via clipform_upload_node_media with fit_media: true (composed 9:16 frames - contain, never crop).`] : [],
|
|
18766
19104
|
...lost ? [``, LOST_JOB_RECOVERY] : []
|
|
18767
|
-
].join("\n")
|
|
19105
|
+
].join("\n"),
|
|
19106
|
+
{ jobs: ids.map((id) => projectJob(id, getJob(id))) }
|
|
18768
19107
|
);
|
|
18769
19108
|
}
|
|
18770
19109
|
);
|
|
@@ -19080,4 +19419,4 @@ export {
|
|
|
19080
19419
|
JSONRPCMessageSchema,
|
|
19081
19420
|
createServer
|
|
19082
19421
|
};
|
|
19083
|
-
//# sourceMappingURL=chunk-
|
|
19422
|
+
//# sourceMappingURL=chunk-3MTEM3VC.js.map
|