n8n-nodes-github-copilot 3.1.0 → 3.2.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.
@@ -1,183 +1,55 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
3
  exports.GitHubCopilotChatAPI = void 0;
27
- async function makeApiRequest(context, endpoint, body) {
28
- const credentials = await context.getCredentials('githubApi');
29
- const options = {
30
- method: 'POST',
31
- headers: {
32
- 'Authorization': `Bearer ${credentials.accessToken}`,
33
- 'Content-Type': 'application/json',
34
- 'User-Agent': 'n8n-github-copilot-chat/3.0.0',
35
- },
36
- body: JSON.stringify(body),
37
- };
38
- const response = await fetch(`https://api.githubcopilot.com${endpoint}`, options);
39
- if (!response.ok) {
40
- const errorText = await response.text();
41
- throw new Error(`GitHub Copilot API error: ${response.status} ${response.statusText}. ${errorText}`);
42
- }
43
- return await response.json();
44
- }
45
- async function downloadFileFromUrl(url) {
46
- const response = await fetch(url);
47
- if (!response.ok) {
48
- throw new Error(`Failed to download file from URL: ${response.status} ${response.statusText}`);
49
- }
50
- return Buffer.from(await response.arrayBuffer());
51
- }
52
- async function getFileFromBinary(context, itemIndex, propertyName) {
53
- const items = context.getInputData();
54
- const item = items[itemIndex];
55
- if (!item.binary || !item.binary[propertyName]) {
56
- throw new Error(`No binary data found in property "${propertyName}"`);
57
- }
58
- const binaryData = item.binary[propertyName];
59
- if (binaryData.data) {
60
- return Buffer.from(binaryData.data, 'base64');
61
- }
62
- else if (binaryData.id) {
63
- return await context.helpers.getBinaryDataBuffer(itemIndex, propertyName);
64
- }
65
- else {
66
- throw new Error(`Invalid binary data format in property "${propertyName}"`);
67
- }
68
- }
69
- async function processAudioFile(context, itemIndex) {
4
+ const utils_1 = require("./utils");
5
+ const nodeProperties_1 = require("./nodeProperties");
6
+ async function processAudioFileLegacy(context, itemIndex) {
70
7
  const audioSource = context.getNodeParameter('audioSource', itemIndex);
71
- let audioBuffer;
72
- let filename = 'audio.mp3';
73
- switch (audioSource) {
74
- case 'manual':
75
- const audioFile = context.getNodeParameter('audioFile', itemIndex);
76
- if (audioFile.startsWith('data:audio/')) {
77
- const base64Data = audioFile.split(',')[1];
78
- audioBuffer = Buffer.from(base64Data, 'base64');
79
- }
80
- else if (audioFile.match(/^[A-Za-z0-9+/=]+$/)) {
81
- audioBuffer = Buffer.from(audioFile, 'base64');
82
- }
83
- else {
84
- const fs = await Promise.resolve().then(() => __importStar(require('fs')));
85
- audioBuffer = fs.readFileSync(audioFile);
86
- filename = audioFile.split(/[\\\/]/).pop() || 'audio.mp3';
87
- }
88
- break;
89
- case 'url':
90
- const audioUrl = context.getNodeParameter('audioUrl', itemIndex);
91
- audioBuffer = await downloadFileFromUrl(audioUrl);
92
- filename = audioUrl.split('/').pop() || 'audio.mp3';
93
- break;
94
- case 'binary':
95
- const audioBinaryProperty = context.getNodeParameter('audioBinaryProperty', itemIndex);
96
- audioBuffer = await getFileFromBinary(context, itemIndex, audioBinaryProperty);
97
- const items = context.getInputData();
98
- const item = items[itemIndex];
99
- if (item.binary && item.binary[audioBinaryProperty] && item.binary[audioBinaryProperty].fileName) {
100
- filename = item.binary[audioBinaryProperty].fileName || 'audio.mp3';
101
- }
102
- break;
103
- default:
104
- throw new Error(`Unknown audio source: ${audioSource}`);
8
+ try {
9
+ const audioFile = context.getNodeParameter('audioFile', itemIndex, '');
10
+ const audioUrl = context.getNodeParameter('audioUrl', itemIndex, '');
11
+ const audioProperty = context.getNodeParameter('audioBinaryProperty', itemIndex, '');
12
+ const result = await (0, utils_1.processAudioFile)(context, itemIndex, audioSource, audioFile, audioUrl, audioProperty);
13
+ const tokenValidation = (0, utils_1.validateTokenLimit)(result.estimatedTokens, 100000);
14
+ if (!tokenValidation.valid) {
15
+ return {
16
+ dataUrl: '',
17
+ description: (0, utils_1.createAudioSummary)(result.filename, result.size)
18
+ };
19
+ }
20
+ const optimized = (0, utils_1.optimizeAudioForTokens)(result.data, 80000);
21
+ let description = `Audio file: ${result.filename} (${Math.round(result.size / 1024)}KB)`;
22
+ if (optimized.truncated) {
23
+ description += ` - Compressed from ${optimized.originalTokens} to ${optimized.finalTokens} tokens`;
24
+ }
25
+ return {
26
+ dataUrl: `data:${result.mimeType};base64,${optimized.data}`,
27
+ description
28
+ };
29
+ }
30
+ catch (error) {
31
+ return {
32
+ dataUrl: '',
33
+ description: `Error processing audio: ${error instanceof Error ? error.message : 'Unknown error'}`
34
+ };
105
35
  }
106
- const mimeType = getAudioMimeType(filename);
107
- return `data:${mimeType};base64,${audioBuffer.toString('base64')}`;
108
36
  }
109
- async function processImageFile(context, itemIndex) {
37
+ async function processImageFileLegacy(context, itemIndex) {
110
38
  const imageSource = context.getNodeParameter('imageSource', itemIndex);
111
- let imageBuffer;
112
- let filename = 'image.jpg';
113
- switch (imageSource) {
114
- case 'manual':
115
- const imageFile = context.getNodeParameter('imageFile', itemIndex);
116
- if (imageFile.startsWith('data:image/')) {
117
- return imageFile;
118
- }
119
- else if (imageFile.match(/^[A-Za-z0-9+/=]+$/)) {
120
- imageBuffer = Buffer.from(imageFile, 'base64');
121
- }
122
- else {
123
- const fs = await Promise.resolve().then(() => __importStar(require('fs')));
124
- imageBuffer = fs.readFileSync(imageFile);
125
- filename = imageFile.split(/[\\\/]/).pop() || 'image.jpg';
126
- }
127
- break;
128
- case 'url':
129
- const imageUrl = context.getNodeParameter('imageUrl', itemIndex);
130
- imageBuffer = await downloadFileFromUrl(imageUrl);
131
- filename = imageUrl.split('/').pop() || 'image.jpg';
132
- break;
133
- case 'binary':
134
- const imageBinaryProperty = context.getNodeParameter('imageBinaryProperty', itemIndex);
135
- imageBuffer = await getFileFromBinary(context, itemIndex, imageBinaryProperty);
136
- const items = context.getInputData();
137
- const item = items[itemIndex];
138
- if (item.binary && item.binary[imageBinaryProperty] && item.binary[imageBinaryProperty].fileName) {
139
- filename = item.binary[imageBinaryProperty].fileName || 'image.jpg';
140
- }
141
- break;
142
- default:
143
- throw new Error(`Unknown image source: ${imageSource}`);
39
+ try {
40
+ const imageFile = context.getNodeParameter('imageFile', itemIndex, '');
41
+ const imageUrl = context.getNodeParameter('imageUrl', itemIndex, '');
42
+ const imageProperty = context.getNodeParameter('imageBinaryProperty', itemIndex, '');
43
+ const result = await (0, utils_1.processImageFile)(context, itemIndex, imageSource, imageFile, imageUrl, imageProperty);
44
+ const tokenValidation = (0, utils_1.validateTokenLimit)(result.estimatedTokens, 50000);
45
+ if (!tokenValidation.valid) {
46
+ throw new Error(`Image too large: ${result.estimatedTokens} estimated tokens. Please use a smaller image.`);
47
+ }
48
+ const optimizedData = (0, utils_1.compressImageToTokenLimit)(result.data, 40000);
49
+ return `data:${result.mimeType};base64,${optimizedData}`;
144
50
  }
145
- const mimeType = getMimeType(filename);
146
- return `data:${mimeType};base64,${imageBuffer.toString('base64')}`;
147
- }
148
- function getMimeType(filename) {
149
- const ext = filename.toLowerCase().split('.').pop();
150
- switch (ext) {
151
- case 'jpg':
152
- case 'jpeg':
153
- return 'image/jpeg';
154
- case 'png':
155
- return 'image/png';
156
- case 'webp':
157
- return 'image/webp';
158
- case 'gif':
159
- return 'image/gif';
160
- default:
161
- return 'image/jpeg';
162
- }
163
- }
164
- function getAudioMimeType(filename) {
165
- const ext = filename.toLowerCase().split('.').pop();
166
- switch (ext) {
167
- case 'mp3':
168
- return 'audio/mpeg';
169
- case 'wav':
170
- return 'audio/wav';
171
- case 'm4a':
172
- return 'audio/mp4';
173
- case 'flac':
174
- return 'audio/flac';
175
- case 'ogg':
176
- return 'audio/ogg';
177
- case 'aac':
178
- return 'audio/aac';
179
- default:
180
- return 'audio/mpeg';
51
+ catch (error) {
52
+ throw new Error(`Error processing image: ${error instanceof Error ? error.message : 'Unknown error'}`);
181
53
  }
182
54
  }
183
55
  class GitHubCopilotChatAPI {
@@ -201,384 +73,88 @@ class GitHubCopilotChatAPI {
201
73
  required: true,
202
74
  },
203
75
  ],
204
- properties: [
205
- {
206
- displayName: 'Operation',
207
- name: 'operation',
208
- type: 'options',
209
- options: [
210
- {
211
- name: 'Chat Completion',
212
- value: 'chatCompletion',
213
- description: 'Send a message and get AI response using Copilot models',
214
- },
215
- {
216
- name: 'Audio Transcription',
217
- value: 'audioTranscription',
218
- description: 'Transcribe audio file to text using Copilot',
219
- },
220
- {
221
- name: 'Image Analysis',
222
- value: 'imageAnalysis',
223
- description: 'Analyze image with AI (vision models)',
224
- },
225
- ],
226
- default: 'chatCompletion',
227
- },
228
- {
229
- displayName: 'Model',
230
- name: 'model',
231
- type: 'options',
232
- options: [
233
- {
234
- name: 'GPT-5 (Latest)',
235
- value: 'gpt-5',
236
- description: 'OpenAI GPT-5 - Latest and most advanced model',
237
- },
238
- {
239
- name: 'GPT-5 Mini',
240
- value: 'gpt-5-mini',
241
- description: 'OpenAI GPT-5 Mini - Faster and more efficient',
242
- },
243
- {
244
- name: 'Claude Opus 4.1',
245
- value: 'claude-opus-4.1',
246
- description: 'Anthropic Claude Opus 4.1 - Advanced reasoning',
247
- },
248
- {
249
- name: 'Gemini 2.5 Pro',
250
- value: 'gemini-2.5-pro',
251
- description: 'Google Gemini 2.5 Pro - Multimodal capabilities',
252
- },
253
- {
254
- name: 'Grok Code Fast 1',
255
- value: 'grok-code-fast-1',
256
- description: 'xAI Grok - Optimized for coding tasks',
257
- },
258
- {
259
- name: 'GPT-4.1 Copilot',
260
- value: 'gpt-4.1-copilot',
261
- description: 'GitHub Copilot optimized GPT-4.1 model',
262
- },
263
- ],
264
- default: 'gpt-5',
265
- description: 'Choose the AI model from your Copilot subscription',
266
- },
267
- {
268
- displayName: 'Message',
269
- name: 'message',
270
- type: 'string',
271
- typeOptions: {
272
- rows: 4,
273
- },
274
- default: '',
275
- placeholder: 'Enter your message here...',
276
- description: 'The message to send to the AI',
277
- displayOptions: {
278
- show: {
279
- operation: ['chatCompletion', 'imageAnalysis'],
280
- },
281
- },
282
- },
283
- {
284
- displayName: 'Audio Source',
285
- name: 'audioSource',
286
- type: 'options',
287
- options: [
288
- { name: 'File Path or Base64', value: 'manual' },
289
- { name: 'Download from URL', value: 'url' },
290
- { name: 'From Previous Node Binary', value: 'binary' },
291
- ],
292
- default: 'manual',
293
- description: 'Choose how to provide the audio file',
294
- displayOptions: {
295
- show: {
296
- operation: ['audioTranscription'],
297
- },
298
- },
299
- },
300
- {
301
- displayName: 'Audio File',
302
- name: 'audioFile',
303
- type: 'string',
304
- default: '',
305
- placeholder: 'Path to audio file or base64 data',
306
- description: 'Audio file to transcribe (supports MP3, WAV, M4A, FLAC, OGG)',
307
- displayOptions: {
308
- show: {
309
- operation: ['audioTranscription'],
310
- audioSource: ['manual'],
311
- },
312
- },
313
- },
314
- {
315
- displayName: 'Audio URL',
316
- name: 'audioUrl',
317
- type: 'string',
318
- default: '',
319
- placeholder: 'https://example.com/audio.mp3',
320
- description: 'URL to download audio file from',
321
- displayOptions: {
322
- show: {
323
- operation: ['audioTranscription'],
324
- audioSource: ['url'],
325
- },
326
- },
327
- },
328
- {
329
- displayName: 'Binary Property Name',
330
- name: 'audioBinaryProperty',
331
- type: 'string',
332
- default: 'data',
333
- placeholder: 'data',
334
- description: 'Name of the binary property containing the audio file',
335
- displayOptions: {
336
- show: {
337
- operation: ['audioTranscription'],
338
- audioSource: ['binary'],
339
- },
340
- },
341
- },
342
- {
343
- displayName: 'Audio Language',
344
- name: 'audioLanguage',
345
- type: 'options',
346
- options: [
347
- { name: 'Auto-detect', value: 'auto' },
348
- { name: 'Portuguese (Brazil)', value: 'pt' },
349
- { name: 'English', value: 'en' },
350
- { name: 'Spanish', value: 'es' },
351
- { name: 'French', value: 'fr' },
352
- { name: 'German', value: 'de' },
353
- { name: 'Italian', value: 'it' },
354
- { name: 'Japanese', value: 'ja' },
355
- { name: 'Chinese', value: 'zh' },
356
- ],
357
- default: 'auto',
358
- description: 'Language of the audio (helps with accuracy)',
359
- displayOptions: {
360
- show: {
361
- operation: ['audioTranscription'],
362
- },
363
- },
364
- },
365
- {
366
- displayName: 'Image Source',
367
- name: 'imageSource',
368
- type: 'options',
369
- options: [
370
- { name: 'File Path or Base64', value: 'manual' },
371
- { name: 'Download from URL', value: 'url' },
372
- { name: 'From Previous Node Binary', value: 'binary' },
373
- ],
374
- default: 'manual',
375
- description: 'Choose how to provide the image file',
376
- displayOptions: {
377
- show: {
378
- operation: ['imageAnalysis'],
379
- },
380
- },
381
- },
382
- {
383
- displayName: 'Image File',
384
- name: 'imageFile',
385
- type: 'string',
386
- default: '',
387
- placeholder: 'Path to image file or base64 data',
388
- description: 'Image file to analyze (supports JPG, PNG, WebP, GIF)',
389
- displayOptions: {
390
- show: {
391
- operation: ['imageAnalysis'],
392
- imageSource: ['manual'],
393
- },
394
- },
395
- },
396
- {
397
- displayName: 'Image URL',
398
- name: 'imageUrl',
399
- type: 'string',
400
- default: '',
401
- placeholder: 'https://example.com/image.jpg',
402
- description: 'URL to download image file from',
403
- displayOptions: {
404
- show: {
405
- operation: ['imageAnalysis'],
406
- imageSource: ['url'],
407
- },
408
- },
409
- },
410
- {
411
- displayName: 'Binary Property Name',
412
- name: 'imageBinaryProperty',
413
- type: 'string',
414
- default: 'data',
415
- placeholder: 'data',
416
- description: 'Name of the binary property containing the image file',
417
- displayOptions: {
418
- show: {
419
- operation: ['imageAnalysis'],
420
- imageSource: ['binary'],
421
- },
422
- },
423
- },
424
- {
425
- displayName: 'System Prompt',
426
- name: 'systemPrompt',
427
- type: 'string',
428
- typeOptions: {
429
- rows: 2,
430
- },
431
- default: '',
432
- placeholder: 'You are a helpful assistant...',
433
- description: 'Optional system prompt to set AI behavior',
434
- displayOptions: {
435
- show: {
436
- operation: ['chatCompletion', 'imageAnalysis'],
437
- },
438
- },
439
- },
440
- {
441
- displayName: 'Temperature',
442
- name: 'temperature',
443
- type: 'number',
444
- typeOptions: {
445
- minValue: 0,
446
- maxValue: 2,
447
- numberStepSize: 0.1,
448
- },
449
- default: 1,
450
- description: 'Controls randomness: 0 = focused, 2 = creative',
451
- displayOptions: {
452
- show: {
453
- operation: ['chatCompletion', 'imageAnalysis'],
454
- },
455
- },
456
- },
457
- {
458
- displayName: 'Max Tokens',
459
- name: 'maxTokens',
460
- type: 'number',
461
- typeOptions: {
462
- minValue: 1,
463
- maxValue: 8192,
464
- },
465
- default: 2000,
466
- description: 'Maximum tokens in response',
467
- displayOptions: {
468
- show: {
469
- operation: ['chatCompletion', 'imageAnalysis'],
470
- },
471
- },
472
- },
473
- ],
76
+ properties: nodeProperties_1.nodeProperties,
474
77
  };
475
78
  }
476
79
  async execute() {
80
+ var _a, _b, _c;
477
81
  const items = this.getInputData();
478
82
  const returnData = [];
479
83
  for (let i = 0; i < items.length; i++) {
480
84
  try {
481
85
  const operation = this.getNodeParameter('operation', i);
482
86
  const model = this.getNodeParameter('model', i);
483
- let result;
484
- if (operation === 'chatCompletion') {
485
- const message = this.getNodeParameter('message', i);
486
- const systemPrompt = this.getNodeParameter('systemPrompt', i);
487
- const temperature = this.getNodeParameter('temperature', i);
488
- const maxTokens = this.getNodeParameter('maxTokens', i);
87
+ if (operation === 'chat') {
88
+ const userMessage = this.getNodeParameter('message', i);
89
+ const systemMessage = this.getNodeParameter('systemMessage', i, '');
90
+ const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
91
+ const includeImage = this.getNodeParameter('includeImage', i, false);
92
+ const includeAudio = this.getNodeParameter('includeAudio', i, false);
489
93
  const messages = [];
490
- if (systemPrompt) {
491
- messages.push({ role: 'system', content: systemPrompt });
492
- }
493
- messages.push({ role: 'user', content: message });
494
- const requestBody = {
495
- model: model,
496
- messages: messages,
497
- temperature: temperature,
498
- max_tokens: maxTokens,
499
- stream: false,
500
- };
501
- const response = await makeApiRequest(this, '/chat/completions', requestBody);
502
- result = {
503
- response: response.choices[0].message.content,
504
- model: model,
505
- usage: response.usage,
506
- finish_reason: response.choices[0].finish_reason,
507
- timestamp: new Date().toISOString(),
508
- };
509
- }
510
- else if (operation === 'audioTranscription') {
511
- const language = this.getNodeParameter('audioLanguage', i);
512
- const audioDataUrl = await processAudioFile(this, i);
513
- const transcriptionPrompt = language === 'auto'
514
- ? `Please transcribe this audio file to text. Detect the language automatically and provide the transcription.`
515
- : `Please transcribe this audio file to text. The audio is in ${language} language.`;
516
- const messages = [
517
- {
94
+ if (systemMessage) {
95
+ messages.push({
518
96
  role: 'system',
519
- content: 'You are an expert at audio transcription. When given an audio file, provide an accurate transcription of the spoken content.'
520
- },
521
- {
522
- role: 'user',
523
- content: `${transcriptionPrompt}\n\nAudio file: ${audioDataUrl}`
97
+ content: systemMessage,
98
+ });
99
+ }
100
+ let userContent = userMessage;
101
+ if (includeImage || includeAudio) {
102
+ const contentArray = [];
103
+ if (userMessage.trim()) {
104
+ contentArray.push({
105
+ type: 'text',
106
+ text: userMessage,
107
+ });
524
108
  }
525
- ];
526
- const requestBody = {
527
- model: model,
528
- messages: messages,
529
- temperature: 0.1,
530
- max_tokens: 4000,
531
- stream: false,
532
- };
533
- const response = await makeApiRequest(this, '/chat/completions', requestBody);
534
- result = {
535
- transcription: response.choices[0].message.content,
536
- language: language,
537
- model: model,
538
- usage: response.usage,
539
- timestamp: new Date().toISOString(),
540
- };
541
- }
542
- else if (operation === 'imageAnalysis') {
543
- const message = this.getNodeParameter('message', i);
544
- const systemPrompt = this.getNodeParameter('systemPrompt', i);
545
- const temperature = this.getNodeParameter('temperature', i);
546
- const maxTokens = this.getNodeParameter('maxTokens', i);
547
- const imageBase64 = await processImageFile(this, i);
548
- const messages = [];
549
- if (systemPrompt) {
550
- messages.push({ role: 'system', content: systemPrompt });
109
+ if (includeImage) {
110
+ const imageDataUrl = await processImageFileLegacy(this, i);
111
+ contentArray.push({
112
+ type: 'image_url',
113
+ image_url: {
114
+ url: imageDataUrl,
115
+ },
116
+ });
117
+ }
118
+ if (includeAudio) {
119
+ const audioResult = await processAudioFileLegacy(this, i);
120
+ if (audioResult.dataUrl) {
121
+ contentArray.push({
122
+ type: 'text',
123
+ text: `[Audio included: ${audioResult.description}]`,
124
+ });
125
+ }
126
+ else {
127
+ contentArray.push({
128
+ type: 'text',
129
+ text: `[Audio processing failed: ${audioResult.description}]`,
130
+ });
131
+ }
132
+ }
133
+ userContent = contentArray;
551
134
  }
552
135
  messages.push({
553
136
  role: 'user',
554
- content: [
555
- { type: 'text', text: message },
556
- { type: 'image_url', image_url: { url: imageBase64 } }
557
- ]
137
+ content: userContent,
558
138
  });
559
139
  const requestBody = {
560
- model: model,
561
- messages: messages,
562
- temperature: temperature,
563
- max_tokens: maxTokens,
140
+ model,
141
+ messages,
564
142
  stream: false,
143
+ ...advancedOptions,
565
144
  };
566
- const response = await makeApiRequest(this, '/chat/completions', requestBody);
567
- result = {
568
- response: response.choices[0].message.content,
569
- model: model,
570
- usage: response.usage,
571
- finish_reason: response.choices[0].finish_reason,
572
- timestamp: new Date().toISOString(),
145
+ const response = await (0, utils_1.makeApiRequest)(this, '/chat/completions', requestBody, includeImage);
146
+ const result = {
147
+ message: ((_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) || '',
148
+ model,
149
+ operation,
150
+ usage: response.usage || null,
151
+ finish_reason: ((_c = response.choices[0]) === null || _c === void 0 ? void 0 : _c.finish_reason) || 'unknown',
573
152
  };
153
+ returnData.push({
154
+ json: result,
155
+ pairedItem: { item: i },
156
+ });
574
157
  }
575
- else {
576
- throw new Error(`Unknown operation: ${operation}`);
577
- }
578
- returnData.push({
579
- json: result,
580
- pairedItem: { item: i },
581
- });
582
158
  }
583
159
  catch (error) {
584
160
  if (this.continueOnFail()) {