n8n-nodes-comfyui-all 2.4.1 → 2.4.3

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.
@@ -1,9 +1,9 @@
1
1
  /**
2
- * ComfyUI Tool - AI Agent-friendly image generation node
2
+ * ComfyUI Tool - Simplified workflow execution node for AI Agents
3
3
  *
4
- * This node is designed to be used as an AI Agent tool with minimal configuration.
5
- * It accepts a simple text query and automatically generates images using ComfyUI.
6
- * Supports both Text-to-Image and Image-to-Image workflows.
4
+ * This is a simplified node designed for AI Agent usage. It executes
5
+ * ComfyUI workflows provided by the user without making assumptions
6
+ * about workflow structure or node types.
7
7
  */
8
8
  import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
9
9
  export declare class ComfyUiTool {
@@ -28,22 +28,13 @@ export declare class ComfyUiTool {
28
28
  subtitle: string;
29
29
  notes: string[];
30
30
  inputSample: {
31
- query: string;
31
+ workflowJson: string;
32
32
  };
33
33
  outputSample: {
34
34
  json: {
35
35
  success: boolean;
36
36
  imageCount: number;
37
37
  imageUrls: string[];
38
- prompt: string;
39
- mode: string;
40
- parameters: {
41
- width: number;
42
- height: number;
43
- steps: number;
44
- cfg: number;
45
- seed: number;
46
- };
47
38
  };
48
39
  };
49
40
  properties: ({
@@ -53,9 +44,26 @@ export declare class ComfyUiTool {
53
44
  required: boolean;
54
45
  default: string;
55
46
  description: string;
47
+ typeOptions?: undefined;
48
+ placeholder?: undefined;
49
+ hint?: undefined;
50
+ minValue?: undefined;
51
+ maxValue?: undefined;
52
+ options?: undefined;
53
+ } | {
54
+ displayName: string;
55
+ name: string;
56
+ type: string;
57
+ typeOptions: {
58
+ rows: number;
59
+ };
60
+ required: boolean;
61
+ default: string;
62
+ description: string;
63
+ placeholder: string;
64
+ hint: string;
56
65
  minValue?: undefined;
57
66
  maxValue?: undefined;
58
- placeholder?: undefined;
59
67
  options?: undefined;
60
68
  } | {
61
69
  displayName: string;
@@ -66,7 +74,9 @@ export declare class ComfyUiTool {
66
74
  minValue: number;
67
75
  maxValue: number;
68
76
  required?: undefined;
77
+ typeOptions?: undefined;
69
78
  placeholder?: undefined;
79
+ hint?: undefined;
70
80
  options?: undefined;
71
81
  } | {
72
82
  displayName: string;
@@ -76,6 +86,8 @@ export declare class ComfyUiTool {
76
86
  description: string;
77
87
  placeholder: string;
78
88
  required?: undefined;
89
+ typeOptions?: undefined;
90
+ hint?: undefined;
79
91
  minValue?: undefined;
80
92
  maxValue?: undefined;
81
93
  options?: undefined;
@@ -85,29 +97,42 @@ export declare class ComfyUiTool {
85
97
  type: string;
86
98
  placeholder: string;
87
99
  default: {};
88
- options: ({
89
- displayName: string;
90
- name: string;
91
- type: string;
92
- typeOptions: {
93
- rows: number;
94
- };
95
- default: string;
96
- description: string;
97
- minValue?: undefined;
98
- maxValue?: undefined;
99
- } | {
100
+ description: string;
101
+ options: {
100
102
  displayName: string;
101
103
  name: string;
102
104
  type: string;
103
- default: number;
104
- description: string;
105
- minValue: number;
106
- maxValue: number;
107
- typeOptions?: undefined;
108
- })[];
105
+ placeholder: string;
106
+ default: {};
107
+ options: ({
108
+ displayName: string;
109
+ name: string;
110
+ type: string;
111
+ default: string;
112
+ description: string;
113
+ placeholder: string;
114
+ required?: undefined;
115
+ } | {
116
+ displayName: string;
117
+ name: string;
118
+ type: string;
119
+ required: boolean;
120
+ default: string;
121
+ description: string;
122
+ placeholder: string;
123
+ } | {
124
+ displayName: string;
125
+ name: string;
126
+ type: string;
127
+ default: string;
128
+ description: string;
129
+ placeholder?: undefined;
130
+ required?: undefined;
131
+ })[];
132
+ }[];
109
133
  required?: undefined;
110
- description?: undefined;
134
+ typeOptions?: undefined;
135
+ hint?: undefined;
111
136
  minValue?: undefined;
112
137
  maxValue?: undefined;
113
138
  })[];
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA4HT;IAEF;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAkLxE"}
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;AActB,qBAAa,WAAW;IACtB;;OAEG;IACH,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2HT;IAEF;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CA+MxE"}
@@ -1,11 +1,44 @@
1
1
  "use strict";
2
2
  /**
3
- * ComfyUI Tool - AI Agent-friendly image generation node
3
+ * ComfyUI Tool - Simplified workflow execution node for AI Agents
4
4
  *
5
- * This node is designed to be used as an AI Agent tool with minimal configuration.
6
- * It accepts a simple text query and automatically generates images using ComfyUI.
7
- * Supports both Text-to-Image and Image-to-Image workflows.
5
+ * This is a simplified node designed for AI Agent usage. It executes
6
+ * ComfyUI workflows provided by the user without making assumptions
7
+ * about workflow structure or node types.
8
8
  */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
9
42
  Object.defineProperty(exports, "__esModule", { value: true });
10
43
  exports.ComfyUiTool = void 0;
11
44
  const n8n_workflow_1 = require("n8n-workflow");
@@ -27,38 +60,28 @@ class ComfyUiTool {
27
60
  group: ['transform'],
28
61
  version: [1],
29
62
  defaultVersion: 1,
30
- description: 'AI-friendly image generation tool. Supports text-to-image and image-to-image.',
63
+ description: 'Execute ComfyUI workflows. Requires a workflow JSON exported from ComfyUI.',
31
64
  defaults: {
32
65
  name: 'ComfyUI Tool',
33
66
  },
34
67
  usableAsTool: true,
35
68
  inputs: ['main'],
36
69
  outputs: ['main'],
37
- subtitle: 'AI Image Generator',
70
+ subtitle: 'ComfyUI Workflow Executor',
38
71
  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"',
72
+ 'You must provide a ComfyUI workflow JSON (API Format)',
73
+ 'In ComfyUI: Design your workflow Click "Save (API Format)" → Copy JSON → Paste here',
74
+ 'Works with ANY ComfyUI workflow: text-to-image, image-to-image, video generation, etc.',
75
+ 'Configure parameters directly in your workflow JSON or use parameter overrides',
44
76
  ],
45
77
  inputSample: {
46
- query: 'A beautiful landscape painting',
78
+ workflowJson: '{ "3": { "inputs": {}, "class_type": "KSampler" } }',
47
79
  },
48
80
  outputSample: {
49
81
  json: {
50
82
  success: true,
51
83
  imageCount: 1,
52
84
  imageUrls: ['http://127.0.0.1:8188/view?filename=ComfyUI_00001.png'],
53
- prompt: 'A beautiful landscape painting',
54
- mode: 'text-to-image',
55
- parameters: {
56
- width: 512,
57
- height: 512,
58
- steps: 20,
59
- cfg: 8,
60
- seed: 123456789,
61
- },
62
85
  },
63
86
  },
64
87
  properties: [
@@ -70,75 +93,84 @@ class ComfyUiTool {
70
93
  default: 'http://127.0.0.1:8188',
71
94
  description: 'URL of ComfyUI server',
72
95
  },
96
+ {
97
+ displayName: 'Workflow JSON',
98
+ name: 'workflowJson',
99
+ type: 'string',
100
+ typeOptions: {
101
+ rows: 20,
102
+ },
103
+ required: true,
104
+ default: '',
105
+ description: 'Paste your ComfyUI workflow JSON (API Format). Required field - no built-in templates.',
106
+ placeholder: 'Paste your ComfyUI workflow JSON (API Format) here...\n\n{\n "3": {\n "inputs": {\n "seed": 123456789,\n ...\n },\n "class_type": "KSampler"\n }\n}',
107
+ hint: 'Required: Export your workflow from ComfyUI in API format and paste it here.',
108
+ },
73
109
  {
74
110
  displayName: 'Timeout (Seconds)',
75
111
  name: 'timeout',
76
112
  type: 'number',
77
- default: 120,
78
- description: 'Maximum time to wait for image generation (in seconds). Default: 120 (2 minutes).',
113
+ default: 300,
114
+ description: 'Maximum time to wait for workflow execution (in seconds). Default: 300 (5 minutes).',
79
115
  minValue: 10,
80
- maxValue: 600,
116
+ maxValue: 3600,
117
+ },
118
+ {
119
+ displayName: 'Load Image Node ID',
120
+ name: 'loadImageNodeId',
121
+ type: 'string',
122
+ default: '',
123
+ description: 'Optional: Node ID of LoadImage node if your workflow uses input images. Leave empty if not using image input.',
124
+ placeholder: 'e.g., 5, 12, load_image_1',
81
125
  },
82
126
  {
83
- displayName: 'Default Negative Prompt',
84
- name: 'defaultNegativePrompt',
127
+ displayName: 'Image Data (Base64 or Path)',
128
+ name: 'imageData',
85
129
  type: 'string',
86
- default: 'ugly, blurry, low quality, distorted',
87
- description: 'Default negative prompt to use when not specified in query',
88
- placeholder: 'ugly, blurry, low quality',
130
+ default: '',
131
+ description: 'Optional: Image data as base64 string (with or without data:image/... prefix) or file path. Use this when passing images from AI Agents or as text parameters.',
132
+ placeholder: 'data:image/png;base64,iVBORw0KG... or /tmp/image.png',
89
133
  },
90
134
  {
91
- displayName: 'Advanced Options',
92
- name: 'advancedOptions',
93
- type: 'collection',
94
- placeholder: 'Add Option',
135
+ displayName: 'Parameter Overrides',
136
+ name: 'parameterOverrides',
137
+ type: 'fixedCollection',
138
+ placeholder: 'Add Parameter Override',
95
139
  default: {},
140
+ description: 'Override specific node parameters at runtime. Useful for dynamic values from input data.',
96
141
  options: [
97
142
  {
98
- displayName: 'Custom Workflow JSON',
99
- name: 'customWorkflow',
100
- type: 'string',
101
- typeOptions: {
102
- rows: 20,
103
- },
104
- default: '',
105
- description: 'Optional: Custom ComfyUI workflow JSON (API Format). If empty, uses default workflow. Only use this if you want to override the default template.',
106
- },
107
- {
108
- displayName: 'Default CFG',
109
- name: 'defaultCfg',
110
- type: 'number',
111
- default: 8,
112
- description: 'Default CFG scale when not specified in query',
113
- minValue: 1,
114
- maxValue: 30,
115
- },
116
- {
117
- displayName: 'Default Height',
118
- name: 'defaultHeight',
119
- type: 'number',
120
- default: 512,
121
- description: 'Default image height when not specified in query',
122
- minValue: 64,
123
- maxValue: 4096,
124
- },
125
- {
126
- displayName: 'Default Steps',
127
- name: 'defaultSteps',
128
- type: 'number',
129
- default: 20,
130
- description: 'Default sampling steps when not specified in query',
131
- minValue: 1,
132
- maxValue: 150,
133
- },
134
- {
135
- displayName: 'Default Width',
136
- name: 'defaultWidth',
137
- type: 'number',
138
- default: 512,
139
- description: 'Default image width when not specified in query',
140
- minValue: 64,
141
- maxValue: 4096,
143
+ displayName: 'Parameter Override',
144
+ name: 'parameterOverride',
145
+ type: 'collection',
146
+ placeholder: 'Add Override',
147
+ default: {},
148
+ options: [
149
+ {
150
+ displayName: 'Node ID',
151
+ name: 'nodeId',
152
+ type: 'string',
153
+ default: '',
154
+ description: 'The node ID to update (e.g., "3", "6", "15")',
155
+ placeholder: 'Node ID from workflow JSON',
156
+ },
157
+ {
158
+ displayName: 'Parameter Path',
159
+ name: 'paramPath',
160
+ type: 'string',
161
+ required: true,
162
+ default: '',
163
+ description: 'Path to the parameter (e.g., "inputs.text", "inputs.seed", "inputs.steps")',
164
+ placeholder: 'inputs.parameter_name',
165
+ },
166
+ {
167
+ displayName: 'Value',
168
+ name: 'value',
169
+ type: 'string',
170
+ default: '',
171
+ description: 'The new value. Can be a static value or an expression (e.g., "{{ $JSON.prompt }}").',
172
+ },
173
+ ],
142
174
  },
143
175
  ],
144
176
  },
@@ -152,58 +184,35 @@ class ComfyUiTool {
152
184
  const logger = (0, logger_1.createLogger)(this.logger);
153
185
  // Get node parameters
154
186
  const comfyUiUrl = this.getNodeParameter('comfyUiUrl', 0);
187
+ const workflowJson = this.getNodeParameter('workflowJson', 0);
155
188
  const timeout = this.getNodeParameter('timeout', 0);
156
- const defaultNegativePrompt = this.getNodeParameter('defaultNegativePrompt', 0);
157
- const advancedOptions = this.getNodeParameter('advancedOptions', 0);
158
- const { customWorkflow = '', defaultWidth = 512, defaultHeight = 512, defaultSteps = 20, defaultCfg = 8, } = advancedOptions || {};
189
+ const loadImageNodeId = this.getNodeParameter('loadImageNodeId', 0);
190
+ const imageData = this.getNodeParameter('imageData', 0);
191
+ const parameterOverrides = this.getNodeParameter('parameterOverrides', 0);
159
192
  // Validate URL
160
193
  if (!(0, validation_1.validateUrl)(comfyUiUrl)) {
161
194
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid ComfyUI URL. Must be a valid HTTP/HTTPS URL.');
162
195
  }
196
+ // Parse and validate workflow
197
+ let workflow;
198
+ try {
199
+ workflow = (0, workflowConfig_1.parseWorkflow)(workflowJson);
200
+ const validation = (0, validation_1.validateComfyUIWorkflow)(workflowJson);
201
+ if (!validation.valid && validation.error) {
202
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid workflow: ${validation.error}`);
203
+ }
204
+ }
205
+ catch (error) {
206
+ if (error instanceof n8n_workflow_1.NodeOperationError) {
207
+ throw error;
208
+ }
209
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to parse workflow JSON. Please ensure it is valid ComfyUI API format.\nError: ${error instanceof Error ? error.message : String(error)}`);
210
+ }
211
+ logger.info('Processing ComfyUI workflow execution request', { comfyUiUrl, timeout });
163
212
  // Get input data
164
213
  const inputData = this.getInputData();
165
- if (!inputData || inputData.length === 0) {
166
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No input data provided. Please provide a query text.');
167
- }
168
- // Check if input contains binary image data
169
214
  const hasInputImage = (0, agentToolHelpers_1.hasBinaryData)(inputData);
170
215
  let uploadedImageFilename = null;
171
- // Get query from input
172
- const firstItem = inputData[0];
173
- const query = firstItem.json.query ||
174
- firstItem.json.text ||
175
- firstItem.json.prompt ||
176
- '';
177
- if (!query || query.trim().length === 0) {
178
- 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.');
179
- }
180
- // Determine mode based on input
181
- const mode = hasInputImage ? 'image-to-image' : 'text-to-image';
182
- logger.info('Processing image generation request', { query, comfyUiUrl, timeout, mode });
183
- // Parse the query to extract parameters
184
- const params = (0, agentToolHelpers_1.parseInput)(query, {
185
- negativePrompt: defaultNegativePrompt,
186
- width: defaultWidth,
187
- height: defaultHeight,
188
- steps: defaultSteps,
189
- cfg: defaultCfg,
190
- });
191
- logger.debug('Parsed parameters', {
192
- prompt: params.prompt,
193
- width: params.width,
194
- height: params.height,
195
- steps: params.steps,
196
- cfg: params.cfg,
197
- seed: params.seed,
198
- });
199
- // Get workflow template
200
- let workflowTemplate;
201
- if (customWorkflow && customWorkflow.trim().length > 0) {
202
- workflowTemplate = (0, validation_1.safeJsonParse)(customWorkflow, 'Custom workflow JSON');
203
- }
204
- else {
205
- workflowTemplate = (0, workflowConfig_1.getWorkflowTemplate)({ mode });
206
- }
207
216
  // Create ComfyUI client
208
217
  const client = new ComfyUiClient_1.ComfyUIClient({
209
218
  baseUrl: comfyUiUrl,
@@ -212,9 +221,8 @@ class ComfyUiTool {
212
221
  logger,
213
222
  });
214
223
  try {
215
- logger.info('Starting ComfyUI workflow execution');
216
- // If input contains image, upload it first
217
- if (hasInputImage) {
224
+ // If input contains image and LoadImage node ID is specified, upload it
225
+ if (hasInputImage && loadImageNodeId) {
218
226
  const binaryKey = (0, agentToolHelpers_1.getFirstBinaryKey)(inputData);
219
227
  if (!binaryKey) {
220
228
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Binary data found but no binary key detected.');
@@ -226,51 +234,110 @@ class ComfyUiTool {
226
234
  logger.info('Uploading input image to ComfyUI', {
227
235
  fileName: binaryData.fileName,
228
236
  mimeType: binaryData.mimeType,
237
+ nodeId: loadImageNodeId,
229
238
  });
230
239
  // Convert base64 to buffer
231
240
  const buffer = Buffer.from(binaryData.data, 'base64');
232
241
  // Upload image to ComfyUI
233
242
  uploadedImageFilename = await client.uploadImage(buffer, binaryData.fileName || 'input_image.png');
234
243
  logger.info('Successfully uploaded input image', { filename: uploadedImageFilename });
244
+ // Update workflow with uploaded image filename
245
+ workflow = (0, agentToolHelpers_1.updateNodeParameter)(workflow, loadImageNodeId, 'inputs.image', uploadedImageFilename);
235
246
  }
236
- // Update workflow with parsed parameters
237
- let workflow = (0, agentToolHelpers_1.updateWorkflow)(workflowTemplate, params);
238
- // If we uploaded an image, update workflow with the image filename
239
- if (uploadedImageFilename) {
240
- workflow = (0, agentToolHelpers_1.updateWorkflowWithImage)(workflow, uploadedImageFilename);
247
+ else if (imageData && loadImageNodeId) {
248
+ // Handle image data passed as base64 string or file path (for AI Agents)
249
+ logger.info('Processing image data from parameter', { dataLength: imageData.length, nodeId: loadImageNodeId });
250
+ let buffer;
251
+ let filename;
252
+ if (imageData.startsWith('data:image')) {
253
+ // Data URL format: data:image/png;base64,iVBORw0KG...
254
+ const [mimeType, base64Data] = imageData.split(',');
255
+ if (!base64Data) {
256
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid data URL format. Expected: data:image/<type>;base64,<data>');
257
+ }
258
+ buffer = Buffer.from(base64Data, 'base64');
259
+ const extension = mimeType.split('/')[1]?.split(';')[0] || 'png';
260
+ filename = `agent_image.${extension}`;
261
+ logger.info('Decoded image from data URL', { mimeType: mimeType.split(';')[0], size: buffer.length });
262
+ }
263
+ else if (imageData.startsWith('/') || imageData.startsWith('./') || imageData.startsWith('../')) {
264
+ // File path
265
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
266
+ try {
267
+ buffer = await fs.readFile(imageData);
268
+ filename = imageData.split('/').pop() || 'agent_image.png';
269
+ logger.info('Read image from file', { path: imageData, size: buffer.length });
270
+ }
271
+ catch (error) {
272
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to read image file from path "${imageData}": ${error instanceof Error ? error.message : String(error)}`);
273
+ }
274
+ }
275
+ else {
276
+ // Plain base64 string (without data:image/... prefix)
277
+ try {
278
+ buffer = Buffer.from(imageData, 'base64');
279
+ filename = 'agent_image.png';
280
+ logger.info('Decoded image from base64 string', { size: buffer.length });
281
+ }
282
+ catch (error) {
283
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to decode base64 image data. Make sure the data is valid base64 or a data URL (data:image/...;base64,...). Error: ${error instanceof Error ? error.message : String(error)}`);
284
+ }
285
+ }
286
+ // Validate buffer
287
+ if (!buffer || buffer.length === 0) {
288
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Decoded image data is empty. Please check the image data.');
289
+ }
290
+ // Upload image to ComfyUI
291
+ uploadedImageFilename = await client.uploadImage(buffer, filename);
292
+ logger.info('Successfully uploaded image from parameter', { filename: uploadedImageFilename });
293
+ // Update workflow with uploaded image filename
294
+ workflow = (0, agentToolHelpers_1.updateNodeParameter)(workflow, loadImageNodeId, 'inputs.image', uploadedImageFilename);
241
295
  }
296
+ // Apply parameter overrides if provided
297
+ if (parameterOverrides?.parameterOverride && parameterOverrides.parameterOverride.length > 0) {
298
+ logger.info('Applying parameter overrides', {
299
+ count: parameterOverrides.parameterOverride.length,
300
+ });
301
+ for (const override of parameterOverrides.parameterOverride) {
302
+ const { nodeId, paramPath, value } = override;
303
+ // Evaluate expressions if needed
304
+ let evaluatedValue = value;
305
+ if (value && value.includes('{{') && value.includes('}}')) {
306
+ try {
307
+ evaluatedValue = this.evaluateExpression(value, 0);
308
+ logger.debug('Evaluated expression', { nodeId, paramPath, result: evaluatedValue });
309
+ }
310
+ catch (error) {
311
+ logger.warn(`Failed to evaluate expression for ${nodeId}.${paramPath}, using raw value`, { error });
312
+ }
313
+ }
314
+ workflow = (0, agentToolHelpers_1.updateNodeParameter)(workflow, nodeId, paramPath, evaluatedValue);
315
+ logger.debug('Applied parameter override', { nodeId, paramPath, value: evaluatedValue });
316
+ }
317
+ }
318
+ logger.info('Starting ComfyUI workflow execution');
242
319
  // Execute workflow
243
320
  const result = await client.executeWorkflow(workflow);
244
321
  if (!result.success) {
245
322
  logger.error('Workflow execution failed', result.error);
246
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to generate image: ${result.error}`);
323
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to execute workflow: ${result.error}`);
247
324
  }
248
- // Only return URLs without downloading (for AI Agent)
325
+ // Build URLs
249
326
  const imageUrls = result.images ? result.images.map(img => `${comfyUiUrl}${img}`) : [];
250
327
  const videoUrls = result.videos ? result.videos.map(vid => `${comfyUiUrl}${vid}`) : [];
251
- const enhancedJson = {
328
+ const outputJson = {
252
329
  success: true,
253
330
  imageUrls,
254
331
  videoUrls,
255
332
  imageCount: result.images?.length || 0,
256
333
  videoCount: result.videos?.length || 0,
257
- prompt: params.prompt,
258
- mode: mode,
259
- parameters: {
260
- width: params.width,
261
- height: params.height,
262
- steps: params.steps,
263
- cfg: params.cfg,
264
- seed: params.seed,
265
- negative_prompt: params.negative_prompt,
266
- },
267
334
  };
268
- logger.info('Image generation completed successfully', {
269
- imageCount: enhancedJson.imageCount,
270
- mode,
335
+ logger.info('Workflow execution completed successfully', {
336
+ imageCount: outputJson.imageCount,
337
+ videoCount: outputJson.videoCount,
271
338
  });
272
- // Return result (no binary data for AI Agent)
273
- return [this.helpers.constructExecutionMetaData([{ json: enhancedJson }], { itemData: { item: 0 } })];
339
+ // Return result (no binary data for AI Agent - URLs only)
340
+ return [this.helpers.constructExecutionMetaData([{ json: outputJson }], { itemData: { item: 0 } })];
274
341
  }
275
342
  catch (error) {
276
343
  logger.error('Error during workflow execution', error);