@fre4x/comfyui 1.1.0-beta.3 → 1.1.0-beta.6
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/index.js +801 -785
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3223,8 +3223,8 @@ var require_utils = __commonJS({
|
|
|
3223
3223
|
}
|
|
3224
3224
|
return ind;
|
|
3225
3225
|
}
|
|
3226
|
-
function removeDotSegments(
|
|
3227
|
-
let input =
|
|
3226
|
+
function removeDotSegments(path4) {
|
|
3227
|
+
let input = path4;
|
|
3228
3228
|
const output = [];
|
|
3229
3229
|
let nextSlash = -1;
|
|
3230
3230
|
let len = 0;
|
|
@@ -3423,8 +3423,8 @@ var require_schemes = __commonJS({
|
|
|
3423
3423
|
wsComponent.secure = void 0;
|
|
3424
3424
|
}
|
|
3425
3425
|
if (wsComponent.resourceName) {
|
|
3426
|
-
const [
|
|
3427
|
-
wsComponent.path =
|
|
3426
|
+
const [path4, query] = wsComponent.resourceName.split("?");
|
|
3427
|
+
wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
|
|
3428
3428
|
wsComponent.query = query;
|
|
3429
3429
|
wsComponent.resourceName = void 0;
|
|
3430
3430
|
}
|
|
@@ -6786,12 +6786,12 @@ var require_dist = __commonJS({
|
|
|
6786
6786
|
throw new Error(`Unknown format "${name}"`);
|
|
6787
6787
|
return f;
|
|
6788
6788
|
};
|
|
6789
|
-
function addFormats(ajv, list,
|
|
6789
|
+
function addFormats(ajv, list, fs4, exportName) {
|
|
6790
6790
|
var _a2;
|
|
6791
6791
|
var _b;
|
|
6792
6792
|
(_a2 = (_b = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
6793
6793
|
for (const f of list)
|
|
6794
|
-
ajv.addFormat(f,
|
|
6794
|
+
ajv.addFormat(f, fs4[f]);
|
|
6795
6795
|
}
|
|
6796
6796
|
module.exports = exports = formatsPlugin;
|
|
6797
6797
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -6800,11 +6800,9 @@ var require_dist = __commonJS({
|
|
|
6800
6800
|
});
|
|
6801
6801
|
|
|
6802
6802
|
// src/index.ts
|
|
6803
|
-
import * as
|
|
6804
|
-
import * as crypto from "node:crypto";
|
|
6803
|
+
import * as fs3 from "node:fs/promises";
|
|
6805
6804
|
import { realpathSync } from "node:fs";
|
|
6806
|
-
import
|
|
6807
|
-
import path from "node:path";
|
|
6805
|
+
import path3 from "node:path";
|
|
6808
6806
|
import { fileURLToPath } from "node:url";
|
|
6809
6807
|
|
|
6810
6808
|
// ../packages/shared/dist/errors.js
|
|
@@ -7873,10 +7871,10 @@ function mergeDefs(...defs) {
|
|
|
7873
7871
|
function cloneDef(schema) {
|
|
7874
7872
|
return mergeDefs(schema._zod.def);
|
|
7875
7873
|
}
|
|
7876
|
-
function getElementAtPath(obj,
|
|
7877
|
-
if (!
|
|
7874
|
+
function getElementAtPath(obj, path4) {
|
|
7875
|
+
if (!path4)
|
|
7878
7876
|
return obj;
|
|
7879
|
-
return
|
|
7877
|
+
return path4.reduce((acc, key) => acc?.[key], obj);
|
|
7880
7878
|
}
|
|
7881
7879
|
function promiseAllObject(promisesObj) {
|
|
7882
7880
|
const keys = Object.keys(promisesObj);
|
|
@@ -8259,11 +8257,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8259
8257
|
}
|
|
8260
8258
|
return false;
|
|
8261
8259
|
}
|
|
8262
|
-
function prefixIssues(
|
|
8260
|
+
function prefixIssues(path4, issues) {
|
|
8263
8261
|
return issues.map((iss) => {
|
|
8264
8262
|
var _a2;
|
|
8265
8263
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8266
|
-
iss.path.unshift(
|
|
8264
|
+
iss.path.unshift(path4);
|
|
8267
8265
|
return iss;
|
|
8268
8266
|
});
|
|
8269
8267
|
}
|
|
@@ -8446,7 +8444,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
8446
8444
|
}
|
|
8447
8445
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
8448
8446
|
const result = { errors: [] };
|
|
8449
|
-
const processError = (error49,
|
|
8447
|
+
const processError = (error49, path4 = []) => {
|
|
8450
8448
|
var _a2, _b;
|
|
8451
8449
|
for (const issue2 of error49.issues) {
|
|
8452
8450
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8456,7 +8454,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
8456
8454
|
} else if (issue2.code === "invalid_element") {
|
|
8457
8455
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8458
8456
|
} else {
|
|
8459
|
-
const fullpath = [...
|
|
8457
|
+
const fullpath = [...path4, ...issue2.path];
|
|
8460
8458
|
if (fullpath.length === 0) {
|
|
8461
8459
|
result.errors.push(mapper(issue2));
|
|
8462
8460
|
continue;
|
|
@@ -8488,8 +8486,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
8488
8486
|
}
|
|
8489
8487
|
function toDotPath(_path) {
|
|
8490
8488
|
const segs = [];
|
|
8491
|
-
const
|
|
8492
|
-
for (const seg of
|
|
8489
|
+
const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
8490
|
+
for (const seg of path4) {
|
|
8493
8491
|
if (typeof seg === "number")
|
|
8494
8492
|
segs.push(`[${seg}]`);
|
|
8495
8493
|
else if (typeof seg === "symbol")
|
|
@@ -20466,13 +20464,13 @@ function resolveRef(ref, ctx) {
|
|
|
20466
20464
|
if (!ref.startsWith("#")) {
|
|
20467
20465
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
20468
20466
|
}
|
|
20469
|
-
const
|
|
20470
|
-
if (
|
|
20467
|
+
const path4 = ref.slice(1).split("/").filter(Boolean);
|
|
20468
|
+
if (path4.length === 0) {
|
|
20471
20469
|
return ctx.rootSchema;
|
|
20472
20470
|
}
|
|
20473
20471
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
20474
|
-
if (
|
|
20475
|
-
const key =
|
|
20472
|
+
if (path4[0] === defsKey) {
|
|
20473
|
+
const key = path4[1];
|
|
20476
20474
|
if (!key || !ctx.defs[key]) {
|
|
20477
20475
|
throw new Error(`Reference not found: ${ref}`);
|
|
20478
20476
|
}
|
|
@@ -21264,8 +21262,8 @@ function getErrorMap2() {
|
|
|
21264
21262
|
|
|
21265
21263
|
// ../node_modules/zod/v3/helpers/parseUtil.js
|
|
21266
21264
|
var makeIssue = (params) => {
|
|
21267
|
-
const { data, path:
|
|
21268
|
-
const fullPath = [...
|
|
21265
|
+
const { data, path: path4, errorMaps, issueData } = params;
|
|
21266
|
+
const fullPath = [...path4, ...issueData.path || []];
|
|
21269
21267
|
const fullIssue = {
|
|
21270
21268
|
...issueData,
|
|
21271
21269
|
path: fullPath
|
|
@@ -21380,11 +21378,11 @@ var errorUtil;
|
|
|
21380
21378
|
|
|
21381
21379
|
// ../node_modules/zod/v3/types.js
|
|
21382
21380
|
var ParseInputLazyPath = class {
|
|
21383
|
-
constructor(parent, value,
|
|
21381
|
+
constructor(parent, value, path4, key) {
|
|
21384
21382
|
this._cachedPath = [];
|
|
21385
21383
|
this.parent = parent;
|
|
21386
21384
|
this.data = value;
|
|
21387
|
-
this._path =
|
|
21385
|
+
this._path = path4;
|
|
21388
21386
|
this._key = key;
|
|
21389
21387
|
}
|
|
21390
21388
|
get path() {
|
|
@@ -30427,6 +30425,37 @@ var StdioServerTransport = class {
|
|
|
30427
30425
|
}
|
|
30428
30426
|
};
|
|
30429
30427
|
|
|
30428
|
+
// src/errors.ts
|
|
30429
|
+
var ComfyApiError = class extends Error {
|
|
30430
|
+
constructor(message, statusCode, details) {
|
|
30431
|
+
super(message);
|
|
30432
|
+
this.statusCode = statusCode;
|
|
30433
|
+
this.details = details;
|
|
30434
|
+
this.name = "ComfyApiError";
|
|
30435
|
+
}
|
|
30436
|
+
};
|
|
30437
|
+
var WorkflowInputError = class extends Error {
|
|
30438
|
+
constructor(message, field, kind = "validation") {
|
|
30439
|
+
super(message);
|
|
30440
|
+
this.field = field;
|
|
30441
|
+
this.kind = kind;
|
|
30442
|
+
this.name = "WorkflowInputError";
|
|
30443
|
+
}
|
|
30444
|
+
};
|
|
30445
|
+
var WorkflowTimeoutError = class extends Error {
|
|
30446
|
+
constructor(promptId, timeoutSeconds, queueSnapshot) {
|
|
30447
|
+
super(`Timeout waiting for workflow ${promptId}`);
|
|
30448
|
+
this.promptId = promptId;
|
|
30449
|
+
this.timeoutSeconds = timeoutSeconds;
|
|
30450
|
+
this.queueSnapshot = queueSnapshot;
|
|
30451
|
+
this.name = "WorkflowTimeoutError";
|
|
30452
|
+
}
|
|
30453
|
+
};
|
|
30454
|
+
|
|
30455
|
+
// src/api.ts
|
|
30456
|
+
import * as fs from "node:fs/promises";
|
|
30457
|
+
import path from "node:path";
|
|
30458
|
+
|
|
30430
30459
|
// src/mock.ts
|
|
30431
30460
|
var IS_MOCK = process.env.MOCK === "true";
|
|
30432
30461
|
var MOCK_FIXTURES = {
|
|
@@ -30577,233 +30606,181 @@ var MOCK_FIXTURES = {
|
|
|
30577
30606
|
}
|
|
30578
30607
|
};
|
|
30579
30608
|
|
|
30580
|
-
// src/
|
|
30581
|
-
var
|
|
30582
|
-
|
|
30583
|
-
|
|
30584
|
-
|
|
30585
|
-
|
|
30586
|
-
|
|
30587
|
-
|
|
30588
|
-
|
|
30589
|
-
|
|
30609
|
+
// src/api.ts
|
|
30610
|
+
var COMFYUI_SERVER_URL = process.env.COMFYUI_SERVER_URL || "http://localhost:8188";
|
|
30611
|
+
async function fetchComfyJson(apiPath, options) {
|
|
30612
|
+
const url2 = new URL(apiPath, COMFYUI_SERVER_URL).toString();
|
|
30613
|
+
let response;
|
|
30614
|
+
try {
|
|
30615
|
+
response = await fetch(url2, {
|
|
30616
|
+
...options,
|
|
30617
|
+
headers: {
|
|
30618
|
+
Accept: "application/json",
|
|
30619
|
+
...options?.headers || {}
|
|
30620
|
+
}
|
|
30621
|
+
});
|
|
30622
|
+
} catch (error48) {
|
|
30623
|
+
throw new Error(
|
|
30624
|
+
`Failed to connect to ComfyUI server at ${COMFYUI_SERVER_URL}: ${error48 instanceof Error ? error48.message : String(error48)}`
|
|
30625
|
+
);
|
|
30626
|
+
}
|
|
30627
|
+
if (response.status === 404) {
|
|
30628
|
+
throw new ComfyApiError(`Not found: ${apiPath}`, 404, null);
|
|
30629
|
+
}
|
|
30630
|
+
const text = await response.text();
|
|
30631
|
+
let body;
|
|
30632
|
+
try {
|
|
30633
|
+
body = text ? JSON.parse(text) : null;
|
|
30634
|
+
} catch {
|
|
30635
|
+
throw new ComfyApiError(
|
|
30636
|
+
`Invalid JSON response from ComfyUI: ${text.slice(0, 100)}`,
|
|
30637
|
+
response.status,
|
|
30638
|
+
text
|
|
30639
|
+
);
|
|
30640
|
+
}
|
|
30641
|
+
if (!response.ok) {
|
|
30642
|
+
throw new ComfyApiError(
|
|
30643
|
+
"The ComfyUI service returned an error.",
|
|
30644
|
+
response.status,
|
|
30645
|
+
body
|
|
30646
|
+
);
|
|
30647
|
+
}
|
|
30648
|
+
return body;
|
|
30590
30649
|
}
|
|
30591
|
-
function
|
|
30592
|
-
|
|
30650
|
+
async function fetchImageAsset(filename, type, subfolder) {
|
|
30651
|
+
const params = new URLSearchParams({ filename, type });
|
|
30652
|
+
if (subfolder) params.set("subfolder", subfolder);
|
|
30653
|
+
const url2 = new URL(
|
|
30654
|
+
`/view?${params.toString()}`,
|
|
30655
|
+
COMFYUI_SERVER_URL
|
|
30656
|
+
).toString();
|
|
30657
|
+
const response = await fetch(url2);
|
|
30658
|
+
if (!response.ok)
|
|
30659
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
30660
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
30661
|
+
const mimeType = response.headers.get("content-type") || "image/png";
|
|
30662
|
+
return {
|
|
30663
|
+
buffer: Buffer.from(arrayBuffer),
|
|
30664
|
+
mimeType
|
|
30665
|
+
};
|
|
30593
30666
|
}
|
|
30594
|
-
function
|
|
30595
|
-
return
|
|
30667
|
+
function createMockImageAsset() {
|
|
30668
|
+
return {
|
|
30669
|
+
buffer: Buffer.from("mock-image-data"),
|
|
30670
|
+
mimeType: "image/png"
|
|
30671
|
+
};
|
|
30596
30672
|
}
|
|
30597
|
-
function
|
|
30598
|
-
|
|
30599
|
-
|
|
30600
|
-
|
|
30601
|
-
|
|
30602
|
-
|
|
30603
|
-
|
|
30604
|
-
|
|
30605
|
-
|
|
30606
|
-
|
|
30607
|
-
|
|
30608
|
-
|
|
30609
|
-
|
|
30610
|
-
|
|
30611
|
-
|
|
30612
|
-
if (seen.has(inputName)) {
|
|
30613
|
-
continue;
|
|
30614
|
-
}
|
|
30615
|
-
orderedEntries.push([inputName, inputDefinition]);
|
|
30673
|
+
function getSessionWorkspaceDir() {
|
|
30674
|
+
return process.env.MCP_WORKSPACE_DIR;
|
|
30675
|
+
}
|
|
30676
|
+
function getSafePathSegments(subfolder) {
|
|
30677
|
+
if (!subfolder) return [];
|
|
30678
|
+
return subfolder.split(/[/\\]/).filter((s) => s.length > 0 && s !== ".." && s !== ".");
|
|
30679
|
+
}
|
|
30680
|
+
function sanitizePathSegment(value, fallback) {
|
|
30681
|
+
const normalized = value.trim().replace(/[\\/]+/g, "_").replace(/\.\.+/g, "_").replace(/_+/g, "_").replace(/[^A-Za-z0-9._-]/g, "_");
|
|
30682
|
+
return normalized.length > 0 ? normalized : fallback;
|
|
30683
|
+
}
|
|
30684
|
+
async function saveToWorkspace(promptId, image, asset) {
|
|
30685
|
+
const workspaceDir = getSessionWorkspaceDir();
|
|
30686
|
+
if (!workspaceDir) {
|
|
30687
|
+
return void 0;
|
|
30616
30688
|
}
|
|
30617
|
-
|
|
30689
|
+
const safePromptId = sanitizePathSegment(promptId, "unknown-prompt");
|
|
30690
|
+
const safeFileName = path.basename(image.filename);
|
|
30691
|
+
const safeSubfolderSegments = getSafePathSegments(image.subfolder);
|
|
30692
|
+
const relativePath = path.join(
|
|
30693
|
+
"comfyui",
|
|
30694
|
+
safePromptId,
|
|
30695
|
+
...safeSubfolderSegments,
|
|
30696
|
+
safeFileName
|
|
30697
|
+
);
|
|
30698
|
+
const workspacePath = path.join(workspaceDir, relativePath);
|
|
30699
|
+
await fs.mkdir(path.dirname(workspacePath), { recursive: true });
|
|
30700
|
+
await fs.writeFile(workspacePath, asset.buffer);
|
|
30701
|
+
return {
|
|
30702
|
+
workspace_path: workspacePath,
|
|
30703
|
+
relative_path: relativePath,
|
|
30704
|
+
filename: safeFileName,
|
|
30705
|
+
mime_type: asset.mimeType,
|
|
30706
|
+
subfolder: image.subfolder
|
|
30707
|
+
};
|
|
30618
30708
|
}
|
|
30619
|
-
function
|
|
30620
|
-
return
|
|
30709
|
+
async function getObjectInfo() {
|
|
30710
|
+
return IS_MOCK ? MOCK_FIXTURES.object_info : await fetchComfyJson("/object_info");
|
|
30621
30711
|
}
|
|
30622
|
-
function
|
|
30623
|
-
|
|
30624
|
-
return typeName === "COMBO" || WIDGET_TYPES.has(typeName);
|
|
30712
|
+
function summarizeErrorMessage(error48) {
|
|
30713
|
+
return error48 instanceof Error ? error48.message : String(error48);
|
|
30625
30714
|
}
|
|
30626
|
-
function
|
|
30627
|
-
|
|
30628
|
-
return
|
|
30715
|
+
async function tryGetObjectInfo() {
|
|
30716
|
+
try {
|
|
30717
|
+
return {
|
|
30718
|
+
objectInfo: await getObjectInfo()
|
|
30719
|
+
};
|
|
30720
|
+
} catch (error48) {
|
|
30721
|
+
return {
|
|
30722
|
+
warning: `Node schema details unavailable from ComfyUI: ${summarizeErrorMessage(
|
|
30723
|
+
error48
|
|
30724
|
+
)}`
|
|
30725
|
+
};
|
|
30629
30726
|
}
|
|
30630
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30631
30727
|
}
|
|
30632
|
-
function
|
|
30633
|
-
|
|
30634
|
-
|
|
30635
|
-
|
|
30636
|
-
return
|
|
30728
|
+
async function getQueueSnapshot() {
|
|
30729
|
+
try {
|
|
30730
|
+
return IS_MOCK ? MOCK_FIXTURES.queue : await fetchComfyJson("/queue");
|
|
30731
|
+
} catch {
|
|
30732
|
+
return void 0;
|
|
30637
30733
|
}
|
|
30638
|
-
return value;
|
|
30639
30734
|
}
|
|
30640
|
-
function
|
|
30641
|
-
|
|
30642
|
-
|
|
30643
|
-
const links = webUIJson.links || [];
|
|
30644
|
-
const nodes = webUIJson.nodes || [];
|
|
30645
|
-
const serverNodeIds = /* @__PURE__ */ new Set();
|
|
30646
|
-
for (const node of nodes) {
|
|
30647
|
-
if (!node.id || !node.type || !objectInfo[node.type]) {
|
|
30648
|
-
continue;
|
|
30649
|
-
}
|
|
30650
|
-
serverNodeIds.add(String(node.id));
|
|
30735
|
+
function formatQueueSnapshotText(queueSnapshot) {
|
|
30736
|
+
if (!queueSnapshot) {
|
|
30737
|
+
return "";
|
|
30651
30738
|
}
|
|
30652
|
-
|
|
30653
|
-
|
|
30654
|
-
|
|
30655
|
-
|
|
30656
|
-
|
|
30739
|
+
return `Queue snapshot: ${queueSnapshot.queue_running.length} running, ${queueSnapshot.queue_pending.length} pending.`;
|
|
30740
|
+
}
|
|
30741
|
+
function getPromptQueueVisibility(promptId, queueSnapshot) {
|
|
30742
|
+
if (!queueSnapshot) {
|
|
30743
|
+
return null;
|
|
30657
30744
|
}
|
|
30658
|
-
|
|
30659
|
-
|
|
30660
|
-
|
|
30661
|
-
|
|
30662
|
-
|
|
30663
|
-
|
|
30664
|
-
|
|
30665
|
-
|
|
30666
|
-
|
|
30667
|
-
|
|
30668
|
-
|
|
30669
|
-
|
|
30670
|
-
|
|
30671
|
-
|
|
30672
|
-
if (Array.isArray(linkData) && linkData.length >= 6 && String(linkData[3]) === nodeIdStr) {
|
|
30673
|
-
const originNodeId = String(linkData[1]);
|
|
30674
|
-
const originSlot = linkData[2];
|
|
30675
|
-
promptNode.inputs[input.name] = [
|
|
30676
|
-
originNodeId,
|
|
30677
|
-
originSlot
|
|
30678
|
-
];
|
|
30679
|
-
connectedInputNames.add(input.name);
|
|
30680
|
-
}
|
|
30681
|
-
}
|
|
30745
|
+
return JSON.stringify(queueSnapshot).includes(promptId);
|
|
30746
|
+
}
|
|
30747
|
+
async function waitForWorkflowResult(prompt_id, timeout_seconds) {
|
|
30748
|
+
const start = Date.now();
|
|
30749
|
+
const end = start + timeout_seconds * 1e3;
|
|
30750
|
+
while (Date.now() < end) {
|
|
30751
|
+
let history = MOCK_FIXTURES.history;
|
|
30752
|
+
if (!IS_MOCK) {
|
|
30753
|
+
try {
|
|
30754
|
+
history = await fetchComfyJson(
|
|
30755
|
+
`/history/${prompt_id}`
|
|
30756
|
+
);
|
|
30757
|
+
} catch {
|
|
30758
|
+
history = {};
|
|
30682
30759
|
}
|
|
30683
30760
|
}
|
|
30684
|
-
if (
|
|
30685
|
-
|
|
30686
|
-
let widgetIndex = 0;
|
|
30687
|
-
const processInputGroup = (group, orderedNames) => {
|
|
30688
|
-
for (const [inputName, inputDataRaw] of getOrderedInputEntries(
|
|
30689
|
-
group,
|
|
30690
|
-
orderedNames
|
|
30691
|
-
)) {
|
|
30692
|
-
const [inputTypeData, inputExtraInfo] = inputDataRaw;
|
|
30693
|
-
if (!isWidgetInput(inputTypeData)) {
|
|
30694
|
-
continue;
|
|
30695
|
-
}
|
|
30696
|
-
const typeName = getWidgetTypeName(inputTypeData);
|
|
30697
|
-
while (widgetIndex < widgets.length && isSkippableUiArtifact(widgets[widgetIndex], typeName)) {
|
|
30698
|
-
widgetIndex++;
|
|
30699
|
-
}
|
|
30700
|
-
const isConnectedWidget = connectedInputNames.has(inputName);
|
|
30701
|
-
if (widgetIndex >= widgets.length) {
|
|
30702
|
-
if (!isConnectedWidget && inputExtraInfo?.default !== void 0) {
|
|
30703
|
-
promptNode.inputs[inputName] = inputExtraInfo.default;
|
|
30704
|
-
}
|
|
30705
|
-
continue;
|
|
30706
|
-
}
|
|
30707
|
-
const widgetSourceIndex = widgetIndex;
|
|
30708
|
-
const value = normalizeWidgetValue(
|
|
30709
|
-
widgets[widgetSourceIndex],
|
|
30710
|
-
typeName,
|
|
30711
|
-
inputExtraInfo
|
|
30712
|
-
);
|
|
30713
|
-
widgetIndex++;
|
|
30714
|
-
if (!isConnectedWidget) {
|
|
30715
|
-
promptNode.inputs[inputName] = value;
|
|
30716
|
-
widgetPathMap[`${nodeIdStr}.widgets[${widgetSourceIndex}]`] = `${nodeIdStr}.inputs.${inputName}`;
|
|
30717
|
-
}
|
|
30718
|
-
}
|
|
30719
|
-
};
|
|
30720
|
-
processInputGroup(
|
|
30721
|
-
objInfo.input?.required,
|
|
30722
|
-
objInfo.input_order?.required
|
|
30723
|
-
);
|
|
30724
|
-
processInputGroup(
|
|
30725
|
-
objInfo.input?.optional,
|
|
30726
|
-
objInfo.input_order?.optional
|
|
30727
|
-
);
|
|
30761
|
+
if (history?.[prompt_id]) {
|
|
30762
|
+
return history[prompt_id];
|
|
30728
30763
|
}
|
|
30729
|
-
|
|
30764
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
30730
30765
|
}
|
|
30731
|
-
|
|
30732
|
-
|
|
30733
|
-
widgetPathMap
|
|
30734
|
-
};
|
|
30766
|
+
const queueSnapshot = await getQueueSnapshot();
|
|
30767
|
+
throw new WorkflowTimeoutError(prompt_id, timeout_seconds, queueSnapshot);
|
|
30735
30768
|
}
|
|
30736
30769
|
|
|
30737
|
-
// src/
|
|
30738
|
-
|
|
30739
|
-
var z3 = zNamespace.z ?? zNamespace.default ?? zNamespace;
|
|
30740
|
-
var COMFYUI_SERVER_URL = process.env.COMFYUI_SERVER_URL || "http://localhost:8188";
|
|
30741
|
-
var PACKAGE_VERSION = getPackageVersion(import.meta.url);
|
|
30742
|
-
var ComfyApiError = class extends Error {
|
|
30743
|
-
constructor(message, statusCode, details) {
|
|
30744
|
-
super(message);
|
|
30745
|
-
this.statusCode = statusCode;
|
|
30746
|
-
this.details = details;
|
|
30747
|
-
this.name = "ComfyApiError";
|
|
30748
|
-
}
|
|
30749
|
-
};
|
|
30750
|
-
var WorkflowInputError = class extends Error {
|
|
30751
|
-
constructor(message, field, kind = "validation") {
|
|
30752
|
-
super(message);
|
|
30753
|
-
this.field = field;
|
|
30754
|
-
this.kind = kind;
|
|
30755
|
-
this.name = "WorkflowInputError";
|
|
30756
|
-
}
|
|
30757
|
-
};
|
|
30758
|
-
var INPUT_SEGMENT = "inputs";
|
|
30759
|
-
var OverrideRecordSchema = z3.record(z3.string(), z3.unknown());
|
|
30760
|
-
var OverridesSchema = z3.union([OverrideRecordSchema, z3.string()]).describe(
|
|
30761
|
-
'Dot-notation overrides as an object or JSON string. e.g. {"6.seed": 7}'
|
|
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
|
-
};
|
|
30772
|
-
function isRecord2(value) {
|
|
30770
|
+
// src/workflow/common.ts
|
|
30771
|
+
function isRecord(value) {
|
|
30773
30772
|
return typeof value === "object" && value !== null;
|
|
30774
30773
|
}
|
|
30775
|
-
function isComfyPromptNode(value) {
|
|
30776
|
-
return isRecord2(value) && typeof value.class_type === "string" && isRecord2(value.inputs);
|
|
30777
|
-
}
|
|
30778
|
-
function isUiOnlyPromptNode(nodeId, node) {
|
|
30779
|
-
return nodeId === "meta" || ["Note", "MarkdownNote", "PrimitiveNode"].includes(node.class_type);
|
|
30780
|
-
}
|
|
30781
|
-
function extractRunnablePromptNodes(prompt) {
|
|
30782
|
-
const runnablePrompt = {};
|
|
30783
|
-
for (const [nodeId, rawNode] of Object.entries(prompt)) {
|
|
30784
|
-
if (!isComfyPromptNode(rawNode) || isUiOnlyPromptNode(nodeId, rawNode)) {
|
|
30785
|
-
continue;
|
|
30786
|
-
}
|
|
30787
|
-
runnablePrompt[nodeId] = rawNode;
|
|
30788
|
-
}
|
|
30789
|
-
if (Object.keys(runnablePrompt).length === 0) {
|
|
30790
|
-
throw new WorkflowInputError(
|
|
30791
|
-
"Workflow prompt does not contain any runnable ComfyUI nodes.",
|
|
30792
|
-
"workflow"
|
|
30793
|
-
);
|
|
30794
|
-
}
|
|
30795
|
-
return runnablePrompt;
|
|
30796
|
-
}
|
|
30797
30774
|
function toStructuredContent(value) {
|
|
30798
|
-
return
|
|
30775
|
+
return isRecord(value) ? value : {};
|
|
30799
30776
|
}
|
|
30800
30777
|
function summarizeNodeErrors(nodeErrors) {
|
|
30801
|
-
if (!
|
|
30778
|
+
if (!isRecord(nodeErrors)) {
|
|
30802
30779
|
return [];
|
|
30803
30780
|
}
|
|
30804
30781
|
const lines = [];
|
|
30805
30782
|
for (const [nodeId, rawNodeError] of Object.entries(nodeErrors)) {
|
|
30806
|
-
if (!
|
|
30783
|
+
if (!isRecord(rawNodeError)) {
|
|
30807
30784
|
continue;
|
|
30808
30785
|
}
|
|
30809
30786
|
const classType = typeof rawNodeError.class_type === "string" ? ` (${rawNodeError.class_type})` : "";
|
|
@@ -30811,7 +30788,7 @@ function summarizeNodeErrors(nodeErrors) {
|
|
|
30811
30788
|
const missingInputs = [];
|
|
30812
30789
|
const otherMessages = [];
|
|
30813
30790
|
for (const rawError of rawErrors) {
|
|
30814
|
-
if (!
|
|
30791
|
+
if (!isRecord(rawError)) {
|
|
30815
30792
|
continue;
|
|
30816
30793
|
}
|
|
30817
30794
|
const errorType = rawError.type;
|
|
@@ -30841,11 +30818,11 @@ function summarizeNodeErrors(nodeErrors) {
|
|
|
30841
30818
|
return lines;
|
|
30842
30819
|
}
|
|
30843
30820
|
function summarizeComfyErrorDetails(details) {
|
|
30844
|
-
if (!
|
|
30821
|
+
if (!isRecord(details)) {
|
|
30845
30822
|
return "";
|
|
30846
30823
|
}
|
|
30847
30824
|
const lines = [];
|
|
30848
|
-
const errorDetails =
|
|
30825
|
+
const errorDetails = isRecord(details.error) ? details.error : void 0;
|
|
30849
30826
|
if (typeof errorDetails?.message === "string") {
|
|
30850
30827
|
lines.push(errorDetails.message);
|
|
30851
30828
|
} else if (typeof details.message === "string") {
|
|
@@ -30864,159 +30841,260 @@ function formatWorkflowNodeErrors(nodeErrors) {
|
|
|
30864
30841
|
}
|
|
30865
30842
|
return ["Workflow submission failed validation.", ...nodeLines].join("\n");
|
|
30866
30843
|
}
|
|
30867
|
-
|
|
30868
|
-
|
|
30869
|
-
|
|
30870
|
-
try {
|
|
30871
|
-
response = await fetch(url2, {
|
|
30872
|
-
...options,
|
|
30873
|
-
headers: {
|
|
30874
|
-
Accept: "application/json",
|
|
30875
|
-
...options?.headers || {}
|
|
30876
|
-
}
|
|
30877
|
-
});
|
|
30878
|
-
} catch (error48) {
|
|
30879
|
-
throw new Error(
|
|
30880
|
-
`Failed to connect to ComfyUI server at ${COMFYUI_SERVER_URL}: ${error48 instanceof Error ? error48.message : String(error48)}`
|
|
30881
|
-
);
|
|
30882
|
-
}
|
|
30883
|
-
if (response.status === 404) {
|
|
30884
|
-
throw new ComfyApiError(`Not found: ${apiPath}`, 404, null);
|
|
30844
|
+
function formatValuePreview(value) {
|
|
30845
|
+
if (typeof value === "string") {
|
|
30846
|
+
return value.length > 100 ? `${value.slice(0, 97)}...` : value;
|
|
30885
30847
|
}
|
|
30886
|
-
const text = await response.text();
|
|
30887
|
-
let body;
|
|
30888
30848
|
try {
|
|
30889
|
-
|
|
30849
|
+
const serialized = JSON.stringify(value);
|
|
30850
|
+
if (!serialized) {
|
|
30851
|
+
return String(value);
|
|
30852
|
+
}
|
|
30853
|
+
return serialized.length > 100 ? `${serialized.slice(0, 97)}...` : serialized;
|
|
30890
30854
|
} catch {
|
|
30891
|
-
|
|
30892
|
-
`Invalid JSON response from ComfyUI: ${text.slice(0, 100)}`,
|
|
30893
|
-
response.status,
|
|
30894
|
-
text
|
|
30895
|
-
);
|
|
30855
|
+
return String(value);
|
|
30896
30856
|
}
|
|
30897
|
-
|
|
30898
|
-
|
|
30899
|
-
|
|
30900
|
-
|
|
30901
|
-
body
|
|
30902
|
-
);
|
|
30857
|
+
}
|
|
30858
|
+
function getInputDefinition(objectInfo, prompt, nodeId, inputName) {
|
|
30859
|
+
if (!objectInfo) {
|
|
30860
|
+
return void 0;
|
|
30903
30861
|
}
|
|
30904
|
-
|
|
30862
|
+
const node = prompt[nodeId];
|
|
30863
|
+
if (!node) {
|
|
30864
|
+
return void 0;
|
|
30865
|
+
}
|
|
30866
|
+
const nodeDefinition = objectInfo[node.class_type];
|
|
30867
|
+
if (!nodeDefinition) {
|
|
30868
|
+
return void 0;
|
|
30869
|
+
}
|
|
30870
|
+
return nodeDefinition.input?.required?.[inputName] ?? nodeDefinition.input?.optional?.[inputName];
|
|
30905
30871
|
}
|
|
30906
|
-
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
30911
|
-
|
|
30912
|
-
).toString();
|
|
30913
|
-
const response = await fetch(url2);
|
|
30914
|
-
if (!response.ok)
|
|
30915
|
-
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
30916
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
30917
|
-
const mimeType = response.headers.get("content-type") || "image/png";
|
|
30918
|
-
return {
|
|
30919
|
-
buffer: Buffer.from(arrayBuffer),
|
|
30920
|
-
mimeType
|
|
30921
|
-
};
|
|
30872
|
+
function getExpectedTypeName(inputDefinition) {
|
|
30873
|
+
if (!inputDefinition) {
|
|
30874
|
+
return void 0;
|
|
30875
|
+
}
|
|
30876
|
+
const [typeData] = inputDefinition;
|
|
30877
|
+
return Array.isArray(typeData) ? "COMBO" : String(typeData).toUpperCase();
|
|
30922
30878
|
}
|
|
30923
|
-
function
|
|
30879
|
+
function getInputOptionsSummary(inputDefinition, previewLimit = 8) {
|
|
30880
|
+
if (!inputDefinition) {
|
|
30881
|
+
return void 0;
|
|
30882
|
+
}
|
|
30883
|
+
const [typeData] = inputDefinition;
|
|
30884
|
+
if (!Array.isArray(typeData)) {
|
|
30885
|
+
return void 0;
|
|
30886
|
+
}
|
|
30924
30887
|
return {
|
|
30925
|
-
|
|
30926
|
-
|
|
30888
|
+
options_count: typeData.length,
|
|
30889
|
+
options_preview: typeData.slice(0, previewLimit),
|
|
30890
|
+
options_truncated: typeData.length > previewLimit
|
|
30927
30891
|
};
|
|
30928
30892
|
}
|
|
30929
|
-
function
|
|
30930
|
-
return
|
|
30893
|
+
function isPlainObject3(value) {
|
|
30894
|
+
return isRecord(value) && !Array.isArray(value);
|
|
30931
30895
|
}
|
|
30932
|
-
function
|
|
30933
|
-
if (
|
|
30934
|
-
|
|
30896
|
+
function getValueTypeName(value) {
|
|
30897
|
+
if (Array.isArray(value)) {
|
|
30898
|
+
return "array";
|
|
30899
|
+
}
|
|
30900
|
+
if (value === null) {
|
|
30901
|
+
return "null";
|
|
30902
|
+
}
|
|
30903
|
+
return typeof value;
|
|
30935
30904
|
}
|
|
30936
|
-
|
|
30937
|
-
|
|
30938
|
-
|
|
30939
|
-
|
|
30905
|
+
|
|
30906
|
+
// src/workflow/load.ts
|
|
30907
|
+
import * as fs2 from "node:fs/promises";
|
|
30908
|
+
import * as crypto from "node:crypto";
|
|
30909
|
+
import { homedir } from "node:os";
|
|
30910
|
+
import path2 from "node:path";
|
|
30911
|
+
|
|
30912
|
+
// src/converter.ts
|
|
30913
|
+
var WIDGET_TYPES = /* @__PURE__ */ new Set(["INT", "FLOAT", "STRING", "BOOLEAN"]);
|
|
30914
|
+
var UI_CONTROL_VALUES = /* @__PURE__ */ new Set([
|
|
30915
|
+
"fixed",
|
|
30916
|
+
"increment",
|
|
30917
|
+
"decrement",
|
|
30918
|
+
"randomize"
|
|
30919
|
+
]);
|
|
30920
|
+
function isRecord2(value) {
|
|
30921
|
+
return typeof value === "object" && value !== null;
|
|
30922
|
+
}
|
|
30923
|
+
function isWebUIFormat(json2) {
|
|
30924
|
+
return isRecord2(json2) && Array.isArray(json2.nodes) && Array.isArray(json2.links);
|
|
30925
|
+
}
|
|
30926
|
+
function isLinkData(link) {
|
|
30927
|
+
return Array.isArray(link) && link.length >= 6 && typeof link[0] === "number" && typeof link[1] === "number" && typeof link[2] === "number" && typeof link[3] === "number" && typeof link[4] === "number" && typeof link[5] === "string";
|
|
30928
|
+
}
|
|
30929
|
+
function getOrderedInputEntries(group, orderedNames) {
|
|
30930
|
+
if (!group) {
|
|
30931
|
+
return [];
|
|
30940
30932
|
}
|
|
30941
|
-
const
|
|
30942
|
-
const
|
|
30943
|
-
const
|
|
30944
|
-
|
|
30945
|
-
|
|
30946
|
-
|
|
30947
|
-
|
|
30948
|
-
|
|
30949
|
-
|
|
30950
|
-
|
|
30951
|
-
|
|
30952
|
-
|
|
30953
|
-
|
|
30954
|
-
|
|
30955
|
-
|
|
30956
|
-
|
|
30957
|
-
|
|
30958
|
-
};
|
|
30933
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30934
|
+
const orderedEntries = [];
|
|
30935
|
+
for (const inputName of orderedNames ?? []) {
|
|
30936
|
+
const inputDefinition = group[inputName];
|
|
30937
|
+
if (!inputDefinition) {
|
|
30938
|
+
continue;
|
|
30939
|
+
}
|
|
30940
|
+
orderedEntries.push([inputName, inputDefinition]);
|
|
30941
|
+
seen.add(inputName);
|
|
30942
|
+
}
|
|
30943
|
+
for (const [inputName, inputDefinition] of Object.entries(group)) {
|
|
30944
|
+
if (seen.has(inputName)) {
|
|
30945
|
+
continue;
|
|
30946
|
+
}
|
|
30947
|
+
orderedEntries.push([inputName, inputDefinition]);
|
|
30948
|
+
}
|
|
30949
|
+
return orderedEntries;
|
|
30959
30950
|
}
|
|
30960
|
-
function
|
|
30961
|
-
|
|
30962
|
-
|
|
30963
|
-
|
|
30964
|
-
|
|
30965
|
-
|
|
30951
|
+
function getWidgetTypeName(inputTypeData) {
|
|
30952
|
+
return Array.isArray(inputTypeData) ? "COMBO" : String(inputTypeData).toUpperCase();
|
|
30953
|
+
}
|
|
30954
|
+
function isWidgetInput(inputTypeData) {
|
|
30955
|
+
const typeName = getWidgetTypeName(inputTypeData);
|
|
30956
|
+
return typeName === "COMBO" || WIDGET_TYPES.has(typeName);
|
|
30957
|
+
}
|
|
30958
|
+
function isSkippableUiArtifact(value, expectedTypeName) {
|
|
30959
|
+
if (expectedTypeName !== "STRING" && typeof value === "string" && UI_CONTROL_VALUES.has(value)) {
|
|
30960
|
+
return true;
|
|
30966
30961
|
}
|
|
30967
|
-
|
|
30968
|
-
|
|
30962
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30963
|
+
}
|
|
30964
|
+
function normalizeWidgetValue(value, typeName, extraInfo) {
|
|
30965
|
+
const defaultValue = extraInfo?.default;
|
|
30966
|
+
const shouldUseDefaultForNumeric = (typeName === "INT" || typeName === "FLOAT") && (value === "" || value === void 0 || value === null);
|
|
30967
|
+
if (shouldUseDefaultForNumeric && defaultValue !== void 0) {
|
|
30968
|
+
return defaultValue;
|
|
30969
|
+
}
|
|
30970
|
+
return value;
|
|
30971
|
+
}
|
|
30972
|
+
function convertWebUIToAPIWithMetadata(webUIJson, objectInfo) {
|
|
30973
|
+
const prompt = {};
|
|
30974
|
+
const widgetPathMap = {};
|
|
30975
|
+
const links = webUIJson.links || [];
|
|
30976
|
+
const nodes = webUIJson.nodes || [];
|
|
30977
|
+
const serverNodeIds = /* @__PURE__ */ new Set();
|
|
30978
|
+
for (const node of nodes) {
|
|
30979
|
+
if (!node.id || !node.type || !objectInfo[node.type]) {
|
|
30980
|
+
continue;
|
|
30981
|
+
}
|
|
30982
|
+
serverNodeIds.add(String(node.id));
|
|
30983
|
+
}
|
|
30984
|
+
const linkMap = /* @__PURE__ */ new Map();
|
|
30985
|
+
for (const link of links) {
|
|
30986
|
+
if (isLinkData(link) && serverNodeIds.has(String(link[3]))) {
|
|
30987
|
+
linkMap.set(link[0], link);
|
|
30988
|
+
}
|
|
30989
|
+
}
|
|
30990
|
+
for (const node of nodes) {
|
|
30991
|
+
if (!node.id || !node.type) continue;
|
|
30992
|
+
const objInfo = objectInfo[node.type];
|
|
30993
|
+
if (!objInfo) continue;
|
|
30994
|
+
const nodeIdStr = String(node.id);
|
|
30995
|
+
const promptNode = {
|
|
30996
|
+
class_type: node.type,
|
|
30997
|
+
inputs: {}
|
|
30998
|
+
};
|
|
30999
|
+
const connectedInputNames = /* @__PURE__ */ new Set();
|
|
31000
|
+
if (Array.isArray(node.inputs)) {
|
|
31001
|
+
for (const input of node.inputs) {
|
|
31002
|
+
if (input.name && input.link !== null && input.link !== void 0) {
|
|
31003
|
+
const linkData = linkMap.get(input.link);
|
|
31004
|
+
if (Array.isArray(linkData) && linkData.length >= 6 && String(linkData[3]) === nodeIdStr) {
|
|
31005
|
+
const originNodeId = String(linkData[1]);
|
|
31006
|
+
const originSlot = linkData[2];
|
|
31007
|
+
promptNode.inputs[input.name] = [
|
|
31008
|
+
originNodeId,
|
|
31009
|
+
originSlot
|
|
31010
|
+
];
|
|
31011
|
+
connectedInputNames.add(input.name);
|
|
31012
|
+
}
|
|
31013
|
+
}
|
|
31014
|
+
}
|
|
31015
|
+
}
|
|
31016
|
+
if (objInfo) {
|
|
31017
|
+
const widgets = Array.isArray(node.widgets_values) ? node.widgets_values : [];
|
|
31018
|
+
let widgetIndex = 0;
|
|
31019
|
+
const processInputGroup = (group, orderedNames) => {
|
|
31020
|
+
for (const [inputName, inputDataRaw] of getOrderedInputEntries(
|
|
31021
|
+
group,
|
|
31022
|
+
orderedNames
|
|
31023
|
+
)) {
|
|
31024
|
+
const [inputTypeData, inputExtraInfo] = inputDataRaw;
|
|
31025
|
+
if (!isWidgetInput(inputTypeData)) {
|
|
31026
|
+
continue;
|
|
31027
|
+
}
|
|
31028
|
+
const typeName = getWidgetTypeName(inputTypeData);
|
|
31029
|
+
while (widgetIndex < widgets.length && isSkippableUiArtifact(widgets[widgetIndex], typeName)) {
|
|
31030
|
+
widgetIndex++;
|
|
31031
|
+
}
|
|
31032
|
+
const isConnectedWidget = connectedInputNames.has(inputName);
|
|
31033
|
+
if (widgetIndex >= widgets.length) {
|
|
31034
|
+
if (!isConnectedWidget && inputExtraInfo?.default !== void 0) {
|
|
31035
|
+
promptNode.inputs[inputName] = inputExtraInfo.default;
|
|
31036
|
+
}
|
|
31037
|
+
continue;
|
|
31038
|
+
}
|
|
31039
|
+
const widgetSourceIndex = widgetIndex;
|
|
31040
|
+
const value = normalizeWidgetValue(
|
|
31041
|
+
widgets[widgetSourceIndex],
|
|
31042
|
+
typeName,
|
|
31043
|
+
inputExtraInfo
|
|
31044
|
+
);
|
|
31045
|
+
widgetIndex++;
|
|
31046
|
+
if (!isConnectedWidget) {
|
|
31047
|
+
promptNode.inputs[inputName] = value;
|
|
31048
|
+
widgetPathMap[`${nodeIdStr}.widgets[${widgetSourceIndex}]`] = `${nodeIdStr}.inputs.${inputName}`;
|
|
31049
|
+
}
|
|
31050
|
+
}
|
|
31051
|
+
};
|
|
31052
|
+
processInputGroup(
|
|
31053
|
+
objInfo.input?.required,
|
|
31054
|
+
objInfo.input_order?.required
|
|
31055
|
+
);
|
|
31056
|
+
processInputGroup(
|
|
31057
|
+
objInfo.input?.optional,
|
|
31058
|
+
objInfo.input_order?.optional
|
|
31059
|
+
);
|
|
31060
|
+
}
|
|
31061
|
+
prompt[nodeIdStr] = promptNode;
|
|
30969
31062
|
}
|
|
30970
|
-
|
|
30971
|
-
|
|
30972
|
-
|
|
30973
|
-
|
|
30974
|
-
|
|
30975
|
-
|
|
30976
|
-
|
|
30977
|
-
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
|
|
30981
|
-
|
|
30982
|
-
|
|
31063
|
+
return {
|
|
31064
|
+
prompt,
|
|
31065
|
+
widgetPathMap
|
|
31066
|
+
};
|
|
31067
|
+
}
|
|
31068
|
+
|
|
31069
|
+
// src/workflow/load.ts
|
|
31070
|
+
function isComfyPromptNode(value) {
|
|
31071
|
+
return isRecord(value) && typeof value.class_type === "string" && isRecord(value.inputs);
|
|
31072
|
+
}
|
|
31073
|
+
function isUiOnlyPromptNode(nodeId, node) {
|
|
31074
|
+
return nodeId === "meta" || ["Note", "MarkdownNote", "PrimitiveNode"].includes(node.class_type);
|
|
31075
|
+
}
|
|
31076
|
+
function extractRunnablePromptNodes(prompt) {
|
|
31077
|
+
const runnablePrompt = {};
|
|
31078
|
+
for (const [nodeId, rawNode] of Object.entries(prompt)) {
|
|
31079
|
+
if (!isComfyPromptNode(rawNode) || isUiOnlyPromptNode(nodeId, rawNode)) {
|
|
31080
|
+
continue;
|
|
31081
|
+
}
|
|
31082
|
+
runnablePrompt[nodeId] = rawNode;
|
|
30983
31083
|
}
|
|
30984
|
-
if (
|
|
30985
|
-
|
|
30986
|
-
|
|
30987
|
-
|
|
30988
|
-
error48.queueSnapshot
|
|
31084
|
+
if (Object.keys(runnablePrompt).length === 0) {
|
|
31085
|
+
throw new WorkflowInputError(
|
|
31086
|
+
"Workflow prompt does not contain any runnable ComfyUI nodes.",
|
|
31087
|
+
"workflow"
|
|
30989
31088
|
);
|
|
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.";
|
|
30991
|
-
return {
|
|
30992
|
-
content: [
|
|
30993
|
-
{
|
|
30994
|
-
type: "text",
|
|
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")
|
|
31001
|
-
}
|
|
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
|
-
},
|
|
31009
|
-
isError: true
|
|
31010
|
-
};
|
|
31011
31089
|
}
|
|
31012
|
-
return
|
|
31090
|
+
return runnablePrompt;
|
|
31013
31091
|
}
|
|
31014
31092
|
function getWorkflowDirectories(extraPath) {
|
|
31015
31093
|
const directories = [
|
|
31016
31094
|
process.cwd(),
|
|
31017
|
-
|
|
31018
|
-
|
|
31019
|
-
|
|
31095
|
+
path2.join(process.cwd(), "workflows"),
|
|
31096
|
+
path2.join(homedir(), ".fre4x-comfyui", "workflows"),
|
|
31097
|
+
path2.join(
|
|
31020
31098
|
homedir(),
|
|
31021
31099
|
"comfy",
|
|
31022
31100
|
"ComfyUI",
|
|
@@ -31029,7 +31107,7 @@ function getWorkflowDirectories(extraPath) {
|
|
|
31029
31107
|
directories.push(extraPath);
|
|
31030
31108
|
}
|
|
31031
31109
|
return [
|
|
31032
|
-
...new Set(directories.map((directory) =>
|
|
31110
|
+
...new Set(directories.map((directory) => path2.resolve(directory)))
|
|
31033
31111
|
];
|
|
31034
31112
|
}
|
|
31035
31113
|
function getWorkflowNameCandidates(name) {
|
|
@@ -31050,48 +31128,32 @@ function normalizeWorkflowFileName(fileName) {
|
|
|
31050
31128
|
"output_file_name"
|
|
31051
31129
|
);
|
|
31052
31130
|
}
|
|
31053
|
-
|
|
31054
|
-
|
|
31055
|
-
|
|
31056
|
-
|
|
31057
|
-
|
|
31058
|
-
async function getObjectInfo() {
|
|
31059
|
-
return IS_MOCK ? MOCK_FIXTURES.object_info : await fetchComfyJson("/object_info");
|
|
31060
|
-
}
|
|
31061
|
-
function summarizeErrorMessage(error48) {
|
|
31062
|
-
return error48 instanceof Error ? error48.message : String(error48);
|
|
31063
|
-
}
|
|
31064
|
-
async function tryGetObjectInfo() {
|
|
31065
|
-
try {
|
|
31066
|
-
return {
|
|
31067
|
-
objectInfo: await getObjectInfo()
|
|
31068
|
-
};
|
|
31069
|
-
} catch (error48) {
|
|
31070
|
-
return {
|
|
31071
|
-
warning: `Node schema details unavailable from ComfyUI: ${summarizeErrorMessage(
|
|
31072
|
-
error48
|
|
31073
|
-
)}`
|
|
31074
|
-
};
|
|
31131
|
+
if (path2.isAbsolute(trimmed)) {
|
|
31132
|
+
throw new WorkflowInputError(
|
|
31133
|
+
"Absolute paths are not allowed.",
|
|
31134
|
+
"output_file_name"
|
|
31135
|
+
);
|
|
31075
31136
|
}
|
|
31137
|
+
return trimmed.endsWith(".json") ? trimmed : `${trimmed}.json`;
|
|
31076
31138
|
}
|
|
31077
31139
|
async function resolveWorkflowReference(args) {
|
|
31078
31140
|
if (args.workflow_file_path) {
|
|
31079
31141
|
const targetPath = args.workflow_file_path;
|
|
31080
31142
|
try {
|
|
31081
|
-
const resolvedPath =
|
|
31082
|
-
const content = await
|
|
31143
|
+
const resolvedPath = path2.resolve(targetPath);
|
|
31144
|
+
const content = await fs2.readFile(resolvedPath, "utf8");
|
|
31083
31145
|
return {
|
|
31084
31146
|
targetPath: resolvedPath,
|
|
31085
31147
|
content
|
|
31086
31148
|
};
|
|
31087
31149
|
} catch {
|
|
31088
|
-
if (
|
|
31150
|
+
if (path2.basename(targetPath) === targetPath) {
|
|
31089
31151
|
const candidates = getWorkflowNameCandidates(targetPath);
|
|
31090
31152
|
for (const dir of getWorkflowDirectories()) {
|
|
31091
31153
|
for (const candidate of candidates) {
|
|
31092
|
-
const candidatePath =
|
|
31154
|
+
const candidatePath = path2.join(dir, candidate);
|
|
31093
31155
|
try {
|
|
31094
|
-
const content = await
|
|
31156
|
+
const content = await fs2.readFile(
|
|
31095
31157
|
candidatePath,
|
|
31096
31158
|
"utf8"
|
|
31097
31159
|
);
|
|
@@ -31122,12 +31184,12 @@ async function resolveWorkflowReference(args) {
|
|
|
31122
31184
|
const objectInfoAvailability = await tryGetObjectInfo();
|
|
31123
31185
|
for (const dir of getWorkflowDirectories()) {
|
|
31124
31186
|
try {
|
|
31125
|
-
const entries = await
|
|
31187
|
+
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
31126
31188
|
for (const entry of entries) {
|
|
31127
31189
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
31128
31190
|
continue;
|
|
31129
31191
|
}
|
|
31130
|
-
const fullPath =
|
|
31192
|
+
const fullPath = path2.join(dir, entry.name);
|
|
31131
31193
|
const inspected = await inspectWorkflowFile(
|
|
31132
31194
|
fullPath,
|
|
31133
31195
|
objectInfoAvailability.objectInfo
|
|
@@ -31157,7 +31219,7 @@ async function resolveWorkflowReference(args) {
|
|
|
31157
31219
|
);
|
|
31158
31220
|
}
|
|
31159
31221
|
async function normalizeWorkflowPrompt(workflow, objectInfo) {
|
|
31160
|
-
if (!
|
|
31222
|
+
if (!isRecord(workflow)) {
|
|
31161
31223
|
throw new WorkflowInputError(
|
|
31162
31224
|
"Workflow must be a JSON object.",
|
|
31163
31225
|
"workflow"
|
|
@@ -31181,8 +31243,8 @@ async function normalizeWorkflowPrompt(workflow, objectInfo) {
|
|
|
31181
31243
|
normalizedWorkflow = converted.prompt;
|
|
31182
31244
|
widgetPathMap = converted.widgetPathMap;
|
|
31183
31245
|
}
|
|
31184
|
-
const promptCandidate =
|
|
31185
|
-
if (!
|
|
31246
|
+
const promptCandidate = isRecord(normalizedWorkflow.prompt) && normalizedWorkflow.prompt ? normalizedWorkflow.prompt : normalizedWorkflow;
|
|
31247
|
+
if (!isRecord(promptCandidate)) {
|
|
31186
31248
|
throw new WorkflowInputError(
|
|
31187
31249
|
"Workflow prompt must be a JSON object.",
|
|
31188
31250
|
"workflow"
|
|
@@ -31214,8 +31276,8 @@ async function loadWorkflow(args, objectInfo) {
|
|
|
31214
31276
|
};
|
|
31215
31277
|
}
|
|
31216
31278
|
async function inspectWorkflowFile(fullPath, objectInfo) {
|
|
31217
|
-
const content = await
|
|
31218
|
-
const defaultName =
|
|
31279
|
+
const content = await fs2.readFile(fullPath, "utf8");
|
|
31280
|
+
const defaultName = path2.basename(fullPath, ".json");
|
|
31219
31281
|
const defaultId = getWorkflowId(fullPath);
|
|
31220
31282
|
let parsed;
|
|
31221
31283
|
try {
|
|
@@ -31224,10 +31286,10 @@ async function inspectWorkflowFile(fullPath, objectInfo) {
|
|
|
31224
31286
|
return void 0;
|
|
31225
31287
|
}
|
|
31226
31288
|
let name = defaultName;
|
|
31227
|
-
if (
|
|
31289
|
+
if (isRecord(parsed)) {
|
|
31228
31290
|
if (typeof parsed.name === "string" && parsed.name.trim().length > 0) {
|
|
31229
31291
|
name = parsed.name;
|
|
31230
|
-
} else if (
|
|
31292
|
+
} else if (isRecord(parsed.workflow) && typeof parsed.workflow.name === "string" && parsed.workflow.name.trim().length > 0) {
|
|
31231
31293
|
name = parsed.workflow.name;
|
|
31232
31294
|
}
|
|
31233
31295
|
}
|
|
@@ -31282,6 +31344,23 @@ async function inspectWorkflowFile(fullPath, objectInfo) {
|
|
|
31282
31344
|
return void 0;
|
|
31283
31345
|
}
|
|
31284
31346
|
}
|
|
31347
|
+
function deriveSavedWorkflowFileName(sourcePath, requestedName) {
|
|
31348
|
+
if (requestedName) {
|
|
31349
|
+
return normalizeWorkflowFileName(requestedName);
|
|
31350
|
+
}
|
|
31351
|
+
if (sourcePath) {
|
|
31352
|
+
return normalizeWorkflowFileName(path2.basename(sourcePath));
|
|
31353
|
+
}
|
|
31354
|
+
return `workflow-${Date.now()}.json`;
|
|
31355
|
+
}
|
|
31356
|
+
function getWorkflowId(absolutePath) {
|
|
31357
|
+
return crypto.createHash("sha256").update(absolutePath).digest("hex").substring(0, 8);
|
|
31358
|
+
}
|
|
31359
|
+
|
|
31360
|
+
// src/workflow/editable.ts
|
|
31361
|
+
function isConnectionValue(value) {
|
|
31362
|
+
return Array.isArray(value) && value.length >= 2 && (typeof value[0] === "string" || typeof value[0] === "number") && typeof value[1] === "number";
|
|
31363
|
+
}
|
|
31285
31364
|
function inferEditableRole(nodeId, classType, inputName, consumerMap) {
|
|
31286
31365
|
if (classType === "CLIPTextEncode" && inputName === "text") {
|
|
31287
31366
|
const consumers = consumerMap.get(nodeId) ?? [];
|
|
@@ -31302,167 +31381,46 @@ function inferEditableRole(nodeId, classType, inputName, consumerMap) {
|
|
|
31302
31381
|
for (const consumer of textConsumers) {
|
|
31303
31382
|
const clipConsumers = consumerMap.get(consumer.nodeId) ?? [];
|
|
31304
31383
|
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
|
-
}
|
|
31318
|
-
switch (inputName) {
|
|
31319
|
-
case "seed":
|
|
31320
|
-
return "seed";
|
|
31321
|
-
case "steps":
|
|
31322
|
-
return "steps";
|
|
31323
|
-
case "cfg":
|
|
31324
|
-
return "cfg";
|
|
31325
|
-
case "sampler_name":
|
|
31326
|
-
return "sampler";
|
|
31327
|
-
case "scheduler":
|
|
31328
|
-
return "scheduler";
|
|
31329
|
-
case "denoise":
|
|
31330
|
-
return "denoise";
|
|
31331
|
-
case "width":
|
|
31332
|
-
return "width";
|
|
31333
|
-
case "height":
|
|
31334
|
-
return "height";
|
|
31335
|
-
case "batch_size":
|
|
31336
|
-
return "batch_size";
|
|
31337
|
-
case "ckpt_name":
|
|
31338
|
-
return "checkpoint";
|
|
31339
|
-
case "filename_prefix":
|
|
31340
|
-
return "filename_prefix";
|
|
31341
|
-
case "text":
|
|
31342
|
-
return "text";
|
|
31343
|
-
default:
|
|
31344
|
-
return void 0;
|
|
31345
|
-
}
|
|
31346
|
-
}
|
|
31347
|
-
function formatValuePreview(value) {
|
|
31348
|
-
if (typeof value === "string") {
|
|
31349
|
-
return value.length > 100 ? `${value.slice(0, 97)}...` : value;
|
|
31350
|
-
}
|
|
31351
|
-
try {
|
|
31352
|
-
const serialized = JSON.stringify(value);
|
|
31353
|
-
if (!serialized) {
|
|
31354
|
-
return String(value);
|
|
31355
|
-
}
|
|
31356
|
-
return serialized.length > 100 ? `${serialized.slice(0, 97)}...` : serialized;
|
|
31357
|
-
} catch {
|
|
31358
|
-
return String(value);
|
|
31359
|
-
}
|
|
31360
|
-
}
|
|
31361
|
-
function getInputDefinition(objectInfo, prompt, nodeId, inputName) {
|
|
31362
|
-
if (!objectInfo) {
|
|
31363
|
-
return void 0;
|
|
31364
|
-
}
|
|
31365
|
-
const node = prompt[nodeId];
|
|
31366
|
-
if (!node) {
|
|
31367
|
-
return void 0;
|
|
31368
|
-
}
|
|
31369
|
-
const nodeDefinition = objectInfo[node.class_type];
|
|
31370
|
-
if (!nodeDefinition) {
|
|
31371
|
-
return void 0;
|
|
31372
|
-
}
|
|
31373
|
-
return nodeDefinition.input?.required?.[inputName] ?? nodeDefinition.input?.optional?.[inputName];
|
|
31374
|
-
}
|
|
31375
|
-
function getExpectedTypeName(inputDefinition) {
|
|
31376
|
-
if (!inputDefinition) {
|
|
31377
|
-
return void 0;
|
|
31378
|
-
}
|
|
31379
|
-
const [typeData] = inputDefinition;
|
|
31380
|
-
return Array.isArray(typeData) ? "COMBO" : String(typeData).toUpperCase();
|
|
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
|
-
}
|
|
31396
|
-
function isPlainObject3(value) {
|
|
31397
|
-
return isRecord2(value) && !Array.isArray(value);
|
|
31398
|
-
}
|
|
31399
|
-
function getValueTypeName(value) {
|
|
31400
|
-
if (Array.isArray(value)) {
|
|
31401
|
-
return "array";
|
|
31402
|
-
}
|
|
31403
|
-
if (value === null) {
|
|
31404
|
-
return "null";
|
|
31405
|
-
}
|
|
31406
|
-
return typeof value;
|
|
31407
|
-
}
|
|
31408
|
-
function validateOverrideValueType(path2, value, inputDefinition) {
|
|
31409
|
-
if (!inputDefinition) {
|
|
31410
|
-
return;
|
|
31411
|
-
}
|
|
31412
|
-
const [typeData] = inputDefinition;
|
|
31413
|
-
if (Array.isArray(typeData)) {
|
|
31414
|
-
if (!typeData.some((option) => option === value)) {
|
|
31415
|
-
throw new WorkflowInputError(
|
|
31416
|
-
`Invalid override for '${path2}': expected one of ${typeData.map((option) => JSON.stringify(option)).join(", ")}, received ${JSON.stringify(value)}.`,
|
|
31417
|
-
"overrides"
|
|
31418
|
-
);
|
|
31419
|
-
}
|
|
31420
|
-
return;
|
|
31421
|
-
}
|
|
31422
|
-
const typeName = String(typeData).toUpperCase();
|
|
31423
|
-
switch (typeName) {
|
|
31424
|
-
case "INT":
|
|
31425
|
-
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
31426
|
-
throw new WorkflowInputError(
|
|
31427
|
-
`Invalid override for '${path2}': expected INT, received ${getValueTypeName(
|
|
31428
|
-
value
|
|
31429
|
-
)}.`,
|
|
31430
|
-
"overrides"
|
|
31431
|
-
);
|
|
31432
|
-
}
|
|
31433
|
-
return;
|
|
31434
|
-
case "FLOAT":
|
|
31435
|
-
if (typeof value !== "number") {
|
|
31436
|
-
throw new WorkflowInputError(
|
|
31437
|
-
`Invalid override for '${path2}': expected FLOAT, received ${getValueTypeName(
|
|
31438
|
-
value
|
|
31439
|
-
)}.`,
|
|
31440
|
-
"overrides"
|
|
31441
|
-
);
|
|
31442
|
-
}
|
|
31443
|
-
return;
|
|
31444
|
-
case "STRING":
|
|
31445
|
-
if (typeof value !== "string") {
|
|
31446
|
-
throw new WorkflowInputError(
|
|
31447
|
-
`Invalid override for '${path2}': expected STRING, received ${getValueTypeName(
|
|
31448
|
-
value
|
|
31449
|
-
)}.`,
|
|
31450
|
-
"overrides"
|
|
31451
|
-
);
|
|
31452
|
-
}
|
|
31453
|
-
return;
|
|
31454
|
-
case "BOOLEAN":
|
|
31455
|
-
if (typeof value !== "boolean") {
|
|
31456
|
-
throw new WorkflowInputError(
|
|
31457
|
-
`Invalid override for '${path2}': expected BOOLEAN, received ${getValueTypeName(
|
|
31458
|
-
value
|
|
31459
|
-
)}.`,
|
|
31460
|
-
"overrides"
|
|
31461
|
-
);
|
|
31384
|
+
(clipConsumer) => clipConsumer.inputName === "positive"
|
|
31385
|
+
)) {
|
|
31386
|
+
return "positive_prompt";
|
|
31387
|
+
}
|
|
31388
|
+
if (clipConsumers.some(
|
|
31389
|
+
(clipConsumer) => clipConsumer.inputName === "negative"
|
|
31390
|
+
)) {
|
|
31391
|
+
return "negative_prompt";
|
|
31392
|
+
}
|
|
31462
31393
|
}
|
|
31463
|
-
return;
|
|
31394
|
+
return "prompt_text";
|
|
31395
|
+
}
|
|
31396
|
+
}
|
|
31397
|
+
switch (inputName) {
|
|
31398
|
+
case "seed":
|
|
31399
|
+
return "seed";
|
|
31400
|
+
case "steps":
|
|
31401
|
+
return "steps";
|
|
31402
|
+
case "cfg":
|
|
31403
|
+
return "cfg";
|
|
31404
|
+
case "sampler_name":
|
|
31405
|
+
return "sampler";
|
|
31406
|
+
case "scheduler":
|
|
31407
|
+
return "scheduler";
|
|
31408
|
+
case "denoise":
|
|
31409
|
+
return "denoise";
|
|
31410
|
+
case "width":
|
|
31411
|
+
return "width";
|
|
31412
|
+
case "height":
|
|
31413
|
+
return "height";
|
|
31414
|
+
case "batch_size":
|
|
31415
|
+
return "batch_size";
|
|
31416
|
+
case "ckpt_name":
|
|
31417
|
+
return "checkpoint";
|
|
31418
|
+
case "filename_prefix":
|
|
31419
|
+
return "filename_prefix";
|
|
31420
|
+
case "text":
|
|
31421
|
+
return "text";
|
|
31464
31422
|
default:
|
|
31465
|
-
return;
|
|
31423
|
+
return void 0;
|
|
31466
31424
|
}
|
|
31467
31425
|
}
|
|
31468
31426
|
function getEditableAliases(canonicalPath, nodeId, inputName, role, widgetPathMap) {
|
|
@@ -31512,15 +31470,15 @@ function buildEditableInputIndex(editableInputs) {
|
|
|
31512
31470
|
pathsByNode
|
|
31513
31471
|
};
|
|
31514
31472
|
}
|
|
31515
|
-
function getPathSegmentHelp(prompt,
|
|
31516
|
-
const parts =
|
|
31473
|
+
function getPathSegmentHelp(prompt, path4) {
|
|
31474
|
+
const parts = path4.split(".");
|
|
31517
31475
|
if (parts.length === 0 || parts[0].length === 0) {
|
|
31518
31476
|
return void 0;
|
|
31519
31477
|
}
|
|
31520
31478
|
const nodeId = parts[0];
|
|
31521
31479
|
return {
|
|
31522
31480
|
nodeId,
|
|
31523
|
-
nodeExists:
|
|
31481
|
+
nodeExists: isRecord(prompt[nodeId])
|
|
31524
31482
|
};
|
|
31525
31483
|
}
|
|
31526
31484
|
function describeAvailableNodePaths(editableIndex, nodeId) {
|
|
@@ -31702,6 +31660,221 @@ function buildOverrideExamples(editableInputs, limit = 5) {
|
|
|
31702
31660
|
function formatOverrideExamplesText(examples) {
|
|
31703
31661
|
return JSON.stringify(examples, null, 2);
|
|
31704
31662
|
}
|
|
31663
|
+
function analyzeEditableInputs(prompt, objectInfo, widgetPathMap = {}) {
|
|
31664
|
+
const consumerMap = /* @__PURE__ */ new Map();
|
|
31665
|
+
for (const [nodeId, node] of Object.entries(prompt)) {
|
|
31666
|
+
for (const [inputName, value] of Object.entries(node.inputs)) {
|
|
31667
|
+
if (!isConnectionValue(value)) {
|
|
31668
|
+
continue;
|
|
31669
|
+
}
|
|
31670
|
+
const sourceNodeId = String(value[0]);
|
|
31671
|
+
const consumers = consumerMap.get(sourceNodeId) ?? [];
|
|
31672
|
+
consumers.push({
|
|
31673
|
+
inputName,
|
|
31674
|
+
classType: node.class_type,
|
|
31675
|
+
nodeId
|
|
31676
|
+
});
|
|
31677
|
+
consumerMap.set(sourceNodeId, consumers);
|
|
31678
|
+
}
|
|
31679
|
+
}
|
|
31680
|
+
const editableInputs = [];
|
|
31681
|
+
for (const [nodeId, node] of Object.entries(prompt)) {
|
|
31682
|
+
for (const [inputName, value] of Object.entries(node.inputs)) {
|
|
31683
|
+
if (isConnectionValue(value)) {
|
|
31684
|
+
continue;
|
|
31685
|
+
}
|
|
31686
|
+
editableInputs.push({
|
|
31687
|
+
path: `${nodeId}.inputs.${inputName}`,
|
|
31688
|
+
node_id: nodeId,
|
|
31689
|
+
class_type: node.class_type,
|
|
31690
|
+
input_name: inputName,
|
|
31691
|
+
value,
|
|
31692
|
+
value_preview: formatValuePreview(value),
|
|
31693
|
+
role: inferEditableRole(
|
|
31694
|
+
nodeId,
|
|
31695
|
+
node.class_type,
|
|
31696
|
+
inputName,
|
|
31697
|
+
consumerMap
|
|
31698
|
+
),
|
|
31699
|
+
aliases: [],
|
|
31700
|
+
expected_type: getExpectedTypeName(
|
|
31701
|
+
getInputDefinition(objectInfo, prompt, nodeId, inputName)
|
|
31702
|
+
),
|
|
31703
|
+
...getInputOptionsSummary(
|
|
31704
|
+
getInputDefinition(objectInfo, prompt, nodeId, inputName)
|
|
31705
|
+
)
|
|
31706
|
+
});
|
|
31707
|
+
}
|
|
31708
|
+
}
|
|
31709
|
+
return editableInputs.map((entry) => ({
|
|
31710
|
+
...entry,
|
|
31711
|
+
aliases: getEditableAliases(
|
|
31712
|
+
entry.path,
|
|
31713
|
+
entry.node_id,
|
|
31714
|
+
entry.input_name,
|
|
31715
|
+
entry.role,
|
|
31716
|
+
widgetPathMap
|
|
31717
|
+
)
|
|
31718
|
+
})).sort(
|
|
31719
|
+
(left, right) => left.path.localeCompare(right.path, void 0, { numeric: true })
|
|
31720
|
+
);
|
|
31721
|
+
}
|
|
31722
|
+
function formatEditableInputsText(editableInputs, options = {}) {
|
|
31723
|
+
if (editableInputs.length === 0) {
|
|
31724
|
+
return "No literal editable inputs were detected.";
|
|
31725
|
+
}
|
|
31726
|
+
return formatListItems(editableInputs, (entry) => {
|
|
31727
|
+
const role = entry.role ? ` [${entry.role}]` : "";
|
|
31728
|
+
const classType = entry.class_type ? ` (${entry.class_type})` : "";
|
|
31729
|
+
const expectedType = entry.expected_type ? ` <${entry.expected_type}>` : "";
|
|
31730
|
+
const aliasSuffix = entry.aliases.length > 0 ? ` | aliases: ${entry.aliases.join(", ")}` : "";
|
|
31731
|
+
const optionsSuffix = options.includeOptions ? formatEditableInputOptionsText(entry) : "";
|
|
31732
|
+
return `${entry.path}${role}${classType}${expectedType}: ${entry.value_preview}${aliasSuffix}${optionsSuffix}`;
|
|
31733
|
+
});
|
|
31734
|
+
}
|
|
31735
|
+
function formatInputDefinitionSummary(inputName, inputDefinition) {
|
|
31736
|
+
const [typeData, extraInfo] = inputDefinition;
|
|
31737
|
+
const typeLabel = Array.isArray(typeData) ? `COMBO (${typeData.length} options)` : String(typeData).toUpperCase();
|
|
31738
|
+
const details = [];
|
|
31739
|
+
if (Array.isArray(typeData)) {
|
|
31740
|
+
details.push(
|
|
31741
|
+
`options: ${typeData.slice(0, 5).map((option) => JSON.stringify(option)).join(", ")}${typeData.length > 5 ? ", ..." : ""}`
|
|
31742
|
+
);
|
|
31743
|
+
}
|
|
31744
|
+
if (isRecord(extraInfo)) {
|
|
31745
|
+
if (extraInfo.default !== void 0) {
|
|
31746
|
+
details.push(`default: ${formatValuePreview(extraInfo.default)}`);
|
|
31747
|
+
}
|
|
31748
|
+
if (typeof extraInfo.min === "number") {
|
|
31749
|
+
details.push(`min: ${extraInfo.min}`);
|
|
31750
|
+
}
|
|
31751
|
+
if (typeof extraInfo.max === "number") {
|
|
31752
|
+
details.push(`max: ${extraInfo.max}`);
|
|
31753
|
+
}
|
|
31754
|
+
}
|
|
31755
|
+
return `${inputName} <${typeLabel}>${details.length > 0 ? ` | ${details.join(" | ")}` : ""}`;
|
|
31756
|
+
}
|
|
31757
|
+
function formatNodeDefinitionText(nodeClass, node) {
|
|
31758
|
+
const requiredInputs = Object.entries(node.input.required ?? {});
|
|
31759
|
+
const optionalInputs = Object.entries(node.input.optional ?? {});
|
|
31760
|
+
const lines = [
|
|
31761
|
+
`Node: ${nodeClass}`,
|
|
31762
|
+
`Display name: ${node.display_name || node.name || nodeClass}`,
|
|
31763
|
+
`Category: ${node.category || "uncategorized"}`
|
|
31764
|
+
];
|
|
31765
|
+
if (typeof node.description === "string" && node.description.trim().length > 0) {
|
|
31766
|
+
lines.push(`Description: ${node.description.trim()}`);
|
|
31767
|
+
}
|
|
31768
|
+
lines.push(
|
|
31769
|
+
`Required inputs (${requiredInputs.length}): ${requiredInputs.length > 0 ? requiredInputs.map(
|
|
31770
|
+
([inputName, inputDefinition]) => formatInputDefinitionSummary(
|
|
31771
|
+
inputName,
|
|
31772
|
+
inputDefinition
|
|
31773
|
+
)
|
|
31774
|
+
).join("\n") : "None."}`
|
|
31775
|
+
);
|
|
31776
|
+
lines.push(
|
|
31777
|
+
`Optional inputs (${optionalInputs.length}): ${optionalInputs.length > 0 ? optionalInputs.map(
|
|
31778
|
+
([inputName, inputDefinition]) => formatInputDefinitionSummary(
|
|
31779
|
+
inputName,
|
|
31780
|
+
inputDefinition
|
|
31781
|
+
)
|
|
31782
|
+
).join("\n") : "None."}`
|
|
31783
|
+
);
|
|
31784
|
+
lines.push(`Outputs: ${node.output.join(", ") || "None."}`);
|
|
31785
|
+
return lines.join("\n");
|
|
31786
|
+
}
|
|
31787
|
+
function formatNodeListText(classes, rawInfo, pagination) {
|
|
31788
|
+
const text = `Available nodes (${pagination.total} total):
|
|
31789
|
+
` + formatListItems(classes, (nodeClass) => {
|
|
31790
|
+
const node = rawInfo[nodeClass];
|
|
31791
|
+
const displayName = node.display_name && node.display_name !== nodeClass ? ` \u2014 ${node.display_name}` : "";
|
|
31792
|
+
const category = node.category ? ` | category: ${node.category}` : "";
|
|
31793
|
+
const description = typeof node.description === "string" && node.description.trim().length > 0 ? ` | ${node.description.trim()}` : "";
|
|
31794
|
+
return `${nodeClass}${displayName}${category}${description}`;
|
|
31795
|
+
});
|
|
31796
|
+
if (!pagination.hasMore) {
|
|
31797
|
+
return text;
|
|
31798
|
+
}
|
|
31799
|
+
return `${text}
|
|
31800
|
+
|
|
31801
|
+
${formatPaginationFooter(
|
|
31802
|
+
pagination.offset,
|
|
31803
|
+
pagination.limit,
|
|
31804
|
+
pagination.total
|
|
31805
|
+
)}`;
|
|
31806
|
+
}
|
|
31807
|
+
|
|
31808
|
+
// src/zod.ts
|
|
31809
|
+
var zNamespace = zod_exports;
|
|
31810
|
+
var z3 = zNamespace.z ?? zNamespace.default ?? zNamespace;
|
|
31811
|
+
|
|
31812
|
+
// src/workflow/overrides.ts
|
|
31813
|
+
var INPUT_SEGMENT = "inputs";
|
|
31814
|
+
var OverrideRecordSchema = z3.record(z3.string(), z3.unknown());
|
|
31815
|
+
var OverridesSchema = z3.union([OverrideRecordSchema, z3.string()]).describe(
|
|
31816
|
+
'Dot-notation overrides as an object or JSON string. e.g. {"6.seed": 7}'
|
|
31817
|
+
);
|
|
31818
|
+
function validateOverrideValueType(path4, value, inputDefinition) {
|
|
31819
|
+
if (!inputDefinition) {
|
|
31820
|
+
return;
|
|
31821
|
+
}
|
|
31822
|
+
const [typeData] = inputDefinition;
|
|
31823
|
+
if (Array.isArray(typeData)) {
|
|
31824
|
+
if (!typeData.some((option) => option === value)) {
|
|
31825
|
+
throw new WorkflowInputError(
|
|
31826
|
+
`Invalid override for '${path4}': expected one of ${typeData.map((option) => JSON.stringify(option)).join(", ")}, received ${JSON.stringify(value)}.`,
|
|
31827
|
+
"overrides"
|
|
31828
|
+
);
|
|
31829
|
+
}
|
|
31830
|
+
return;
|
|
31831
|
+
}
|
|
31832
|
+
const typeName = String(typeData).toUpperCase();
|
|
31833
|
+
switch (typeName) {
|
|
31834
|
+
case "INT":
|
|
31835
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
31836
|
+
throw new WorkflowInputError(
|
|
31837
|
+
`Invalid override for '${path4}': expected INT, received ${getValueTypeName(
|
|
31838
|
+
value
|
|
31839
|
+
)}.`,
|
|
31840
|
+
"overrides"
|
|
31841
|
+
);
|
|
31842
|
+
}
|
|
31843
|
+
return;
|
|
31844
|
+
case "FLOAT":
|
|
31845
|
+
if (typeof value !== "number") {
|
|
31846
|
+
throw new WorkflowInputError(
|
|
31847
|
+
`Invalid override for '${path4}': expected FLOAT, received ${getValueTypeName(
|
|
31848
|
+
value
|
|
31849
|
+
)}.`,
|
|
31850
|
+
"overrides"
|
|
31851
|
+
);
|
|
31852
|
+
}
|
|
31853
|
+
return;
|
|
31854
|
+
case "STRING":
|
|
31855
|
+
if (typeof value !== "string") {
|
|
31856
|
+
throw new WorkflowInputError(
|
|
31857
|
+
`Invalid override for '${path4}': expected STRING, received ${getValueTypeName(
|
|
31858
|
+
value
|
|
31859
|
+
)}.`,
|
|
31860
|
+
"overrides"
|
|
31861
|
+
);
|
|
31862
|
+
}
|
|
31863
|
+
return;
|
|
31864
|
+
case "BOOLEAN":
|
|
31865
|
+
if (typeof value !== "boolean") {
|
|
31866
|
+
throw new WorkflowInputError(
|
|
31867
|
+
`Invalid override for '${path4}': expected BOOLEAN, received ${getValueTypeName(
|
|
31868
|
+
value
|
|
31869
|
+
)}.`,
|
|
31870
|
+
"overrides"
|
|
31871
|
+
);
|
|
31872
|
+
}
|
|
31873
|
+
return;
|
|
31874
|
+
default:
|
|
31875
|
+
return;
|
|
31876
|
+
}
|
|
31877
|
+
}
|
|
31705
31878
|
function resolveOverridePath(prompt, rawPath, editableIndex) {
|
|
31706
31879
|
if (!editableIndex) {
|
|
31707
31880
|
return rawPath;
|
|
@@ -31720,25 +31893,9 @@ function resolveOverridePath(prompt, rawPath, editableIndex) {
|
|
|
31720
31893
|
}
|
|
31721
31894
|
const resolved = editableIndex.aliasToPath.get(rawPath);
|
|
31722
31895
|
if (resolved) {
|
|
31723
|
-
return resolved;
|
|
31724
|
-
}
|
|
31725
|
-
const rawParts = rawPath.split(".");
|
|
31726
|
-
if (rawParts.length >= 3 && rawParts[1] === INPUT_SEGMENT) {
|
|
31727
|
-
const pathHelp2 = getPathSegmentHelp(prompt, rawPath);
|
|
31728
|
-
if (pathHelp2?.nodeId && pathHelp2.nodeExists) {
|
|
31729
|
-
const validPaths = describeAvailableNodePaths(
|
|
31730
|
-
editableIndex,
|
|
31731
|
-
pathHelp2.nodeId
|
|
31732
|
-
);
|
|
31733
|
-
if (validPaths.length > 0) {
|
|
31734
|
-
throw new WorkflowInputError(
|
|
31735
|
-
`Unsupported override path '${rawPath}'. Only detected editable inputs can be overridden. Valid editable paths for node ${pathHelp2.nodeId}:
|
|
31736
|
-
${validPaths}`,
|
|
31737
|
-
"overrides"
|
|
31738
|
-
);
|
|
31739
|
-
}
|
|
31740
|
-
}
|
|
31896
|
+
return resolved;
|
|
31741
31897
|
}
|
|
31898
|
+
const rawParts = rawPath.split(".");
|
|
31742
31899
|
const pathHelp = getPathSegmentHelp(prompt, rawPath);
|
|
31743
31900
|
if (pathHelp?.nodeId && pathHelp.nodeExists) {
|
|
31744
31901
|
const validPaths = describeAvailableNodePaths(
|
|
@@ -31746,11 +31903,10 @@ ${validPaths}`,
|
|
|
31746
31903
|
pathHelp.nodeId
|
|
31747
31904
|
);
|
|
31748
31905
|
if (validPaths.length > 0) {
|
|
31749
|
-
|
|
31750
|
-
|
|
31751
|
-
${validPaths}
|
|
31752
|
-
|
|
31753
|
-
);
|
|
31906
|
+
const message = rawParts.length >= 3 && rawParts[1] === INPUT_SEGMENT ? `Unsupported override path '${rawPath}'. Only detected editable inputs can be overridden. Valid editable paths for node ${pathHelp.nodeId}:
|
|
31907
|
+
${validPaths}` : `Unknown override path '${rawPath}'. Valid editable paths for node ${pathHelp.nodeId}:
|
|
31908
|
+
${validPaths}`;
|
|
31909
|
+
throw new WorkflowInputError(message, "overrides");
|
|
31754
31910
|
}
|
|
31755
31911
|
}
|
|
31756
31912
|
return rawPath;
|
|
@@ -31779,78 +31935,6 @@ function parseOverrides(rawOverrides) {
|
|
|
31779
31935
|
}
|
|
31780
31936
|
return parsed;
|
|
31781
31937
|
}
|
|
31782
|
-
function analyzeEditableInputs(prompt, objectInfo, widgetPathMap = {}) {
|
|
31783
|
-
const consumerMap = /* @__PURE__ */ new Map();
|
|
31784
|
-
for (const [nodeId, node] of Object.entries(prompt)) {
|
|
31785
|
-
for (const [inputName, value] of Object.entries(node.inputs)) {
|
|
31786
|
-
if (!isConnectionValue(value)) {
|
|
31787
|
-
continue;
|
|
31788
|
-
}
|
|
31789
|
-
const sourceNodeId = String(value[0]);
|
|
31790
|
-
const consumers = consumerMap.get(sourceNodeId) ?? [];
|
|
31791
|
-
consumers.push({
|
|
31792
|
-
inputName,
|
|
31793
|
-
classType: node.class_type,
|
|
31794
|
-
nodeId
|
|
31795
|
-
});
|
|
31796
|
-
consumerMap.set(sourceNodeId, consumers);
|
|
31797
|
-
}
|
|
31798
|
-
}
|
|
31799
|
-
const editableInputs = [];
|
|
31800
|
-
for (const [nodeId, node] of Object.entries(prompt)) {
|
|
31801
|
-
for (const [inputName, value] of Object.entries(node.inputs)) {
|
|
31802
|
-
if (isConnectionValue(value)) {
|
|
31803
|
-
continue;
|
|
31804
|
-
}
|
|
31805
|
-
editableInputs.push({
|
|
31806
|
-
path: `${nodeId}.inputs.${inputName}`,
|
|
31807
|
-
node_id: nodeId,
|
|
31808
|
-
class_type: node.class_type,
|
|
31809
|
-
input_name: inputName,
|
|
31810
|
-
value,
|
|
31811
|
-
value_preview: formatValuePreview(value),
|
|
31812
|
-
role: inferEditableRole(
|
|
31813
|
-
nodeId,
|
|
31814
|
-
node.class_type,
|
|
31815
|
-
inputName,
|
|
31816
|
-
consumerMap
|
|
31817
|
-
),
|
|
31818
|
-
aliases: [],
|
|
31819
|
-
expected_type: getExpectedTypeName(
|
|
31820
|
-
getInputDefinition(objectInfo, prompt, nodeId, inputName)
|
|
31821
|
-
),
|
|
31822
|
-
...getInputOptionsSummary(
|
|
31823
|
-
getInputDefinition(objectInfo, prompt, nodeId, inputName)
|
|
31824
|
-
)
|
|
31825
|
-
});
|
|
31826
|
-
}
|
|
31827
|
-
}
|
|
31828
|
-
return editableInputs.map((entry) => ({
|
|
31829
|
-
...entry,
|
|
31830
|
-
aliases: getEditableAliases(
|
|
31831
|
-
entry.path,
|
|
31832
|
-
entry.node_id,
|
|
31833
|
-
entry.input_name,
|
|
31834
|
-
entry.role,
|
|
31835
|
-
widgetPathMap
|
|
31836
|
-
)
|
|
31837
|
-
})).sort(
|
|
31838
|
-
(left, right) => left.path.localeCompare(right.path, void 0, { numeric: true })
|
|
31839
|
-
);
|
|
31840
|
-
}
|
|
31841
|
-
function formatEditableInputsText(editableInputs, options = {}) {
|
|
31842
|
-
if (editableInputs.length === 0) {
|
|
31843
|
-
return "No literal editable inputs were detected.";
|
|
31844
|
-
}
|
|
31845
|
-
return formatListItems(editableInputs, (entry) => {
|
|
31846
|
-
const role = entry.role ? ` [${entry.role}]` : "";
|
|
31847
|
-
const classType = entry.class_type ? ` (${entry.class_type})` : "";
|
|
31848
|
-
const expectedType = entry.expected_type ? ` <${entry.expected_type}>` : "";
|
|
31849
|
-
const aliasSuffix = entry.aliases.length > 0 ? ` | aliases: ${entry.aliases.join(", ")}` : "";
|
|
31850
|
-
const optionsSuffix = options.includeOptions ? formatEditableInputOptionsText(entry) : "";
|
|
31851
|
-
return `${entry.path}${role}${classType}${expectedType}: ${entry.value_preview}${aliasSuffix}${optionsSuffix}`;
|
|
31852
|
-
});
|
|
31853
|
-
}
|
|
31854
31938
|
function validatePromptPreflight(prompt, objectInfo, widgetPathMap = {}) {
|
|
31855
31939
|
if (!objectInfo) {
|
|
31856
31940
|
return {
|
|
@@ -31904,106 +31988,6 @@ ${issues.join("\n")}`,
|
|
|
31904
31988
|
combo_inputs: comboInputs
|
|
31905
31989
|
};
|
|
31906
31990
|
}
|
|
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
|
-
}
|
|
31998
|
-
function deriveSavedWorkflowFileName(sourcePath, requestedName) {
|
|
31999
|
-
if (requestedName) {
|
|
32000
|
-
return normalizeWorkflowFileName(requestedName);
|
|
32001
|
-
}
|
|
32002
|
-
if (sourcePath) {
|
|
32003
|
-
return normalizeWorkflowFileName(path.basename(sourcePath));
|
|
32004
|
-
}
|
|
32005
|
-
return `workflow-${Date.now()}.json`;
|
|
32006
|
-
}
|
|
32007
31991
|
function applyOverrides(prompt, overrides, options = {}) {
|
|
32008
31992
|
for (const [rawKey, value] of Object.entries(overrides)) {
|
|
32009
31993
|
const key = resolveOverridePath(prompt, rawKey, options.editableIndex);
|
|
@@ -32012,7 +31996,7 @@ function applyOverrides(prompt, overrides, options = {}) {
|
|
|
32012
31996
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
32013
31997
|
const part = parts[i];
|
|
32014
31998
|
const next = current[part];
|
|
32015
|
-
if (!
|
|
31999
|
+
if (!isRecord(next) || Array.isArray(next)) {
|
|
32016
32000
|
const pathHelp = getPathSegmentHelp(prompt, key);
|
|
32017
32001
|
const validPaths = pathHelp?.nodeId && pathHelp.nodeExists ? describeAvailableNodePaths(
|
|
32018
32002
|
options.editableIndex,
|
|
@@ -32040,6 +32024,63 @@ ${validPaths}` : "";
|
|
|
32040
32024
|
current[parts[parts.length - 1]] = value;
|
|
32041
32025
|
}
|
|
32042
32026
|
}
|
|
32027
|
+
|
|
32028
|
+
// src/index.ts
|
|
32029
|
+
var PACKAGE_VERSION = getPackageVersion(import.meta.url);
|
|
32030
|
+
function handleComfyError(error48) {
|
|
32031
|
+
if (error48 instanceof zod_exports.ZodError) {
|
|
32032
|
+
return createValidationError(
|
|
32033
|
+
"arguments",
|
|
32034
|
+
error48.issues[0]?.message || "Invalid input."
|
|
32035
|
+
);
|
|
32036
|
+
}
|
|
32037
|
+
if (error48 instanceof WorkflowInputError) {
|
|
32038
|
+
return error48.kind === "not_found" ? createNotFoundError(error48.message) : createValidationError(error48.field, error48.message);
|
|
32039
|
+
}
|
|
32040
|
+
if (error48 instanceof ComfyApiError) {
|
|
32041
|
+
const detailSummary = summarizeComfyErrorDetails(error48.details);
|
|
32042
|
+
return {
|
|
32043
|
+
content: [
|
|
32044
|
+
{
|
|
32045
|
+
type: "text",
|
|
32046
|
+
text: detailSummary.length > 0 ? `${error48.message}
|
|
32047
|
+
${detailSummary}` : error48.message
|
|
32048
|
+
}
|
|
32049
|
+
],
|
|
32050
|
+
structuredContent: toStructuredContent(error48.details),
|
|
32051
|
+
isError: true
|
|
32052
|
+
};
|
|
32053
|
+
}
|
|
32054
|
+
if (error48 instanceof WorkflowTimeoutError) {
|
|
32055
|
+
const queueSummary = formatQueueSnapshotText(error48.queueSnapshot);
|
|
32056
|
+
const promptVisibility = getPromptQueueVisibility(
|
|
32057
|
+
error48.promptId,
|
|
32058
|
+
error48.queueSnapshot
|
|
32059
|
+
);
|
|
32060
|
+
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.";
|
|
32061
|
+
return {
|
|
32062
|
+
content: [
|
|
32063
|
+
{
|
|
32064
|
+
type: "text",
|
|
32065
|
+
text: [
|
|
32066
|
+
`${error48.message}.`,
|
|
32067
|
+
queueSummary,
|
|
32068
|
+
promptVisibilityText,
|
|
32069
|
+
`You can re-attach by calling 'comfyui_wait_for_workflow' again with prompt_id '${error48.promptId}'.`
|
|
32070
|
+
].filter((line) => line && line.length > 0).join("\n")
|
|
32071
|
+
}
|
|
32072
|
+
],
|
|
32073
|
+
structuredContent: {
|
|
32074
|
+
prompt_id: error48.promptId,
|
|
32075
|
+
timeout_seconds: error48.timeoutSeconds,
|
|
32076
|
+
queue: error48.queueSnapshot ?? null,
|
|
32077
|
+
prompt_visible_in_queue: promptVisibility
|
|
32078
|
+
},
|
|
32079
|
+
isError: true
|
|
32080
|
+
};
|
|
32081
|
+
}
|
|
32082
|
+
return createInternalError(error48);
|
|
32083
|
+
}
|
|
32043
32084
|
var InspectNodeSchema = paginationSchema.extend({
|
|
32044
32085
|
node_class: z3.string().optional().describe(
|
|
32045
32086
|
"Specific node class to inspect. If omitted, lists all available nodes."
|
|
@@ -32139,9 +32180,6 @@ async function handleInspectNode(args) {
|
|
|
32139
32180
|
return handleComfyError(error48);
|
|
32140
32181
|
}
|
|
32141
32182
|
}
|
|
32142
|
-
function getWorkflowId(absolutePath) {
|
|
32143
|
-
return crypto.createHash("sha256").update(absolutePath).digest("hex").substring(0, 8);
|
|
32144
|
-
}
|
|
32145
32183
|
async function handleDiscoverWorkflows(args) {
|
|
32146
32184
|
const pathsToScan = getWorkflowDirectories(args.directory_path);
|
|
32147
32185
|
const objectInfoAvailability = await tryGetObjectInfo();
|
|
@@ -32149,10 +32187,10 @@ async function handleDiscoverWorkflows(args) {
|
|
|
32149
32187
|
let skippedNonWorkflowFiles = 0;
|
|
32150
32188
|
for (const dir of pathsToScan) {
|
|
32151
32189
|
try {
|
|
32152
|
-
const entries = await
|
|
32190
|
+
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
32153
32191
|
for (const entry of entries) {
|
|
32154
32192
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
32155
|
-
const fullPath =
|
|
32193
|
+
const fullPath = path3.join(dir, entry.name);
|
|
32156
32194
|
try {
|
|
32157
32195
|
const inspected = await inspectWorkflowFile(
|
|
32158
32196
|
fullPath,
|
|
@@ -32237,28 +32275,6 @@ Hint: If your workflows are stored elsewhere, provide a custom path using the 'd
|
|
|
32237
32275
|
}
|
|
32238
32276
|
};
|
|
32239
32277
|
}
|
|
32240
|
-
async function waitForWorkflowResult(prompt_id, timeout_seconds) {
|
|
32241
|
-
const start = Date.now();
|
|
32242
|
-
const end = start + timeout_seconds * 1e3;
|
|
32243
|
-
while (Date.now() < end) {
|
|
32244
|
-
let history = MOCK_FIXTURES.history;
|
|
32245
|
-
if (!IS_MOCK) {
|
|
32246
|
-
try {
|
|
32247
|
-
history = await fetchComfyJson(
|
|
32248
|
-
`/history/${prompt_id}`
|
|
32249
|
-
);
|
|
32250
|
-
} catch {
|
|
32251
|
-
history = {};
|
|
32252
|
-
}
|
|
32253
|
-
}
|
|
32254
|
-
if (history?.[prompt_id]) {
|
|
32255
|
-
return history[prompt_id];
|
|
32256
|
-
}
|
|
32257
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
32258
|
-
}
|
|
32259
|
-
const queueSnapshot = await getQueueSnapshot();
|
|
32260
|
-
throw new WorkflowTimeoutError(prompt_id, timeout_seconds, queueSnapshot);
|
|
32261
|
-
}
|
|
32262
32278
|
async function handleWaitForWorkflow(args) {
|
|
32263
32279
|
try {
|
|
32264
32280
|
const historyEntry = await waitForWorkflowResult(
|
|
@@ -32438,11 +32454,11 @@ async function handleSaveWorkflow(args) {
|
|
|
32438
32454
|
"Directory traversal sequences (..) are not allowed."
|
|
32439
32455
|
);
|
|
32440
32456
|
}
|
|
32441
|
-
const outputPath =
|
|
32442
|
-
await
|
|
32457
|
+
const outputPath = path3.resolve(process.cwd(), outputFileName);
|
|
32458
|
+
await fs3.mkdir(path3.dirname(outputPath), { recursive: true });
|
|
32443
32459
|
let existedBeforeSave = false;
|
|
32444
32460
|
try {
|
|
32445
|
-
await
|
|
32461
|
+
await fs3.access(outputPath);
|
|
32446
32462
|
existedBeforeSave = true;
|
|
32447
32463
|
} catch {
|
|
32448
32464
|
existedBeforeSave = false;
|
|
@@ -32453,7 +32469,7 @@ async function handleSaveWorkflow(args) {
|
|
|
32453
32469
|
`File already exists: ${outputFileName}. Set overwrite=true to replace it.`
|
|
32454
32470
|
);
|
|
32455
32471
|
}
|
|
32456
|
-
await
|
|
32472
|
+
await fs3.writeFile(
|
|
32457
32473
|
outputPath,
|
|
32458
32474
|
`${JSON.stringify(prompt, null, 2)}
|
|
32459
32475
|
`,
|