@fre4x/comfyui 1.1.0-beta.1 → 1.1.0-beta.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/README.md +22 -3
- package/dist/index.js +547 -73
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,10 @@ An MCP server to interact with ComfyUI remotely. Probe server state, inspect nod
|
|
|
11
11
|
- `comfyui_workflow_run`: Run a stored workflow with optional overrides.
|
|
12
12
|
- `comfyui_wait_for_workflow`: Wait for workflow completion with a timeout.
|
|
13
13
|
|
|
14
|
+
`comfyui_discover_workflows` filters out non-workflow JSON files and distinguishes
|
|
15
|
+
between API workflows and Web UI graphs whose conversion was validated against the
|
|
16
|
+
live node schema.
|
|
17
|
+
|
|
14
18
|
**Do not assume `structuredContent` is what the model actually sees.** Many MCP clients
|
|
15
19
|
surface `content.text` to the model first and treat `structuredContent` as secondary
|
|
16
20
|
machine-readable metadata. Every actionable detail that an agent needs for its next step
|
|
@@ -109,9 +113,24 @@ To inspect editable inputs and semantic hints for agent editing:
|
|
|
109
113
|
}
|
|
110
114
|
```
|
|
111
115
|
|
|
112
|
-
`comfyui_get_workflow`
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
`comfyui_get_workflow` and `comfyui_save_workflow` both return:
|
|
117
|
+
|
|
118
|
+
- `high_signal_inputs`: the most useful prompt/model/sampler controls first
|
|
119
|
+
- `input_groups`: grouped counts for prompts, models, sampling, output, etc.
|
|
120
|
+
- combo-backed inputs include `options_count`, `options_preview`, and `options_truncated`
|
|
121
|
+
- `override_examples`: copy-ready payloads using the preferred override aliases
|
|
122
|
+
|
|
123
|
+
These appear in both `content.text` and `structuredContent` so agents can steer
|
|
124
|
+
complex workflows without having to scan every literal widget first.
|
|
125
|
+
|
|
126
|
+
When `comfyui_wait_for_workflow` times out, the error now includes a queue
|
|
127
|
+
snapshot in both `content.text` and `structuredContent` to show whether the
|
|
128
|
+
prompt is still pending or has disappeared from the server queue.
|
|
129
|
+
|
|
130
|
+
`comfyui_workflow_run` also performs a preflight pass against the live
|
|
131
|
+
`/object_info` schema before submission so invalid combo-backed values such as
|
|
132
|
+
missing checkpoints, LoRAs, VAEs, or input filenames fail fast without entering
|
|
133
|
+
the ComfyUI queue.
|
|
115
134
|
|
|
116
135
|
To save a new or edited workflow locally:
|
|
117
136
|
|
package/dist/index.js
CHANGED
|
@@ -30760,6 +30760,15 @@ var OverrideRecordSchema = z3.record(z3.string(), z3.unknown());
|
|
|
30760
30760
|
var OverridesSchema = z3.union([OverrideRecordSchema, z3.string()]).describe(
|
|
30761
30761
|
'Dot-notation overrides as an object or JSON string. e.g. {"6.seed": 7}'
|
|
30762
30762
|
);
|
|
30763
|
+
var WorkflowTimeoutError = class extends Error {
|
|
30764
|
+
constructor(promptId, timeoutSeconds, queueSnapshot) {
|
|
30765
|
+
super(`Timeout waiting for workflow ${promptId}`);
|
|
30766
|
+
this.promptId = promptId;
|
|
30767
|
+
this.timeoutSeconds = timeoutSeconds;
|
|
30768
|
+
this.queueSnapshot = queueSnapshot;
|
|
30769
|
+
this.name = "WorkflowTimeoutError";
|
|
30770
|
+
}
|
|
30771
|
+
};
|
|
30763
30772
|
function isRecord2(value) {
|
|
30764
30773
|
return typeof value === "object" && value !== null;
|
|
30765
30774
|
}
|
|
@@ -30972,17 +30981,31 @@ ${detailSummary}` : error48.message
|
|
|
30972
30981
|
isError: true
|
|
30973
30982
|
};
|
|
30974
30983
|
}
|
|
30975
|
-
|
|
30976
|
-
|
|
30984
|
+
if (error48 instanceof WorkflowTimeoutError) {
|
|
30985
|
+
const queueSummary = formatQueueSnapshotText(error48.queueSnapshot);
|
|
30986
|
+
const promptVisibility = getPromptQueueVisibility(
|
|
30987
|
+
error48.promptId,
|
|
30988
|
+
error48.queueSnapshot
|
|
30989
|
+
);
|
|
30990
|
+
const promptVisibilityText = promptVisibility === true ? "The prompt is still visible in the ComfyUI queue snapshot." : promptVisibility === false ? "The prompt is not visible in the ComfyUI queue snapshot; inspect ComfyUI history or server logs if it never completes." : "ComfyUI queue state was unavailable at timeout.";
|
|
30977
30991
|
return {
|
|
30978
30992
|
content: [
|
|
30979
30993
|
{
|
|
30980
30994
|
type: "text",
|
|
30981
|
-
text:
|
|
30982
|
-
|
|
30983
|
-
|
|
30995
|
+
text: [
|
|
30996
|
+
`${error48.message}.`,
|
|
30997
|
+
queueSummary,
|
|
30998
|
+
promptVisibilityText,
|
|
30999
|
+
`You can re-attach by calling 'comfyui_wait_for_workflow' again with prompt_id '${error48.promptId}'.`
|
|
31000
|
+
].filter((line) => line && line.length > 0).join("\n")
|
|
30984
31001
|
}
|
|
30985
31002
|
],
|
|
31003
|
+
structuredContent: {
|
|
31004
|
+
prompt_id: error48.promptId,
|
|
31005
|
+
timeout_seconds: error48.timeoutSeconds,
|
|
31006
|
+
queue: error48.queueSnapshot ?? null,
|
|
31007
|
+
prompt_visible_in_queue: promptVisibility
|
|
31008
|
+
},
|
|
30986
31009
|
isError: true
|
|
30987
31010
|
};
|
|
30988
31011
|
}
|
|
@@ -31005,7 +31028,9 @@ function getWorkflowDirectories(extraPath) {
|
|
|
31005
31028
|
if (extraPath) {
|
|
31006
31029
|
directories.push(extraPath);
|
|
31007
31030
|
}
|
|
31008
|
-
return
|
|
31031
|
+
return [
|
|
31032
|
+
...new Set(directories.map((directory) => path.resolve(directory)))
|
|
31033
|
+
];
|
|
31009
31034
|
}
|
|
31010
31035
|
function getWorkflowNameCandidates(name) {
|
|
31011
31036
|
const trimmed = name.trim();
|
|
@@ -31094,6 +31119,7 @@ async function resolveWorkflowReference(args) {
|
|
|
31094
31119
|
"workflow_id"
|
|
31095
31120
|
);
|
|
31096
31121
|
}
|
|
31122
|
+
const objectInfoAvailability = await tryGetObjectInfo();
|
|
31097
31123
|
for (const dir of getWorkflowDirectories()) {
|
|
31098
31124
|
try {
|
|
31099
31125
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
@@ -31102,11 +31128,17 @@ async function resolveWorkflowReference(args) {
|
|
|
31102
31128
|
continue;
|
|
31103
31129
|
}
|
|
31104
31130
|
const fullPath = path.join(dir, entry.name);
|
|
31105
|
-
const
|
|
31106
|
-
|
|
31131
|
+
const inspected = await inspectWorkflowFile(
|
|
31132
|
+
fullPath,
|
|
31133
|
+
objectInfoAvailability.objectInfo
|
|
31134
|
+
);
|
|
31135
|
+
if (!inspected) {
|
|
31136
|
+
continue;
|
|
31137
|
+
}
|
|
31138
|
+
if (requestedId === inspected.id || requestedId === inspected.name || requestedId === entry.name.replace(/\.json$/, "")) {
|
|
31107
31139
|
return {
|
|
31108
31140
|
targetPath: fullPath,
|
|
31109
|
-
content:
|
|
31141
|
+
content: inspected.content
|
|
31110
31142
|
};
|
|
31111
31143
|
}
|
|
31112
31144
|
}
|
|
@@ -31181,6 +31213,75 @@ async function loadWorkflow(args, objectInfo) {
|
|
|
31181
31213
|
widgetPathMap
|
|
31182
31214
|
};
|
|
31183
31215
|
}
|
|
31216
|
+
async function inspectWorkflowFile(fullPath, objectInfo) {
|
|
31217
|
+
const content = await fs.readFile(fullPath, "utf8");
|
|
31218
|
+
const defaultName = path.basename(fullPath, ".json");
|
|
31219
|
+
const defaultId = getWorkflowId(fullPath);
|
|
31220
|
+
let parsed;
|
|
31221
|
+
try {
|
|
31222
|
+
parsed = JSON.parse(content);
|
|
31223
|
+
} catch {
|
|
31224
|
+
return void 0;
|
|
31225
|
+
}
|
|
31226
|
+
let name = defaultName;
|
|
31227
|
+
if (isRecord2(parsed)) {
|
|
31228
|
+
if (typeof parsed.name === "string" && parsed.name.trim().length > 0) {
|
|
31229
|
+
name = parsed.name;
|
|
31230
|
+
} else if (isRecord2(parsed.workflow) && typeof parsed.workflow.name === "string" && parsed.workflow.name.trim().length > 0) {
|
|
31231
|
+
name = parsed.workflow.name;
|
|
31232
|
+
}
|
|
31233
|
+
}
|
|
31234
|
+
if (isWebUIFormat(parsed)) {
|
|
31235
|
+
if (!objectInfo) {
|
|
31236
|
+
return {
|
|
31237
|
+
id: defaultId,
|
|
31238
|
+
name,
|
|
31239
|
+
path: fullPath,
|
|
31240
|
+
source_format: "webui",
|
|
31241
|
+
validation_status: "conversion_requires_node_schemas",
|
|
31242
|
+
content,
|
|
31243
|
+
isWebUI: true
|
|
31244
|
+
};
|
|
31245
|
+
}
|
|
31246
|
+
try {
|
|
31247
|
+
await normalizeWorkflowPrompt(parsed, objectInfo);
|
|
31248
|
+
return {
|
|
31249
|
+
id: defaultId,
|
|
31250
|
+
name,
|
|
31251
|
+
path: fullPath,
|
|
31252
|
+
source_format: "webui",
|
|
31253
|
+
validation_status: "conversion_validated",
|
|
31254
|
+
content,
|
|
31255
|
+
isWebUI: true
|
|
31256
|
+
};
|
|
31257
|
+
} catch (error48) {
|
|
31258
|
+
return {
|
|
31259
|
+
id: defaultId,
|
|
31260
|
+
name,
|
|
31261
|
+
path: fullPath,
|
|
31262
|
+
source_format: "webui",
|
|
31263
|
+
validation_status: "conversion_failed",
|
|
31264
|
+
content,
|
|
31265
|
+
error: summarizeErrorMessage(error48),
|
|
31266
|
+
isWebUI: true
|
|
31267
|
+
};
|
|
31268
|
+
}
|
|
31269
|
+
}
|
|
31270
|
+
try {
|
|
31271
|
+
await normalizeWorkflowPrompt(parsed);
|
|
31272
|
+
return {
|
|
31273
|
+
id: defaultId,
|
|
31274
|
+
name,
|
|
31275
|
+
path: fullPath,
|
|
31276
|
+
source_format: "api",
|
|
31277
|
+
validation_status: "ready",
|
|
31278
|
+
content,
|
|
31279
|
+
isWebUI: false
|
|
31280
|
+
};
|
|
31281
|
+
} catch {
|
|
31282
|
+
return void 0;
|
|
31283
|
+
}
|
|
31284
|
+
}
|
|
31184
31285
|
function inferEditableRole(nodeId, classType, inputName, consumerMap) {
|
|
31185
31286
|
if (classType === "CLIPTextEncode" && inputName === "text") {
|
|
31186
31287
|
const consumers = consumerMap.get(nodeId) ?? [];
|
|
@@ -31192,6 +31293,28 @@ function inferEditableRole(nodeId, classType, inputName, consumerMap) {
|
|
|
31192
31293
|
}
|
|
31193
31294
|
return "prompt_text";
|
|
31194
31295
|
}
|
|
31296
|
+
if (inputName === "value") {
|
|
31297
|
+
const consumers = consumerMap.get(nodeId) ?? [];
|
|
31298
|
+
const textConsumers = consumers.filter(
|
|
31299
|
+
(consumer) => consumer.classType === "CLIPTextEncode" && consumer.inputName === "text"
|
|
31300
|
+
);
|
|
31301
|
+
if (textConsumers.length > 0) {
|
|
31302
|
+
for (const consumer of textConsumers) {
|
|
31303
|
+
const clipConsumers = consumerMap.get(consumer.nodeId) ?? [];
|
|
31304
|
+
if (clipConsumers.some(
|
|
31305
|
+
(clipConsumer) => clipConsumer.inputName === "positive"
|
|
31306
|
+
)) {
|
|
31307
|
+
return "positive_prompt";
|
|
31308
|
+
}
|
|
31309
|
+
if (clipConsumers.some(
|
|
31310
|
+
(clipConsumer) => clipConsumer.inputName === "negative"
|
|
31311
|
+
)) {
|
|
31312
|
+
return "negative_prompt";
|
|
31313
|
+
}
|
|
31314
|
+
}
|
|
31315
|
+
return "prompt_text";
|
|
31316
|
+
}
|
|
31317
|
+
}
|
|
31195
31318
|
switch (inputName) {
|
|
31196
31319
|
case "seed":
|
|
31197
31320
|
return "seed";
|
|
@@ -31256,6 +31379,20 @@ function getExpectedTypeName(inputDefinition) {
|
|
|
31256
31379
|
const [typeData] = inputDefinition;
|
|
31257
31380
|
return Array.isArray(typeData) ? "COMBO" : String(typeData).toUpperCase();
|
|
31258
31381
|
}
|
|
31382
|
+
function getInputOptionsSummary(inputDefinition, previewLimit = 8) {
|
|
31383
|
+
if (!inputDefinition) {
|
|
31384
|
+
return void 0;
|
|
31385
|
+
}
|
|
31386
|
+
const [typeData] = inputDefinition;
|
|
31387
|
+
if (!Array.isArray(typeData)) {
|
|
31388
|
+
return void 0;
|
|
31389
|
+
}
|
|
31390
|
+
return {
|
|
31391
|
+
options_count: typeData.length,
|
|
31392
|
+
options_preview: typeData.slice(0, previewLimit),
|
|
31393
|
+
options_truncated: typeData.length > previewLimit
|
|
31394
|
+
};
|
|
31395
|
+
}
|
|
31259
31396
|
function isPlainObject3(value) {
|
|
31260
31397
|
return isRecord2(value) && !Array.isArray(value);
|
|
31261
31398
|
}
|
|
@@ -31413,10 +31550,146 @@ function getPreferredOverridePath(entry) {
|
|
|
31413
31550
|
);
|
|
31414
31551
|
return nonWidgetAlias ?? entry.path;
|
|
31415
31552
|
}
|
|
31553
|
+
function formatEditableInputOptionsText(entry) {
|
|
31554
|
+
if (entry.options_count === void 0 || entry.options_preview === void 0 || entry.options_preview.length === 0) {
|
|
31555
|
+
return "";
|
|
31556
|
+
}
|
|
31557
|
+
const preview = entry.options_preview.map((option) => formatValuePreview(option)).join(", ");
|
|
31558
|
+
const truncatedSuffix = entry.options_truncated ? ", ..." : "";
|
|
31559
|
+
return ` | options: ${preview}${truncatedSuffix} (${entry.options_count} total)`;
|
|
31560
|
+
}
|
|
31561
|
+
function getEditableInputGroup(entry) {
|
|
31562
|
+
if (entry.role === "positive_prompt" || entry.role === "negative_prompt" || entry.role === "prompt_text") {
|
|
31563
|
+
return "prompts";
|
|
31564
|
+
}
|
|
31565
|
+
if (entry.role === "checkpoint" || entry.input_name === "ckpt_name" || entry.input_name === "model_name" || entry.input_name === "vae_name" || entry.class_type.includes("Checkpoint") || entry.class_type.includes("VAE")) {
|
|
31566
|
+
return "models";
|
|
31567
|
+
}
|
|
31568
|
+
if (entry.role === "seed" || entry.role === "steps" || entry.role === "cfg" || entry.role === "sampler" || entry.role === "scheduler" || entry.role === "denoise" || entry.class_type.includes("Sampler")) {
|
|
31569
|
+
return "sampling";
|
|
31570
|
+
}
|
|
31571
|
+
if (entry.role === "width" || entry.role === "height" || entry.role === "batch_size") {
|
|
31572
|
+
return "image";
|
|
31573
|
+
}
|
|
31574
|
+
if (entry.input_name === "lora_name" || entry.input_name.startsWith("strength_") || entry.class_type.includes("Lora")) {
|
|
31575
|
+
return "loras";
|
|
31576
|
+
}
|
|
31577
|
+
if (entry.class_type.includes("ControlNet") || entry.class_type.includes("IPAdapter") || entry.class_type.includes("FreeU") || entry.class_type.includes("FaceDetailer")) {
|
|
31578
|
+
return "control";
|
|
31579
|
+
}
|
|
31580
|
+
if (entry.role === "filename_prefix" || entry.input_name === "filename" || entry.input_name === "path" || entry.input_name === "extension" || entry.class_type.includes("Save") || entry.class_type.includes("PromptSaver")) {
|
|
31581
|
+
return "output";
|
|
31582
|
+
}
|
|
31583
|
+
return "other";
|
|
31584
|
+
}
|
|
31585
|
+
function getEditableInputPriority(entry) {
|
|
31586
|
+
const rolePriority = {
|
|
31587
|
+
positive_prompt: 300,
|
|
31588
|
+
negative_prompt: 295,
|
|
31589
|
+
prompt_text: 290,
|
|
31590
|
+
checkpoint: 260,
|
|
31591
|
+
seed: 250,
|
|
31592
|
+
steps: 240,
|
|
31593
|
+
cfg: 235,
|
|
31594
|
+
sampler: 230,
|
|
31595
|
+
scheduler: 225,
|
|
31596
|
+
width: 220,
|
|
31597
|
+
height: 219,
|
|
31598
|
+
batch_size: 218,
|
|
31599
|
+
denoise: 215,
|
|
31600
|
+
filename_prefix: 190,
|
|
31601
|
+
text: 180
|
|
31602
|
+
};
|
|
31603
|
+
let priority = rolePriority[entry.role ?? ""] ?? 0;
|
|
31604
|
+
if (entry.input_name === "lora_name") {
|
|
31605
|
+
priority = Math.max(priority, 170);
|
|
31606
|
+
}
|
|
31607
|
+
if (entry.input_name.startsWith("strength_")) {
|
|
31608
|
+
priority = Math.max(priority, 160);
|
|
31609
|
+
}
|
|
31610
|
+
if (entry.class_type.includes("PromptSaver") || entry.class_type === "SaveImage") {
|
|
31611
|
+
priority -= 70;
|
|
31612
|
+
}
|
|
31613
|
+
if (entry.class_type === "PrimitiveStringMultiline" && (entry.role === "positive_prompt" || entry.role === "negative_prompt")) {
|
|
31614
|
+
priority += 30;
|
|
31615
|
+
}
|
|
31616
|
+
return priority;
|
|
31617
|
+
}
|
|
31618
|
+
function getHighSignalEditableInputs(editableInputs, limit = 12) {
|
|
31619
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31620
|
+
const prioritized = [...editableInputs].sort((left, right) => {
|
|
31621
|
+
const priorityDiff = getEditableInputPriority(right) - getEditableInputPriority(left);
|
|
31622
|
+
if (priorityDiff !== 0) {
|
|
31623
|
+
return priorityDiff;
|
|
31624
|
+
}
|
|
31625
|
+
return getPreferredOverridePath(left).localeCompare(
|
|
31626
|
+
getPreferredOverridePath(right),
|
|
31627
|
+
void 0,
|
|
31628
|
+
{ numeric: true }
|
|
31629
|
+
);
|
|
31630
|
+
}).filter((entry) => {
|
|
31631
|
+
const preferredPath = getPreferredOverridePath(entry);
|
|
31632
|
+
if (seen.has(preferredPath)) {
|
|
31633
|
+
return false;
|
|
31634
|
+
}
|
|
31635
|
+
seen.add(preferredPath);
|
|
31636
|
+
return true;
|
|
31637
|
+
});
|
|
31638
|
+
return prioritized.slice(0, limit);
|
|
31639
|
+
}
|
|
31640
|
+
function summarizeEditableInputGroups(editableInputs) {
|
|
31641
|
+
const labels = {
|
|
31642
|
+
prompts: "Prompts",
|
|
31643
|
+
models: "Models and checkpoints",
|
|
31644
|
+
sampling: "Sampling",
|
|
31645
|
+
image: "Image size and batching",
|
|
31646
|
+
loras: "LoRAs and strengths",
|
|
31647
|
+
control: "Conditioning and adapters",
|
|
31648
|
+
output: "Output and persistence",
|
|
31649
|
+
other: "Other"
|
|
31650
|
+
};
|
|
31651
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
31652
|
+
for (const entry of editableInputs) {
|
|
31653
|
+
const group = getEditableInputGroup(entry);
|
|
31654
|
+
const existing = summaries.get(group) ?? {
|
|
31655
|
+
group,
|
|
31656
|
+
label: labels[group],
|
|
31657
|
+
count: 0,
|
|
31658
|
+
sample_paths: []
|
|
31659
|
+
};
|
|
31660
|
+
existing.count += 1;
|
|
31661
|
+
if (existing.sample_paths.length < 3) {
|
|
31662
|
+
existing.sample_paths.push(getPreferredOverridePath(entry));
|
|
31663
|
+
}
|
|
31664
|
+
summaries.set(group, existing);
|
|
31665
|
+
}
|
|
31666
|
+
const order = [
|
|
31667
|
+
"prompts",
|
|
31668
|
+
"models",
|
|
31669
|
+
"sampling",
|
|
31670
|
+
"image",
|
|
31671
|
+
"loras",
|
|
31672
|
+
"control",
|
|
31673
|
+
"output",
|
|
31674
|
+
"other"
|
|
31675
|
+
];
|
|
31676
|
+
return order.map((group) => summaries.get(group)).filter(
|
|
31677
|
+
(summary) => Boolean(summary)
|
|
31678
|
+
);
|
|
31679
|
+
}
|
|
31680
|
+
function formatEditableInputGroupsText(groupSummaries) {
|
|
31681
|
+
if (groupSummaries.length === 0) {
|
|
31682
|
+
return "No editable input groups were detected.";
|
|
31683
|
+
}
|
|
31684
|
+
return formatListItems(groupSummaries, (summary) => {
|
|
31685
|
+
const examples = summary.sample_paths.length > 0 ? ` | examples: ${summary.sample_paths.join(", ")}` : "";
|
|
31686
|
+
return `${summary.label}: ${summary.count}${examples}`;
|
|
31687
|
+
});
|
|
31688
|
+
}
|
|
31416
31689
|
function buildOverrideExamples(editableInputs, limit = 5) {
|
|
31417
31690
|
const examples = {};
|
|
31418
31691
|
const preferredPaths = [];
|
|
31419
|
-
for (const entry of editableInputs
|
|
31692
|
+
for (const entry of getHighSignalEditableInputs(editableInputs, limit)) {
|
|
31420
31693
|
const preferredPath = getPreferredOverridePath(entry);
|
|
31421
31694
|
examples[preferredPath] = entry.value;
|
|
31422
31695
|
preferredPaths.push(preferredPath);
|
|
@@ -31545,6 +31818,9 @@ function analyzeEditableInputs(prompt, objectInfo, widgetPathMap = {}) {
|
|
|
31545
31818
|
aliases: [],
|
|
31546
31819
|
expected_type: getExpectedTypeName(
|
|
31547
31820
|
getInputDefinition(objectInfo, prompt, nodeId, inputName)
|
|
31821
|
+
),
|
|
31822
|
+
...getInputOptionsSummary(
|
|
31823
|
+
getInputDefinition(objectInfo, prompt, nodeId, inputName)
|
|
31548
31824
|
)
|
|
31549
31825
|
});
|
|
31550
31826
|
}
|
|
@@ -31562,7 +31838,7 @@ function analyzeEditableInputs(prompt, objectInfo, widgetPathMap = {}) {
|
|
|
31562
31838
|
(left, right) => left.path.localeCompare(right.path, void 0, { numeric: true })
|
|
31563
31839
|
);
|
|
31564
31840
|
}
|
|
31565
|
-
function formatEditableInputsText(editableInputs) {
|
|
31841
|
+
function formatEditableInputsText(editableInputs, options = {}) {
|
|
31566
31842
|
if (editableInputs.length === 0) {
|
|
31567
31843
|
return "No literal editable inputs were detected.";
|
|
31568
31844
|
}
|
|
@@ -31571,9 +31847,154 @@ function formatEditableInputsText(editableInputs) {
|
|
|
31571
31847
|
const classType = entry.class_type ? ` (${entry.class_type})` : "";
|
|
31572
31848
|
const expectedType = entry.expected_type ? ` <${entry.expected_type}>` : "";
|
|
31573
31849
|
const aliasSuffix = entry.aliases.length > 0 ? ` | aliases: ${entry.aliases.join(", ")}` : "";
|
|
31574
|
-
|
|
31850
|
+
const optionsSuffix = options.includeOptions ? formatEditableInputOptionsText(entry) : "";
|
|
31851
|
+
return `${entry.path}${role}${classType}${expectedType}: ${entry.value_preview}${aliasSuffix}${optionsSuffix}`;
|
|
31575
31852
|
});
|
|
31576
31853
|
}
|
|
31854
|
+
function validatePromptPreflight(prompt, objectInfo, widgetPathMap = {}) {
|
|
31855
|
+
if (!objectInfo) {
|
|
31856
|
+
return {
|
|
31857
|
+
checked_inputs: 0,
|
|
31858
|
+
combo_inputs: 0
|
|
31859
|
+
};
|
|
31860
|
+
}
|
|
31861
|
+
const editableInputs = analyzeEditableInputs(
|
|
31862
|
+
prompt,
|
|
31863
|
+
objectInfo,
|
|
31864
|
+
widgetPathMap
|
|
31865
|
+
);
|
|
31866
|
+
const issues = [];
|
|
31867
|
+
let checkedInputs = 0;
|
|
31868
|
+
let comboInputs = 0;
|
|
31869
|
+
for (const entry of editableInputs) {
|
|
31870
|
+
const inputDefinition = getInputDefinition(
|
|
31871
|
+
objectInfo,
|
|
31872
|
+
prompt,
|
|
31873
|
+
entry.node_id,
|
|
31874
|
+
entry.input_name
|
|
31875
|
+
);
|
|
31876
|
+
if (!inputDefinition) {
|
|
31877
|
+
continue;
|
|
31878
|
+
}
|
|
31879
|
+
checkedInputs += 1;
|
|
31880
|
+
if (Array.isArray(inputDefinition[0])) {
|
|
31881
|
+
comboInputs += 1;
|
|
31882
|
+
}
|
|
31883
|
+
try {
|
|
31884
|
+
validateOverrideValueType(entry.path, entry.value, inputDefinition);
|
|
31885
|
+
} catch (error48) {
|
|
31886
|
+
if (!(error48 instanceof WorkflowInputError)) {
|
|
31887
|
+
throw error48;
|
|
31888
|
+
}
|
|
31889
|
+
const preferredPath = getPreferredOverridePath(entry);
|
|
31890
|
+
const comboHint = formatEditableInputOptionsText(entry);
|
|
31891
|
+
const issueMessage = entry.expected_type === "COMBO" && entry.options_count !== void 0 ? `${formatValuePreview(entry.value)} is not in the server-reported options for ${preferredPath}.` : error48.message;
|
|
31892
|
+
issues.push(`- ${preferredPath}: ${issueMessage}${comboHint}`);
|
|
31893
|
+
}
|
|
31894
|
+
}
|
|
31895
|
+
if (issues.length > 0) {
|
|
31896
|
+
throw new WorkflowInputError(
|
|
31897
|
+
`Workflow preflight failed before submission.
|
|
31898
|
+
${issues.join("\n")}`,
|
|
31899
|
+
"workflow"
|
|
31900
|
+
);
|
|
31901
|
+
}
|
|
31902
|
+
return {
|
|
31903
|
+
checked_inputs: checkedInputs,
|
|
31904
|
+
combo_inputs: comboInputs
|
|
31905
|
+
};
|
|
31906
|
+
}
|
|
31907
|
+
function formatInputDefinitionSummary(inputName, inputDefinition) {
|
|
31908
|
+
const [typeData, extraInfo] = inputDefinition;
|
|
31909
|
+
const typeLabel = Array.isArray(typeData) ? `COMBO (${typeData.length} options)` : String(typeData).toUpperCase();
|
|
31910
|
+
const details = [];
|
|
31911
|
+
if (Array.isArray(typeData)) {
|
|
31912
|
+
details.push(
|
|
31913
|
+
`options: ${typeData.slice(0, 5).map((option) => JSON.stringify(option)).join(", ")}${typeData.length > 5 ? ", ..." : ""}`
|
|
31914
|
+
);
|
|
31915
|
+
}
|
|
31916
|
+
if (isRecord2(extraInfo)) {
|
|
31917
|
+
if (extraInfo.default !== void 0) {
|
|
31918
|
+
details.push(`default: ${formatValuePreview(extraInfo.default)}`);
|
|
31919
|
+
}
|
|
31920
|
+
if (typeof extraInfo.min === "number") {
|
|
31921
|
+
details.push(`min: ${extraInfo.min}`);
|
|
31922
|
+
}
|
|
31923
|
+
if (typeof extraInfo.max === "number") {
|
|
31924
|
+
details.push(`max: ${extraInfo.max}`);
|
|
31925
|
+
}
|
|
31926
|
+
}
|
|
31927
|
+
return `${inputName} <${typeLabel}>${details.length > 0 ? ` | ${details.join(" | ")}` : ""}`;
|
|
31928
|
+
}
|
|
31929
|
+
function formatNodeDefinitionText(nodeClass, node) {
|
|
31930
|
+
const requiredInputs = Object.entries(node.input.required ?? {});
|
|
31931
|
+
const optionalInputs = Object.entries(node.input.optional ?? {});
|
|
31932
|
+
const lines = [
|
|
31933
|
+
`Node: ${nodeClass}`,
|
|
31934
|
+
`Display name: ${node.display_name || node.name || nodeClass}`,
|
|
31935
|
+
`Category: ${node.category || "uncategorized"}`
|
|
31936
|
+
];
|
|
31937
|
+
if (typeof node.description === "string" && node.description.trim().length > 0) {
|
|
31938
|
+
lines.push(`Description: ${node.description.trim()}`);
|
|
31939
|
+
}
|
|
31940
|
+
lines.push(
|
|
31941
|
+
`Required inputs (${requiredInputs.length}): ${requiredInputs.length > 0 ? requiredInputs.map(
|
|
31942
|
+
([inputName, inputDefinition]) => formatInputDefinitionSummary(
|
|
31943
|
+
inputName,
|
|
31944
|
+
inputDefinition
|
|
31945
|
+
)
|
|
31946
|
+
).join("\n") : "None."}`
|
|
31947
|
+
);
|
|
31948
|
+
lines.push(
|
|
31949
|
+
`Optional inputs (${optionalInputs.length}): ${optionalInputs.length > 0 ? optionalInputs.map(
|
|
31950
|
+
([inputName, inputDefinition]) => formatInputDefinitionSummary(
|
|
31951
|
+
inputName,
|
|
31952
|
+
inputDefinition
|
|
31953
|
+
)
|
|
31954
|
+
).join("\n") : "None."}`
|
|
31955
|
+
);
|
|
31956
|
+
lines.push(`Outputs: ${node.output.join(", ") || "None."}`);
|
|
31957
|
+
return lines.join("\n");
|
|
31958
|
+
}
|
|
31959
|
+
function formatNodeListText(classes, rawInfo, pagination) {
|
|
31960
|
+
const text = `Available nodes (${pagination.total} total):
|
|
31961
|
+
` + formatListItems(classes, (nodeClass) => {
|
|
31962
|
+
const node = rawInfo[nodeClass];
|
|
31963
|
+
const displayName = node.display_name && node.display_name !== nodeClass ? ` \u2014 ${node.display_name}` : "";
|
|
31964
|
+
const category = node.category ? ` | category: ${node.category}` : "";
|
|
31965
|
+
const description = typeof node.description === "string" && node.description.trim().length > 0 ? ` | ${node.description.trim()}` : "";
|
|
31966
|
+
return `${nodeClass}${displayName}${category}${description}`;
|
|
31967
|
+
});
|
|
31968
|
+
if (!pagination.hasMore) {
|
|
31969
|
+
return text;
|
|
31970
|
+
}
|
|
31971
|
+
return `${text}
|
|
31972
|
+
|
|
31973
|
+
${formatPaginationFooter(
|
|
31974
|
+
pagination.offset,
|
|
31975
|
+
pagination.limit,
|
|
31976
|
+
pagination.total
|
|
31977
|
+
)}`;
|
|
31978
|
+
}
|
|
31979
|
+
async function getQueueSnapshot() {
|
|
31980
|
+
try {
|
|
31981
|
+
return IS_MOCK ? MOCK_FIXTURES.queue : await fetchComfyJson("/queue");
|
|
31982
|
+
} catch {
|
|
31983
|
+
return void 0;
|
|
31984
|
+
}
|
|
31985
|
+
}
|
|
31986
|
+
function formatQueueSnapshotText(queueSnapshot) {
|
|
31987
|
+
if (!queueSnapshot) {
|
|
31988
|
+
return "";
|
|
31989
|
+
}
|
|
31990
|
+
return `Queue snapshot: ${queueSnapshot.queue_running.length} running, ${queueSnapshot.queue_pending.length} pending.`;
|
|
31991
|
+
}
|
|
31992
|
+
function getPromptQueueVisibility(promptId, queueSnapshot) {
|
|
31993
|
+
if (!queueSnapshot) {
|
|
31994
|
+
return null;
|
|
31995
|
+
}
|
|
31996
|
+
return JSON.stringify(queueSnapshot).includes(promptId);
|
|
31997
|
+
}
|
|
31577
31998
|
function deriveSavedWorkflowFileName(sourcePath, requestedName) {
|
|
31578
31999
|
if (requestedName) {
|
|
31579
32000
|
return normalizeWorkflowFileName(requestedName);
|
|
@@ -31670,7 +32091,10 @@ async function handleInspectNode(args) {
|
|
|
31670
32091
|
}
|
|
31671
32092
|
return {
|
|
31672
32093
|
content: [
|
|
31673
|
-
{
|
|
32094
|
+
{
|
|
32095
|
+
type: "text",
|
|
32096
|
+
text: formatNodeDefinitionText(args.node_class, node)
|
|
32097
|
+
}
|
|
31674
32098
|
],
|
|
31675
32099
|
structuredContent: { ...node }
|
|
31676
32100
|
};
|
|
@@ -31689,16 +32113,18 @@ async function handleInspectNode(args) {
|
|
|
31689
32113
|
for (const c of paginated.items) {
|
|
31690
32114
|
resultNodes[c] = rawInfo[c];
|
|
31691
32115
|
}
|
|
31692
|
-
const text = `Available nodes (${paginated.total} total):
|
|
31693
|
-
` + paginated.items.join(", ") + (paginated.hasMore ? `
|
|
31694
|
-
|
|
31695
|
-
${formatPaginationFooter(
|
|
31696
|
-
paginated.offset,
|
|
31697
|
-
paginated.limit,
|
|
31698
|
-
paginated.total
|
|
31699
|
-
)}` : "");
|
|
31700
32116
|
return {
|
|
31701
|
-
content: [
|
|
32117
|
+
content: [
|
|
32118
|
+
{
|
|
32119
|
+
type: "text",
|
|
32120
|
+
text: formatNodeListText(paginated.items, rawInfo, {
|
|
32121
|
+
total: paginated.total,
|
|
32122
|
+
offset: paginated.offset,
|
|
32123
|
+
limit: paginated.limit,
|
|
32124
|
+
hasMore: paginated.hasMore
|
|
32125
|
+
})
|
|
32126
|
+
}
|
|
32127
|
+
],
|
|
31702
32128
|
structuredContent: {
|
|
31703
32129
|
nodes: resultNodes,
|
|
31704
32130
|
pagination: {
|
|
@@ -31718,42 +32144,27 @@ function getWorkflowId(absolutePath) {
|
|
|
31718
32144
|
}
|
|
31719
32145
|
async function handleDiscoverWorkflows(args) {
|
|
31720
32146
|
const pathsToScan = getWorkflowDirectories(args.directory_path);
|
|
32147
|
+
const objectInfoAvailability = await tryGetObjectInfo();
|
|
31721
32148
|
const foundWorkflows = [];
|
|
32149
|
+
let skippedNonWorkflowFiles = 0;
|
|
31722
32150
|
for (const dir of pathsToScan) {
|
|
31723
32151
|
try {
|
|
31724
32152
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
31725
32153
|
for (const entry of entries) {
|
|
31726
32154
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
31727
32155
|
const fullPath = path.join(dir, entry.name);
|
|
31728
|
-
const defaultId = getWorkflowId(fullPath);
|
|
31729
|
-
const defaultName = entry.name.replace(/\.json$/, "");
|
|
31730
32156
|
try {
|
|
31731
|
-
const
|
|
31732
|
-
|
|
31733
|
-
|
|
31734
|
-
|
|
31735
|
-
|
|
31736
|
-
|
|
31737
|
-
|
|
31738
|
-
|
|
31739
|
-
}
|
|
31740
|
-
if (typeof json2.name === "string") name = json2.name;
|
|
31741
|
-
else if (json2.workflow && typeof json2.workflow.name === "string")
|
|
31742
|
-
name = json2.workflow.name;
|
|
32157
|
+
const inspected = await inspectWorkflowFile(
|
|
32158
|
+
fullPath,
|
|
32159
|
+
objectInfoAvailability.objectInfo
|
|
32160
|
+
);
|
|
32161
|
+
if (inspected) {
|
|
32162
|
+
foundWorkflows.push(inspected);
|
|
32163
|
+
} else {
|
|
32164
|
+
skippedNonWorkflowFiles += 1;
|
|
31743
32165
|
}
|
|
31744
|
-
|
|
31745
|
-
|
|
31746
|
-
name,
|
|
31747
|
-
path: fullPath,
|
|
31748
|
-
isWebUI
|
|
31749
|
-
});
|
|
31750
|
-
} catch (e) {
|
|
31751
|
-
foundWorkflows.push({
|
|
31752
|
-
id: defaultId,
|
|
31753
|
-
name: defaultName,
|
|
31754
|
-
path: fullPath,
|
|
31755
|
-
error: String(e)
|
|
31756
|
-
});
|
|
32166
|
+
} catch {
|
|
32167
|
+
skippedNonWorkflowFiles += 1;
|
|
31757
32168
|
}
|
|
31758
32169
|
}
|
|
31759
32170
|
}
|
|
@@ -31761,14 +32172,14 @@ async function handleDiscoverWorkflows(args) {
|
|
|
31761
32172
|
}
|
|
31762
32173
|
}
|
|
31763
32174
|
if (foundWorkflows.length === 0) {
|
|
31764
|
-
const
|
|
32175
|
+
const text = `No workflows found in searched directories.
|
|
31765
32176
|
|
|
31766
32177
|
Searched paths:
|
|
31767
32178
|
${pathsToScan.map((p) => `- ${p}`).join("\n")}
|
|
31768
32179
|
|
|
31769
32180
|
Hint: If your workflows are stored elsewhere, provide a custom path using the 'directory_path' parameter.`;
|
|
31770
32181
|
return {
|
|
31771
|
-
content: [{ type: "text", text
|
|
32182
|
+
content: [{ type: "text", text }],
|
|
31772
32183
|
structuredContent: {
|
|
31773
32184
|
workflows: [],
|
|
31774
32185
|
searched_paths: pathsToScan
|
|
@@ -31776,23 +32187,47 @@ Hint: If your workflows are stored elsewhere, provide a custom path using the 'd
|
|
|
31776
32187
|
};
|
|
31777
32188
|
}
|
|
31778
32189
|
const paginated = applyPagination(foundWorkflows, args);
|
|
31779
|
-
const
|
|
31780
|
-
`
|
|
31781
|
-
|
|
31782
|
-
|
|
31783
|
-
|
|
31784
|
-
|
|
31785
|
-
|
|
31786
|
-
|
|
31787
|
-
|
|
31788
|
-
|
|
31789
|
-
|
|
31790
|
-
|
|
31791
|
-
|
|
32190
|
+
const textSections = [
|
|
32191
|
+
`Found ${paginated.total} workflow files:`,
|
|
32192
|
+
formatListItems(paginated.items, (workflow) => {
|
|
32193
|
+
const formatTag = workflow.source_format === "webui" ? workflow.validation_status === "conversion_validated" ? "\u26A0\uFE0F Web UI graph (conversion validated)" : workflow.validation_status === "conversion_requires_node_schemas" ? "\u26A0\uFE0F Web UI graph (needs node schemas to validate)" : "\u274C Web UI graph (conversion failed)" : "\u2705 API workflow";
|
|
32194
|
+
let line = `[ID: ${workflow.id}] [${formatTag}] Name: "${workflow.name}"`;
|
|
32195
|
+
if (workflow.error) {
|
|
32196
|
+
line += ` (Validation error: ${workflow.error})`;
|
|
32197
|
+
}
|
|
32198
|
+
return line;
|
|
32199
|
+
})
|
|
32200
|
+
];
|
|
32201
|
+
if (skippedNonWorkflowFiles > 0) {
|
|
32202
|
+
textSections.push(
|
|
32203
|
+
`Skipped ${skippedNonWorkflowFiles} non-workflow JSON file(s).`
|
|
32204
|
+
);
|
|
32205
|
+
}
|
|
32206
|
+
if (objectInfoAvailability.warning) {
|
|
32207
|
+
textSections.push(objectInfoAvailability.warning);
|
|
32208
|
+
}
|
|
32209
|
+
if (paginated.hasMore) {
|
|
32210
|
+
textSections.push(
|
|
32211
|
+
formatPaginationFooter(
|
|
32212
|
+
paginated.offset,
|
|
32213
|
+
paginated.limit,
|
|
32214
|
+
paginated.total
|
|
32215
|
+
)
|
|
32216
|
+
);
|
|
32217
|
+
}
|
|
31792
32218
|
return {
|
|
31793
|
-
content: [{ type: "text", text }],
|
|
32219
|
+
content: [{ type: "text", text: textSections.join("\n\n") }],
|
|
31794
32220
|
structuredContent: {
|
|
31795
|
-
workflows: paginated.items
|
|
32221
|
+
workflows: paginated.items.map((workflow) => ({
|
|
32222
|
+
id: workflow.id,
|
|
32223
|
+
name: workflow.name,
|
|
32224
|
+
path: workflow.path,
|
|
32225
|
+
isWebUI: workflow.isWebUI,
|
|
32226
|
+
source_format: workflow.source_format,
|
|
32227
|
+
validation_status: workflow.validation_status,
|
|
32228
|
+
...workflow.error ? { error: workflow.error } : {}
|
|
32229
|
+
})),
|
|
32230
|
+
skipped_non_workflow_files: skippedNonWorkflowFiles,
|
|
31796
32231
|
pagination: {
|
|
31797
32232
|
total: paginated.total,
|
|
31798
32233
|
offset: paginated.offset,
|
|
@@ -31821,7 +32256,8 @@ async function waitForWorkflowResult(prompt_id, timeout_seconds) {
|
|
|
31821
32256
|
}
|
|
31822
32257
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
31823
32258
|
}
|
|
31824
|
-
|
|
32259
|
+
const queueSnapshot = await getQueueSnapshot();
|
|
32260
|
+
throw new WorkflowTimeoutError(prompt_id, timeout_seconds, queueSnapshot);
|
|
31825
32261
|
}
|
|
31826
32262
|
async function handleWaitForWorkflow(args) {
|
|
31827
32263
|
try {
|
|
@@ -31903,6 +32339,8 @@ async function handleGetWorkflow(args) {
|
|
|
31903
32339
|
objectInfoAvailability.objectInfo,
|
|
31904
32340
|
loadedWorkflow.widgetPathMap
|
|
31905
32341
|
);
|
|
32342
|
+
const highSignalInputs = getHighSignalEditableInputs(editableInputs);
|
|
32343
|
+
const editableInputGroups = summarizeEditableInputGroups(editableInputs);
|
|
31906
32344
|
const overrideExamples = buildOverrideExamples(editableInputs);
|
|
31907
32345
|
const workflowId = getWorkflowId(loadedWorkflow.targetPath);
|
|
31908
32346
|
const textSections = [
|
|
@@ -31913,7 +32351,13 @@ async function handleGetWorkflow(args) {
|
|
|
31913
32351
|
textSections.push(objectInfoAvailability.warning);
|
|
31914
32352
|
}
|
|
31915
32353
|
textSections.push(
|
|
31916
|
-
`
|
|
32354
|
+
`High-signal overrides (${highSignalInputs.length}):`,
|
|
32355
|
+
formatEditableInputsText(highSignalInputs, {
|
|
32356
|
+
includeOptions: true
|
|
32357
|
+
}),
|
|
32358
|
+
"Editable input groups:",
|
|
32359
|
+
formatEditableInputGroupsText(editableInputGroups),
|
|
32360
|
+
`Editable inputs (${editableInputs.length} total):`,
|
|
31917
32361
|
formatEditableInputsText(editableInputs),
|
|
31918
32362
|
"Copy-ready override example:",
|
|
31919
32363
|
formatOverrideExamplesText(overrideExamples.examples)
|
|
@@ -31924,6 +32368,8 @@ async function handleGetWorkflow(args) {
|
|
|
31924
32368
|
path: loadedWorkflow.targetPath,
|
|
31925
32369
|
source_format: loadedWorkflow.sourceFormat,
|
|
31926
32370
|
editable_inputs: editableInputs,
|
|
32371
|
+
high_signal_inputs: highSignalInputs,
|
|
32372
|
+
input_groups: editableInputGroups,
|
|
31927
32373
|
override_examples: overrideExamples.examples,
|
|
31928
32374
|
preferred_override_paths: overrideExamples.preferred_paths
|
|
31929
32375
|
};
|
|
@@ -32018,6 +32464,12 @@ async function handleSaveWorkflow(args) {
|
|
|
32018
32464
|
objectInfoAvailability.objectInfo,
|
|
32019
32465
|
widgetPathMap
|
|
32020
32466
|
);
|
|
32467
|
+
const highSignalInputs = getHighSignalEditableInputs(
|
|
32468
|
+
updatedEditableInputs
|
|
32469
|
+
);
|
|
32470
|
+
const editableInputGroups = summarizeEditableInputGroups(
|
|
32471
|
+
updatedEditableInputs
|
|
32472
|
+
);
|
|
32021
32473
|
const overrideExamples = buildOverrideExamples(updatedEditableInputs);
|
|
32022
32474
|
const workflowId = getWorkflowId(outputPath);
|
|
32023
32475
|
const structuredContent = {
|
|
@@ -32026,6 +32478,8 @@ async function handleSaveWorkflow(args) {
|
|
|
32026
32478
|
source_path: sourcePath,
|
|
32027
32479
|
overwritten: existedBeforeSave,
|
|
32028
32480
|
editable_inputs: updatedEditableInputs,
|
|
32481
|
+
high_signal_inputs: highSignalInputs,
|
|
32482
|
+
input_groups: editableInputGroups,
|
|
32029
32483
|
override_examples: overrideExamples.examples,
|
|
32030
32484
|
preferred_override_paths: overrideExamples.preferred_paths
|
|
32031
32485
|
};
|
|
@@ -32044,7 +32498,13 @@ async function handleSaveWorkflow(args) {
|
|
|
32044
32498
|
textSections.push(objectInfoAvailability.warning);
|
|
32045
32499
|
}
|
|
32046
32500
|
textSections.push(
|
|
32047
|
-
`
|
|
32501
|
+
`High-signal overrides (${highSignalInputs.length}):`,
|
|
32502
|
+
formatEditableInputsText(highSignalInputs, {
|
|
32503
|
+
includeOptions: true
|
|
32504
|
+
}),
|
|
32505
|
+
"Editable input groups:",
|
|
32506
|
+
formatEditableInputGroupsText(editableInputGroups),
|
|
32507
|
+
`Editable inputs (${updatedEditableInputs.length} total):`,
|
|
32048
32508
|
formatEditableInputsText(updatedEditableInputs),
|
|
32049
32509
|
"Copy-ready override example:",
|
|
32050
32510
|
formatOverrideExamplesText(overrideExamples.examples)
|
|
@@ -32098,6 +32558,11 @@ async function handleWorkflowRun(args) {
|
|
|
32098
32558
|
objectInfo
|
|
32099
32559
|
});
|
|
32100
32560
|
}
|
|
32561
|
+
const preflight = validatePromptPreflight(
|
|
32562
|
+
promptObj,
|
|
32563
|
+
objectInfo,
|
|
32564
|
+
loadedWorkflow.widgetPathMap
|
|
32565
|
+
);
|
|
32101
32566
|
const clientId = `mcp-${Date.now()}`;
|
|
32102
32567
|
const result = IS_MOCK ? MOCK_FIXTURES.prompt_response : await fetchComfyJson("/prompt", {
|
|
32103
32568
|
method: "POST",
|
|
@@ -32124,16 +32589,25 @@ async function handleWorkflowRun(args) {
|
|
|
32124
32589
|
timeout: args.timeout
|
|
32125
32590
|
});
|
|
32126
32591
|
}
|
|
32592
|
+
const queueSnapshot = await getQueueSnapshot();
|
|
32127
32593
|
return {
|
|
32128
32594
|
content: [
|
|
32129
32595
|
{
|
|
32130
32596
|
type: "text",
|
|
32131
|
-
text:
|
|
32132
|
-
|
|
32133
|
-
|
|
32597
|
+
text: [
|
|
32598
|
+
`Workflow submitted. prompt_id: ${result.prompt_id}.`,
|
|
32599
|
+
`ComfyUI queue number: ${result.number} (queue number is not an ETA).`,
|
|
32600
|
+
`Preflight checked ${preflight.checked_inputs} literal inputs (${preflight.combo_inputs} combo-backed).`,
|
|
32601
|
+
formatQueueSnapshotText(queueSnapshot),
|
|
32602
|
+
`To retrieve the final results or check its status later, use the 'comfyui_wait_for_workflow' tool with this prompt_id.`
|
|
32603
|
+
].filter((line) => line && line.length > 0).join("\n")
|
|
32134
32604
|
}
|
|
32135
32605
|
],
|
|
32136
|
-
structuredContent: {
|
|
32606
|
+
structuredContent: {
|
|
32607
|
+
...result,
|
|
32608
|
+
preflight,
|
|
32609
|
+
...queueSnapshot ? { queue: queueSnapshot } : {}
|
|
32610
|
+
}
|
|
32137
32611
|
};
|
|
32138
32612
|
} catch (error48) {
|
|
32139
32613
|
return handleComfyError(error48);
|