n8n-nodes-comfyui-all 2.2.24 → 2.3.1

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.
@@ -29,6 +29,12 @@ export declare class ComfyUiTool {
29
29
  notes: string[];
30
30
  inputSample: {
31
31
  query: string;
32
+ parameters: {
33
+ seed: number;
34
+ steps: number;
35
+ width: number;
36
+ height: number;
37
+ };
32
38
  };
33
39
  outputSample: {
34
40
  json: {
@@ -45,13 +51,6 @@ export declare class ComfyUiTool {
45
51
  seed: number;
46
52
  };
47
53
  };
48
- binary: {
49
- data: {
50
- data: string;
51
- mimeType: string;
52
- fileName: string;
53
- };
54
- };
55
54
  };
56
55
  properties: ({
57
56
  displayName: string;
@@ -62,8 +61,10 @@ export declare class ComfyUiTool {
62
61
  description: string;
63
62
  minValue?: undefined;
64
63
  maxValue?: undefined;
64
+ typeOptions?: undefined;
65
+ validate?: undefined;
65
66
  placeholder?: undefined;
66
- options?: undefined;
67
+ displayOptions?: undefined;
67
68
  } | {
68
69
  displayName: string;
69
70
  name: string;
@@ -73,55 +74,84 @@ export declare class ComfyUiTool {
73
74
  minValue: number;
74
75
  maxValue: number;
75
76
  required?: undefined;
77
+ typeOptions?: undefined;
78
+ validate?: undefined;
76
79
  placeholder?: undefined;
77
- options?: undefined;
80
+ displayOptions?: undefined;
78
81
  } | {
79
82
  displayName: string;
80
83
  name: string;
81
84
  type: string;
85
+ required: boolean;
86
+ typeOptions: {
87
+ rows: number;
88
+ loadOptionsMethod?: undefined;
89
+ };
82
90
  default: string;
83
91
  description: string;
92
+ validate: (parameterValue: string) => Promise<string | undefined>;
93
+ minValue?: undefined;
94
+ maxValue?: undefined;
95
+ placeholder?: undefined;
96
+ displayOptions?: undefined;
97
+ } | {
98
+ displayName: string;
99
+ name: string;
100
+ type: string;
101
+ description: string;
102
+ typeOptions: {
103
+ loadOptionsMethod: string;
104
+ rows?: undefined;
105
+ };
84
106
  placeholder: string;
107
+ default: string;
85
108
  required?: undefined;
86
109
  minValue?: undefined;
87
110
  maxValue?: undefined;
88
- options?: undefined;
111
+ validate?: undefined;
112
+ displayOptions?: undefined;
89
113
  } | {
90
114
  displayName: string;
91
115
  name: string;
92
116
  type: string;
117
+ description: string;
118
+ typeOptions: {
119
+ loadOptionsMethod: string;
120
+ rows?: undefined;
121
+ };
93
122
  placeholder: string;
94
- default: {};
95
- options: ({
96
- displayName: string;
97
- name: string;
98
- type: string;
99
- typeOptions: {
100
- rows: number;
123
+ default: never[];
124
+ displayOptions: {
125
+ show: {
126
+ nodeId: (string | null | undefined)[];
127
+ mode: string;
101
128
  };
102
- default: string;
103
- description: string;
104
- minValue?: undefined;
105
- maxValue?: undefined;
106
- } | {
107
- displayName: string;
108
- name: string;
109
- type: string;
110
- default: number;
111
- description: string;
112
- minValue: number;
113
- maxValue: number;
114
- typeOptions?: undefined;
115
- })[];
129
+ };
116
130
  required?: undefined;
117
- description?: undefined;
118
131
  minValue?: undefined;
119
132
  maxValue?: undefined;
133
+ validate?: undefined;
120
134
  })[];
121
135
  };
122
136
  /**
123
137
  * Execute function - called when the node runs
124
138
  */
125
139
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
140
+ /**
141
+ * Load all nodes from workflow JSON for Node ID dropdown
142
+ */
143
+ getWorkflowNodes(this: IExecuteFunctions): Promise<{
144
+ name: string;
145
+ value: string;
146
+ description?: string;
147
+ }[]>;
148
+ /**
149
+ * Load parameters for a specific node for Allowed Parameters multi-select
150
+ */
151
+ getNodeParameters(this: IExecuteFunctions): Promise<{
152
+ name: string;
153
+ value: string;
154
+ description?: string;
155
+ }[]>;
126
156
  }
127
157
  //# sourceMappingURL=ComfyUiTool.node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ComfyUiTool.node.d.ts","sourceRoot":"","sources":["../../../nodes/ComfyUiTool/ComfyUiTool.node.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAEnB,MAAM,cAAc,CAAC;AAgBtB,qBAAa,WAAW;IACtB;;OAEG;IACH,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2IT;IAEF;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAiLxE"}
1
+ {"version":3,"file":"ComfyUiTool.node.d.ts","sourceRoot":"","sources":["../../../nodes/ComfyUiTool/ComfyUiTool.node.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAEnB,MAAM,cAAc,CAAC;AAiBtB,qBAAa,WAAW;IACtB;;OAEG;IACH,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCA+E4B,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAuD3C;IAEF;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;IA+OvE;;OAEG;IACG,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAmCjH;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAsDnH"}
@@ -13,7 +13,6 @@ const ComfyUiClient_1 = require("../ComfyUiClient");
13
13
  const validation_1 = require("../validation");
14
14
  const logger_1 = require("../logger");
15
15
  const agentToolHelpers_1 = require("../agentToolHelpers");
16
- const workflowConfig_1 = require("../workflowConfig");
17
16
  class ComfyUiTool {
18
17
  constructor() {
19
18
  /**
@@ -36,14 +35,23 @@ class ComfyUiTool {
36
35
  outputs: ['main'],
37
36
  subtitle: 'AI Image Generator',
38
37
  notes: [
39
- 'Optimized for AI Agent usage',
40
- 'Automatically detects and handles both text-to-image and image-to-image',
41
- 'For image editing: pass image binary + text description',
42
- 'Supports size, steps, cfg, seed, and negative prompt parameters',
43
- 'Examples: "A beautiful sunset, size:1024x768, steps:30"',
38
+ 'AI Agent-friendly ComfyUI tool',
39
+ 'Requires ComfyUI workflow JSON in API format',
40
+ 'Export workflow: ComfyUI Menu > Export > API Format',
41
+ 'Supports both text-to-image and image-to-image workflows',
42
+ 'Configure which node/parameters AI can modify using "Node ID" and "Allowed Parameters"',
43
+ 'AI Agent provides: { query: "...", parameters: { seed: 123456, steps: 30 } }',
44
+ 'Only parameters in "Allowed Parameters" list will be applied',
45
+ 'Legacy format supported: "A sunset, size:1024x768, steps:30"',
44
46
  ],
45
47
  inputSample: {
46
48
  query: 'A beautiful landscape painting',
49
+ parameters: {
50
+ seed: 123456,
51
+ steps: 30,
52
+ width: 1024,
53
+ height: 768,
54
+ },
47
55
  },
48
56
  outputSample: {
49
57
  json: {
@@ -53,18 +61,11 @@ class ComfyUiTool {
53
61
  prompt: 'A beautiful landscape painting',
54
62
  mode: 'text-to-image',
55
63
  parameters: {
56
- width: 512,
57
- height: 512,
58
- steps: 20,
64
+ width: 1024,
65
+ height: 768,
66
+ steps: 30,
59
67
  cfg: 8,
60
- seed: 123456789,
61
- },
62
- },
63
- binary: {
64
- data: {
65
- data: 'base64_encoded_image_data',
66
- mimeType: 'image/png',
67
- fileName: 'ComfyUI_00001.png',
68
+ seed: 123456,
68
69
  },
69
70
  },
70
71
  },
@@ -87,75 +88,63 @@ class ComfyUiTool {
87
88
  maxValue: 600,
88
89
  },
89
90
  {
90
- displayName: 'Output Binary Key',
91
- name: 'outputBinaryKey',
91
+ displayName: 'Workflow JSON',
92
+ name: 'workflowJson',
92
93
  type: 'string',
93
- default: 'data',
94
- description: 'Property name for the output binary data (e.g., "data", "image", "output")',
95
- placeholder: 'data',
94
+ required: true,
95
+ typeOptions: {
96
+ rows: 20,
97
+ },
98
+ default: '',
99
+ description: 'ComfyUI workflow JSON in API format. Export your workflow from ComfyUI (Menu > Export > API Format) and paste here.',
100
+ validate: async (parameterValue) => {
101
+ if (!parameterValue || parameterValue.trim().length === 0) {
102
+ // eslint-disable-next-line n8n-nodes-base/node-execute-block-wrong-error-thrown
103
+ throw new Error('Workflow JSON is required');
104
+ }
105
+ const validation = (0, validation_1.validateComfyUIWorkflowEnhanced)(parameterValue);
106
+ if (!validation.valid) {
107
+ // eslint-disable-next-line n8n-nodes-base/node-execute-block-wrong-error-thrown
108
+ throw new Error(validation.error || 'Invalid workflow format');
109
+ }
110
+ if (validation.warnings && validation.warnings.length > 0) {
111
+ const warningMessage = 'Workflow validation warnings:\n' +
112
+ validation.warnings.map((w, i) => `${i + 1}. ${w}`).join('\n') +
113
+ '\n\nSuggestions:\n' +
114
+ (validation.suggestions?.map((s, i) => `${i + 1}. ${s}`).join('\n') || '');
115
+ // Return warning message (doesn't block save, but shows warning)
116
+ return warningMessage;
117
+ }
118
+ return undefined;
119
+ },
96
120
  },
97
121
  {
98
- displayName: 'Default Negative Prompt',
99
- name: 'defaultNegativePrompt',
100
- type: 'string',
101
- default: 'ugly, blurry, low quality, distorted',
102
- description: 'Default negative prompt to use when not specified in query',
103
- placeholder: 'ugly, blurry, low quality',
122
+ displayName: 'Node Name or ID',
123
+ name: 'nodeId',
124
+ type: 'options',
125
+ description: 'Select a node from your workflow. AI will be able to modify parameters of this node. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
126
+ typeOptions: {
127
+ loadOptionsMethod: 'getWorkflowNodes',
128
+ },
129
+ placeholder: 'Select a node to configure AI-accessible parameters...',
130
+ default: '',
104
131
  },
105
132
  {
106
- displayName: 'Advanced Options',
107
- name: 'advancedOptions',
108
- type: 'collection',
109
- placeholder: 'Add Option',
110
- default: {},
111
- options: [
112
- {
113
- displayName: 'Custom Workflow JSON',
114
- name: 'customWorkflow',
115
- type: 'string',
116
- typeOptions: {
117
- rows: 20,
118
- },
119
- default: '',
120
- description: 'Optional: Custom ComfyUI workflow JSON (API Format). If empty, uses default workflow. Only use this if you want to override the default template.',
121
- },
122
- {
123
- displayName: 'Default CFG',
124
- name: 'defaultCfg',
125
- type: 'number',
126
- default: 8,
127
- description: 'Default CFG scale when not specified in query',
128
- minValue: 1,
129
- maxValue: 30,
130
- },
131
- {
132
- displayName: 'Default Height',
133
- name: 'defaultHeight',
134
- type: 'number',
135
- default: 512,
136
- description: 'Default image height when not specified in query',
137
- minValue: 64,
138
- maxValue: 4096,
139
- },
140
- {
141
- displayName: 'Default Steps',
142
- name: 'defaultSteps',
143
- type: 'number',
144
- default: 20,
145
- description: 'Default sampling steps when not specified in query',
146
- minValue: 1,
147
- maxValue: 150,
148
- },
149
- {
150
- displayName: 'Default Width',
151
- name: 'defaultWidth',
152
- type: 'number',
153
- default: 512,
154
- description: 'Default image width when not specified in query',
155
- minValue: 64,
156
- maxValue: 4096,
133
+ displayName: 'Allowed Parameter Names or IDs',
134
+ name: 'allowedParameters',
135
+ type: 'multiOptions',
136
+ description: 'Select which parameters of this node AI can modify. Parameters will be loaded from the selected node. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
137
+ typeOptions: {
138
+ loadOptionsMethod: 'getNodeParameters',
139
+ },
140
+ placeholder: 'Select parameters...',
141
+ default: [],
142
+ displayOptions: {
143
+ show: {
144
+ nodeId: ['', null, undefined],
145
+ mode: 'invert',
157
146
  },
158
- ],
147
+ },
159
148
  },
160
149
  ],
161
150
  };
@@ -168,16 +157,15 @@ class ComfyUiTool {
168
157
  // Get node parameters
169
158
  const comfyUiUrl = this.getNodeParameter('comfyUiUrl', 0);
170
159
  const timeout = this.getNodeParameter('timeout', 0);
171
- const outputBinaryKey = this.getNodeParameter('outputBinaryKey', 0);
172
- const defaultNegativePrompt = this.getNodeParameter('defaultNegativePrompt', 0);
173
- const advancedOptions = this.getNodeParameter('advancedOptions', 0);
174
- const { customWorkflow = '', defaultWidth = 512, defaultHeight = 512, defaultSteps = 20, defaultCfg = 8, } = advancedOptions || {};
160
+ const workflowJson = this.getNodeParameter('workflowJson', 0);
175
161
  // Validate URL
176
162
  if (!(0, validation_1.validateUrl)(comfyUiUrl)) {
177
163
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid ComfyUI URL. Must be a valid HTTP/HTTPS URL.');
178
164
  }
179
- // Validate output binary key
180
- (0, validation_1.validateOutputBinaryKey)(outputBinaryKey);
165
+ // Validate workflow JSON
166
+ if (!workflowJson || workflowJson.trim().length === 0) {
167
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Workflow JSON is required. Please export your ComfyUI workflow (Menu > Export > API Format) and paste it in the "Workflow JSON" field.');
168
+ }
181
169
  // Get input data
182
170
  const inputData = this.getInputData();
183
171
  if (!inputData || inputData.length === 0) {
@@ -195,32 +183,83 @@ class ComfyUiTool {
195
183
  if (!query || query.trim().length === 0) {
196
184
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No query found in input. Please provide a "query", "text", or "prompt" field with a description of the image you want to generate.');
197
185
  }
198
- // Determine mode based on input
199
- const mode = hasInputImage ? 'image-to-image' : 'text-to-image';
200
- logger.info('Processing image generation request', { query, comfyUiUrl, timeout, mode });
201
- // Parse the query to extract parameters
202
- const params = (0, agentToolHelpers_1.parseInput)(query, {
203
- negativePrompt: defaultNegativePrompt,
204
- width: defaultWidth,
205
- height: defaultHeight,
206
- steps: defaultSteps,
207
- cfg: defaultCfg,
208
- });
209
- logger.debug('Parsed parameters', {
210
- prompt: params.prompt,
211
- width: params.width,
212
- height: params.height,
213
- steps: params.steps,
214
- cfg: params.cfg,
215
- seed: params.seed,
216
- });
217
- // Get workflow template
186
+ // Parse workflow JSON (already validated in parameter validation)
218
187
  let workflowTemplate;
219
- if (customWorkflow && customWorkflow.trim().length > 0) {
220
- workflowTemplate = (0, validation_1.safeJsonParse)(customWorkflow, 'Custom workflow JSON');
188
+ try {
189
+ workflowTemplate = (0, validation_1.safeJsonParse)(workflowJson, 'Workflow JSON');
190
+ }
191
+ catch (error) {
192
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid Workflow JSON: ${error instanceof Error ? error.message : String(error)}`);
193
+ }
194
+ // Check if structured parameters are provided
195
+ const structuredParams = firstItem.json.parameters;
196
+ // Get node configuration (which node/parameters AI can modify)
197
+ const configuredNodeId = this.getNodeParameter('nodeId', 0);
198
+ const allowedParams = this.getNodeParameter('allowedParameters', 0) || [];
199
+ let params;
200
+ let workflow = workflowTemplate;
201
+ let usedStructuredParams = false;
202
+ if (structuredParams && typeof structuredParams === 'object' && Object.keys(structuredParams).length > 0) {
203
+ // Use structured parameters from AI Agent
204
+ logger.info('Using structured parameters from input', { parameters: structuredParams });
205
+ // Filter parameters based on allowed list
206
+ let filteredParams = structuredParams;
207
+ if (configuredNodeId && allowedParams.length > 0) {
208
+ filteredParams = {};
209
+ for (const paramName of allowedParams) {
210
+ if (paramName in structuredParams) {
211
+ filteredParams[paramName] = structuredParams[paramName];
212
+ }
213
+ }
214
+ logger.info('Filtered parameters based on allowed list', {
215
+ configuredNodeId,
216
+ allowedParams,
217
+ filteredParams,
218
+ });
219
+ }
220
+ // Convert structured parameters to ParsedParameters format
221
+ // Use filteredParams when available to ensure response only includes allowed parameters
222
+ const sourceParams = (configuredNodeId && allowedParams.length > 0) ? filteredParams : structuredParams;
223
+ params = {
224
+ prompt: query,
225
+ negative_prompt: sourceParams.negative_prompt ||
226
+ sourceParams.negative ||
227
+ structuredParams.negative_prompt ||
228
+ structuredParams.negative ||
229
+ 'ugly, blurry, low quality, distorted',
230
+ width: sourceParams.width || 512,
231
+ height: sourceParams.height || 512,
232
+ steps: sourceParams.steps || 20,
233
+ cfg: sourceParams.cfg || 8,
234
+ seed: sourceParams.seed || Math.floor(Math.random() * 2147483647),
235
+ };
236
+ // Apply filtered parameters to the configured node
237
+ if (configuredNodeId && Object.keys(filteredParams).length > 0) {
238
+ workflow = (0, agentToolHelpers_1.applyParametersToNode)(workflowTemplate, configuredNodeId, filteredParams);
239
+ usedStructuredParams = true;
240
+ logger.debug('Applied filtered parameters to configured node', {
241
+ nodeId: configuredNodeId,
242
+ params: filteredParams,
243
+ });
244
+ }
245
+ else if (Object.keys(structuredParams).length > 0) {
246
+ // Fallback to old behavior if no node configured
247
+ workflow = (0, agentToolHelpers_1.applyStructuredParameters)(workflowTemplate, structuredParams);
248
+ usedStructuredParams = true;
249
+ logger.debug('Applied structured parameters (auto-mapped)', structuredParams);
250
+ }
221
251
  }
222
252
  else {
223
- workflowTemplate = (0, workflowConfig_1.getWorkflowTemplate)({ mode });
253
+ // Parse the query to extract parameters (legacy behavior)
254
+ params = (0, agentToolHelpers_1.parseInput)(query);
255
+ logger.debug('Parsed parameters from query', {
256
+ prompt: params.prompt,
257
+ width: params.width,
258
+ height: params.height,
259
+ steps: params.steps,
260
+ cfg: params.cfg,
261
+ seed: params.seed,
262
+ });
224
263
  }
225
264
  // Create ComfyUI client
226
265
  const client = new ComfyUiClient_1.ComfyUIClient({
@@ -251,8 +290,11 @@ class ComfyUiTool {
251
290
  uploadedImageFilename = await client.uploadImage(buffer, binaryData.fileName || 'input_image.png');
252
291
  logger.info('Successfully uploaded input image', { filename: uploadedImageFilename });
253
292
  }
254
- // Update workflow with parsed parameters
255
- let workflow = (0, agentToolHelpers_1.updateWorkflow)(workflowTemplate, params);
293
+ // Update workflow with parsed parameters (only in legacy mode)
294
+ // Skip if structured parameters were already applied
295
+ if (!usedStructuredParams) {
296
+ workflow = (0, agentToolHelpers_1.updateWorkflow)(workflow, params);
297
+ }
256
298
  // If we uploaded an image, update workflow with the image filename
257
299
  if (uploadedImageFilename) {
258
300
  workflow = (0, agentToolHelpers_1.updateWorkflowWithImage)(workflow, uploadedImageFilename);
@@ -263,13 +305,24 @@ class ComfyUiTool {
263
305
  logger.error('Workflow execution failed', result.error);
264
306
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to generate image: ${result.error}`);
265
307
  }
266
- // Process results
267
- const { json, binary } = await client.processResults(result, outputBinaryKey);
268
- // Add metadata to JSON output
308
+ // Only return URLs without downloading (for AI Agent)
309
+ // Fix URL concatenation to handle trailing/leading slashes
310
+ const baseUrl = comfyUiUrl.endsWith('/') ? comfyUiUrl.slice(0, -1) : comfyUiUrl;
311
+ const imageUrls = result.images ? result.images.map(img => {
312
+ const imagePath = img.startsWith('/') ? img : `/${img}`;
313
+ return `${baseUrl}${imagePath}`;
314
+ }) : [];
315
+ const videoUrls = result.videos ? result.videos.map(vid => {
316
+ const videoPath = vid.startsWith('/') ? vid : `/${vid}`;
317
+ return `${baseUrl}${videoPath}`;
318
+ }) : [];
269
319
  const enhancedJson = {
270
- ...json,
320
+ success: true,
321
+ imageUrls,
322
+ videoUrls,
323
+ imageCount: result.images?.length || 0,
324
+ videoCount: result.videos?.length || 0,
271
325
  prompt: params.prompt,
272
- mode: mode,
273
326
  parameters: {
274
327
  width: params.width,
275
328
  height: params.height,
@@ -280,10 +333,10 @@ class ComfyUiTool {
280
333
  },
281
334
  };
282
335
  logger.info('Image generation completed successfully', {
283
- imageCount: json.imageCount,
284
- mode,
336
+ imageCount: enhancedJson.imageCount,
285
337
  });
286
- return [this.helpers.constructExecutionMetaData([{ json: enhancedJson, binary }], { itemData: { item: 0 } })];
338
+ // Return result (no binary data for AI Agent)
339
+ return [this.helpers.constructExecutionMetaData([{ json: enhancedJson }], { itemData: { item: 0 } })];
287
340
  }
288
341
  catch (error) {
289
342
  logger.error('Error during workflow execution', error);
@@ -294,6 +347,89 @@ class ComfyUiTool {
294
347
  logger.debug('Client destroyed');
295
348
  }
296
349
  }
350
+ /**
351
+ * Load all nodes from workflow JSON for Node ID dropdown
352
+ */
353
+ async getWorkflowNodes() {
354
+ try {
355
+ const workflowJson = this.getNodeParameter('workflowJson', 0);
356
+ if (!workflowJson || workflowJson.trim().length === 0) {
357
+ return [];
358
+ }
359
+ const workflow = (0, validation_1.safeJsonParse)(workflowJson, 'Workflow JSON');
360
+ const nodes = [];
361
+ for (const [nodeId, nodeData] of Object.entries(workflow)) {
362
+ if (nodeData && nodeData.class_type) {
363
+ nodes.push({
364
+ name: `${nodeId} - ${nodeData.class_type}`,
365
+ value: nodeId,
366
+ description: nodeData.class_type,
367
+ });
368
+ }
369
+ }
370
+ // Sort by node ID (numeric)
371
+ nodes.sort((a, b) => {
372
+ const aNum = parseInt(a.value);
373
+ const bNum = parseInt(b.value);
374
+ return aNum - bNum;
375
+ });
376
+ return nodes;
377
+ }
378
+ catch (error) {
379
+ // Silently return empty array on error
380
+ return [];
381
+ }
382
+ }
383
+ /**
384
+ * Load parameters for a specific node for Allowed Parameters multi-select
385
+ */
386
+ async getNodeParameters() {
387
+ try {
388
+ const workflowJson = this.getNodeParameter('workflowJson', 0);
389
+ const nodeId = this.getNodeParameter('nodeId', 0);
390
+ if (!workflowJson || workflowJson.trim().length === 0 || !nodeId) {
391
+ return [];
392
+ }
393
+ const workflow = (0, validation_1.safeJsonParse)(workflowJson, 'Workflow JSON');
394
+ const nodeData = workflow[nodeId];
395
+ if (!nodeData || !nodeData.inputs) {
396
+ return [];
397
+ }
398
+ const parameters = [];
399
+ for (const [paramName, paramValue] of Object.entries(nodeData.inputs)) {
400
+ // Skip array values (these are connections to other nodes)
401
+ if (Array.isArray(paramValue)) {
402
+ continue;
403
+ }
404
+ // Auto-detect type for display
405
+ let detectedType = 'text';
406
+ if (paramName.toLowerCase().includes('image') || paramName.toLowerCase().includes('upload')) {
407
+ detectedType = 'image';
408
+ }
409
+ else if (typeof paramValue === 'boolean') {
410
+ detectedType = 'boolean';
411
+ }
412
+ else if (typeof paramValue === 'number') {
413
+ detectedType = 'number';
414
+ }
415
+ // Add parameter with value and type as description
416
+ const valueStr = String(paramValue);
417
+ const description = `Type: ${detectedType} | Current value: ${valueStr.length > 50 ? valueStr.substring(0, 50) + '...' : valueStr}`;
418
+ parameters.push({
419
+ name: paramName,
420
+ value: paramName,
421
+ description: description,
422
+ });
423
+ }
424
+ // Sort alphabetically
425
+ parameters.sort((a, b) => a.name.localeCompare(b.name));
426
+ return parameters;
427
+ }
428
+ catch (error) {
429
+ // Silently return empty array on error
430
+ return [];
431
+ }
432
+ }
297
433
  }
298
434
  exports.ComfyUiTool = ComfyUiTool;
299
435
  //# sourceMappingURL=ComfyUiTool.node.js.map