n8n-nodes-vercel-ai-sdk-universal-temp 0.2.88 → 0.2.90

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.
Files changed (51) hide show
  1. package/dist/nodes/UniversalAI/UniversalAI.node.js +49 -475
  2. package/dist/nodes/UniversalAI/UniversalAI.node.js.map +1 -1
  3. package/dist/nodes/UniversalAI/helpers/cacheMetrics.d.ts +3 -0
  4. package/dist/nodes/UniversalAI/helpers/cacheMetrics.js +12 -0
  5. package/dist/nodes/UniversalAI/helpers/cacheMetrics.js.map +1 -0
  6. package/dist/nodes/UniversalAI/helpers/inputBuilder.d.ts +8 -0
  7. package/dist/nodes/UniversalAI/helpers/inputBuilder.js +232 -0
  8. package/dist/nodes/UniversalAI/helpers/inputBuilder.js.map +1 -0
  9. package/dist/nodes/UniversalAI/helpers/responseFormatter.d.ts +7 -0
  10. package/dist/nodes/UniversalAI/helpers/responseFormatter.js +78 -0
  11. package/dist/nodes/UniversalAI/helpers/responseFormatter.js.map +1 -0
  12. package/dist/nodes/UniversalAI/helpers/utils.d.ts +5 -0
  13. package/dist/nodes/UniversalAI/helpers/utils.js +50 -0
  14. package/dist/nodes/UniversalAI/helpers/utils.js.map +1 -0
  15. package/dist/nodes/UniversalAI/providers/google.d.ts +16 -0
  16. package/dist/nodes/UniversalAI/providers/google.js +105 -0
  17. package/dist/nodes/UniversalAI/providers/google.js.map +1 -0
  18. package/dist/nodes/UniversalAI/providers/index.d.ts +3 -0
  19. package/dist/nodes/UniversalAI/providers/index.js +16 -0
  20. package/dist/nodes/UniversalAI/providers/index.js.map +1 -0
  21. package/dist/nodes/UniversalAI/providers/strategy.d.ts +15 -0
  22. package/dist/nodes/UniversalAI/providers/strategy.js +3 -0
  23. package/dist/nodes/UniversalAI/providers/strategy.js.map +1 -0
  24. package/dist/nodes/UniversalAI/providers/types.d.ts +15 -0
  25. package/dist/nodes/UniversalAI/providers/types.js +3 -0
  26. package/dist/nodes/UniversalAI/providers/types.js.map +1 -0
  27. package/dist/nodes/shared/DescriptionBuilder.d.ts +10 -0
  28. package/dist/nodes/shared/DescriptionBuilder.js +46 -0
  29. package/dist/nodes/shared/DescriptionBuilder.js.map +1 -0
  30. package/dist/nodes/shared/cache/cache.d.ts +1 -1
  31. package/dist/nodes/shared/cache/cache.js +4 -4
  32. package/dist/nodes/shared/cache/cache.js.map +1 -1
  33. package/dist/nodes/shared/descriptions.js +74 -271
  34. package/dist/nodes/shared/descriptions.js.map +1 -1
  35. package/dist/nodes/shared/helpers.js +4 -4
  36. package/dist/nodes/shared/helpers.js.map +1 -1
  37. package/dist/nodes/shared/icons/ai-chip.svg +32 -0
  38. package/dist/nodes/shared/icons/anthropic.svg +1 -0
  39. package/dist/nodes/shared/icons/gemini.svg +10 -0
  40. package/dist/nodes/shared/icons/groq.svg +1 -0
  41. package/dist/nodes/shared/icons/openai.svg +1 -0
  42. package/dist/nodes/shared/icons/openrouter.svg +39 -0
  43. package/dist/nodes/shared/icons.d.ts +1 -0
  44. package/dist/nodes/shared/icons.js +14 -0
  45. package/dist/nodes/shared/icons.js.map +1 -0
  46. package/dist/nodes/shared/letta/client.js +25 -12
  47. package/dist/nodes/shared/letta/client.js.map +1 -1
  48. package/dist/nodes/shared/providers.d.ts +7 -0
  49. package/dist/nodes/shared/providers.js +41 -0
  50. package/dist/nodes/shared/providers.js.map +1 -0
  51. package/package.json +7 -7
@@ -32,425 +32,19 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.UniversalAI = void 0;
40
37
  const n8n_workflow_1 = require("n8n-workflow");
41
38
  const ai_1 = require("ai");
42
- const zod_1 = require("zod");
43
- const ajv_1 = __importDefault(require("ajv"));
44
39
  const descriptions_1 = require("../shared/descriptions");
45
40
  const helpers_1 = require("../shared/helpers");
46
41
  const cache_1 = require("../shared/cache/cache");
47
42
  const constants_1 = require("../shared/constants");
43
+ const providers_1 = require("./providers");
48
44
  const nodeCacheManagers = new cache_1.LRUCache(constants_1.CACHE_SIZE.NODE_INSTANCES);
49
- const messageSchema = zod_1.z.object({
50
- role: zod_1.z.enum(['system', 'user', 'assistant']),
51
- content: zod_1.z.any(),
52
- });
53
- const messagesArraySchema = zod_1.z.array(messageSchema);
54
- const ajv = new ajv_1.default({
55
- allErrors: true,
56
- verbose: true,
57
- strict: false,
58
- });
59
- const isUrl = (str) => {
60
- return typeof str === 'string' && /^(https?:|data:)/i.test(str);
61
- };
62
- const isLikelyBase64 = (str) => {
63
- return str.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(str) && str.length > 10000;
64
- };
65
- async function buildInput(exec, itemIndex) {
66
- const inputType = exec.getNodeParameter('inputType', itemIndex);
67
- if (inputType === 'prompt') {
68
- const promptValue = exec.getNodeParameter('prompt', itemIndex, '');
69
- const systemValue = exec.getNodeParameter('system', itemIndex, '');
70
- const cachePrompt = exec.getNodeParameter('cachePrompt', itemIndex, false);
71
- const cacheSystemInstruction = exec.getNodeParameter('cacheSystemInstruction', itemIndex, false);
72
- const result = {};
73
- const cacheableContent = [];
74
- if (cacheSystemInstruction && systemValue?.trim()) {
75
- cacheableContent.push({
76
- role: 'user',
77
- parts: [{ text: systemValue.trim() }],
78
- });
79
- }
80
- if (cachePrompt && promptValue?.trim()) {
81
- cacheableContent.push({
82
- role: 'user',
83
- parts: [{ text: promptValue.trim() }],
84
- });
85
- }
86
- const trimmedPrompt = typeof promptValue === 'string' ? promptValue.trim() : '';
87
- if (trimmedPrompt && !cachePrompt) {
88
- result.prompt = trimmedPrompt;
89
- }
90
- const trimmedSystem = typeof systemValue === 'string' ? systemValue.trim() : '';
91
- if (trimmedSystem && !cacheSystemInstruction) {
92
- result.system = trimmedSystem;
93
- }
94
- if (cacheableContent.length > 0) {
95
- result.cacheableContent = cacheableContent;
96
- }
97
- return result;
98
- }
99
- const messageAsJson = exec.getNodeParameter('messageAsJson', itemIndex, false);
100
- return messageAsJson
101
- ? buildMessagesFromJson(exec, itemIndex)
102
- : buildMessagesFromUI(exec, itemIndex);
103
- }
104
- async function buildMessagesFromJson(exec, itemIndex) {
105
- const rawJson = exec.getNodeParameter('messagesJson', itemIndex);
106
- try {
107
- const parsed = JSON.parse(rawJson);
108
- const result = messagesArraySchema.safeParse(parsed);
109
- if (!result.success) {
110
- const formattedError = result.error.format();
111
- const errorMessage = JSON.stringify(formattedError, null, 2);
112
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid JSON structure for messages: ${errorMessage}`);
113
- }
114
- return { messages: result.data };
115
- }
116
- catch (error) {
117
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid JSON in "Messages (JSON)" field: ${error.message}`);
118
- }
119
- }
120
- async function buildMessagesFromUI(exec, itemIndex) {
121
- const items = exec.getInputData();
122
- const messagesUi = exec.getNodeParameter('messages.messagesUi', itemIndex, []);
123
- const builtMessages = [];
124
- const cacheableContent = [];
125
- const itemBinary = items[itemIndex].binary;
126
- for (const msg of messagesUi) {
127
- const role = msg.role;
128
- const shouldCache = msg.cacheMessage === true;
129
- if (role === 'system') {
130
- const systemText = msg.systemContent || '';
131
- if (shouldCache && systemText.trim()) {
132
- cacheableContent.push({
133
- role: 'user',
134
- parts: [{ text: systemText.trim() }],
135
- });
136
- }
137
- else {
138
- builtMessages.push({ role, content: systemText });
139
- }
140
- continue;
141
- }
142
- const attachments = msg.attachments?.attachment || [];
143
- if (attachments.length === 0) {
144
- const messageText = msg.content || '';
145
- if (shouldCache && messageText.trim()) {
146
- const cacheRole = role === 'assistant' ? 'model' : 'user';
147
- cacheableContent.push({
148
- role: cacheRole,
149
- parts: [{ text: messageText.trim() }],
150
- });
151
- }
152
- else {
153
- builtMessages.push({ role, content: messageText });
154
- }
155
- }
156
- else {
157
- const messageWithAttachments = await buildMessageWithAttachments(role, msg.content, attachments, itemBinary, exec, itemIndex, shouldCache, cacheableContent);
158
- if (messageWithAttachments) {
159
- builtMessages.push(messageWithAttachments);
160
- }
161
- }
162
- }
163
- const convertMessagesToModel = exec.getNodeParameter('convertMessagesToModel', itemIndex, false);
164
- const result = {
165
- messages: convertMessagesToModel ? (0, ai_1.convertToModelMessages)(builtMessages) : builtMessages,
166
- };
167
- if (cacheableContent.length > 0) {
168
- result.cacheableContent = cacheableContent;
169
- }
170
- return result;
171
- }
172
- async function buildMessageWithAttachments(role, content, attachments, itemBinary, exec, itemIndex, shouldCacheMessage, cacheableContent) {
173
- const parts = [];
174
- if (content) {
175
- parts.push({ type: 'text', text: content });
176
- }
177
- for (const attachment of attachments) {
178
- const filePart = await processAttachment(attachment, itemBinary, exec, itemIndex, shouldCacheMessage, cacheableContent);
179
- if (filePart) {
180
- parts.push(filePart);
181
- }
182
- }
183
- return parts.length > 0 ? { role, content: parts } : null;
184
- }
185
- async function processAttachment(attachment, itemBinary, exec, itemIndex, shouldCacheMessage, cacheableContent) {
186
- const fileResult = await processFileData(attachment.fileContent, itemBinary, attachment, cacheableContent, exec, itemIndex);
187
- if (!fileResult)
188
- return null;
189
- if (isUrl(attachment.fileContent)) {
190
- return {
191
- type: 'file',
192
- data: fileResult.data,
193
- mediaType: fileResult.mimeType,
194
- };
195
- }
196
- else {
197
- return {
198
- type: 'file',
199
- data: fileResult.data,
200
- mediaType: fileResult.mimeType,
201
- };
202
- }
203
- }
204
- async function processFileData(fileContentInput, itemBinary, attachment, cacheableContent, exec, itemIndex) {
205
- if (!fileContentInput || typeof fileContentInput !== 'string') {
206
- return null;
207
- }
208
- let mimeType = attachment.mimeType === 'other' ? attachment.mimeTypeOther : attachment.mimeType;
209
- let fileData;
210
- let shouldCache = attachment.cacheAttachment === true;
211
- function detectMimeTypeFromUrl(url) {
212
- if (url.includes('youtube.com') || url.includes('youtu.be')) {
213
- return 'video/mp4';
214
- }
215
- if (url.includes('generativelanguage.googleapis.com') && url.includes('/files/')) {
216
- return undefined;
217
- }
218
- const extension = url.split('.').pop()?.toLowerCase();
219
- const mimeTypes = {
220
- png: 'image/png',
221
- jpg: 'image/jpeg',
222
- jpeg: 'image/jpeg',
223
- gif: 'image/gif',
224
- webp: 'image/webp',
225
- svg: 'image/svg+xml',
226
- pdf: 'application/pdf',
227
- txt: 'text/plain',
228
- json: 'application/json',
229
- xml: 'application/xml',
230
- html: 'text/html',
231
- mp4: 'video/mp4',
232
- avi: 'video/x-msvideo',
233
- mov: 'video/quicktime',
234
- mkv: 'video/x-matroska',
235
- mp3: 'audio/mpeg',
236
- wav: 'audio/wav',
237
- flac: 'audio/flac',
238
- };
239
- return extension ? mimeTypes[extension] : undefined;
240
- }
241
- try {
242
- if (isUrl(fileContentInput)) {
243
- fileData = fileContentInput;
244
- if (shouldCache) {
245
- cacheableContent.push({
246
- role: 'user',
247
- parts: [
248
- {
249
- fileUri: fileContentInput,
250
- mimeType: mimeType || detectMimeTypeFromUrl(fileContentInput) || 'application/octet-stream',
251
- },
252
- ],
253
- });
254
- return null;
255
- }
256
- if (!mimeType) {
257
- mimeType = detectMimeTypeFromUrl(fileContentInput);
258
- }
259
- }
260
- else if (fileContentInput.startsWith('data:')) {
261
- const dataUriMatch = fileContentInput.match(/^data:([^;]+);base64,(.+)$/);
262
- if (!dataUriMatch)
263
- return null;
264
- const [, extractedMimeType, base64Data] = dataUriMatch;
265
- fileData = Buffer.from(base64Data, 'base64');
266
- if (fileData.length > 20 * 1024 * 1024) {
267
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), 'Base64 data exceeds 20MB limit');
268
- }
269
- mimeType = mimeType || extractedMimeType;
270
- }
271
- else if (isLikelyBase64(fileContentInput)) {
272
- fileData = Buffer.from(fileContentInput, 'base64');
273
- if (fileData.length > 20 * 1024 * 1024) {
274
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), 'Base64 data exceeds 20MB limit');
275
- }
276
- }
277
- else if (itemBinary?.[fileContentInput]) {
278
- const binaryData = itemBinary[fileContentInput];
279
- fileData = Buffer.from(binaryData.data, 'base64');
280
- mimeType = mimeType || binaryData.mimeType;
281
- }
282
- else {
283
- return null;
284
- }
285
- if (!fileData || (Buffer.isBuffer(fileData) && fileData.length === 0)) {
286
- return null;
287
- }
288
- return { data: fileData, mimeType: mimeType || 'application/octet-stream', shouldCache };
289
- }
290
- catch (error) {
291
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid file content for attachment: ${error.message}`);
292
- }
293
- }
294
- function formatTextResult(result, includeRequestBody, provider) {
295
- const baseResult = {
296
- text: result.text,
297
- reasoning: result.reasoning,
298
- reasoningText: result.reasoningText,
299
- toolCalls: result.toolCalls || [],
300
- toolResults: result.toolResults || [],
301
- finishReason: result.finishReason,
302
- sources: result.sources || [],
303
- files: result.files || [],
304
- usage: formatUsage(result, provider),
305
- response: formatResponse(result),
306
- steps: result.steps || [],
307
- warnings: result.warnings || [],
308
- experimental_providerMetadata: result.experimental_providerMetadata,
309
- providerMetadata: result.providerMetadata ?? result.experimentalProviderMetadata,
310
- };
311
- if (provider === 'google') {
312
- const providerMetadata = result.experimental_providerMetadata;
313
- baseResult.groundingMetadata = providerMetadata?.google?.groundingMetadata;
314
- baseResult.safetyRatings = providerMetadata?.google?.safetyRatings;
315
- baseResult.urlContextMetadata = providerMetadata?.google?.urlContextMetadata;
316
- }
317
- if (includeRequestBody) {
318
- const requestBody = result.request?.body;
319
- if (requestBody !== undefined) {
320
- baseResult.request = { body: requestBody };
321
- }
322
- }
323
- return baseResult;
324
- }
325
- function formatObjectResult(result, includeRequestBody, provider) {
326
- const out = {
327
- object: result.object,
328
- finishReason: result.finishReason,
329
- usage: formatUsage(result, provider),
330
- response: formatResponse(result),
331
- warnings: result.warnings || [],
332
- experimental_providerMetadata: result.experimental_providerMetadata,
333
- providerMetadata: result.providerMetadata ?? result.experimentalProviderMetadata,
334
- };
335
- if (includeRequestBody) {
336
- out.request = { body: result.request?.body };
337
- }
338
- return out;
339
- }
340
- function formatUsage(result, provider) {
341
- const usage = {
342
- promptTokens: result.usage?.promptTokens,
343
- completionTokens: result.usage?.completionTokens,
344
- totalTokens: result.usage?.totalTokens,
345
- };
346
- const metadata = result.experimental_providerMetadata ??
347
- result.experimentalProviderMetadata ??
348
- result.providerMetadata ??
349
- result.experimental_provider_metadata;
350
- const cacheMetrics = getCacheMetrics(result, provider, metadata);
351
- if (Object.keys(cacheMetrics).length > 0) {
352
- usage.cacheMetrics = cacheMetrics;
353
- }
354
- return usage;
355
- }
356
- function getCacheMetrics(result, provider, metadata) {
357
- const resolvedMetadata = metadata ?? result.experimental_providerMetadata;
358
- const metrics = {};
359
- switch (provider) {
360
- case 'deepseek':
361
- if (resolvedMetadata?.deepseek?.promptCacheHitTokens !== undefined) {
362
- metrics.promptCacheHitTokens = resolvedMetadata.deepseek.promptCacheHitTokens;
363
- }
364
- if (resolvedMetadata?.deepseek?.promptCacheMissTokens !== undefined) {
365
- metrics.promptCacheMissTokens = resolvedMetadata.deepseek.promptCacheMissTokens;
366
- }
367
- break;
368
- case 'groq':
369
- if (resolvedMetadata?.groq?.promptCacheHitTokens !== undefined) {
370
- metrics.promptCacheHitTokens = resolvedMetadata.groq.promptCacheHitTokens;
371
- }
372
- if (resolvedMetadata?.groq?.promptCacheMissTokens !== undefined) {
373
- metrics.promptCacheMissTokens = resolvedMetadata.groq.promptCacheMissTokens;
374
- }
375
- break;
376
- case 'google':
377
- let cachedTokens;
378
- if (resolvedMetadata?.google?.usageMetadata?.cachedContentTokenCount !== undefined) {
379
- cachedTokens = resolvedMetadata.google.usageMetadata.cachedContentTokenCount;
380
- }
381
- if (cachedTokens === undefined &&
382
- result.response?.usageMetadata?.cachedContentTokenCount !== undefined) {
383
- cachedTokens = result.response.usageMetadata.cachedContentTokenCount;
384
- }
385
- if (cachedTokens === undefined &&
386
- resolvedMetadata?.google?.candidates?.[0]?.usageMetadata?.cachedContentTokenCount !==
387
- undefined) {
388
- cachedTokens = resolvedMetadata.google.candidates[0].usageMetadata.cachedContentTokenCount;
389
- }
390
- if (cachedTokens === undefined &&
391
- result.providerMetadata?.google?.usageMetadata?.cachedContentTokenCount !== undefined) {
392
- cachedTokens = result.providerMetadata.google.usageMetadata.cachedContentTokenCount;
393
- }
394
- if (cachedTokens === undefined &&
395
- result.rawResponse?.usageMetadata?.cachedContentTokenCount !== undefined) {
396
- cachedTokens = result.rawResponse.usageMetadata.cachedContentTokenCount;
397
- }
398
- if (cachedTokens !== undefined) {
399
- metrics.cachedContentTokenCount = cachedTokens;
400
- }
401
- if (resolvedMetadata?.google?.usageMetadata?.thoughtsTokenCount !== undefined) {
402
- metrics.thoughtsTokenCount = resolvedMetadata.google.usageMetadata.thoughtsTokenCount;
403
- }
404
- if (resolvedMetadata?.google?.usageMetadata?.totalBillableTokenCount !== undefined) {
405
- metrics.totalBillableTokenCount =
406
- resolvedMetadata.google.usageMetadata.totalBillableTokenCount;
407
- }
408
- break;
409
- }
410
- return metrics;
411
- }
412
- function formatResponse(result) {
413
- return {
414
- id: result.response?.id,
415
- modelId: result.response?.modelId,
416
- timestamp: result.response?.timestamp,
417
- headers: result.response?.headers,
418
- };
419
- }
420
- function parseAndValidateSchema(rawSchema, exec, cacheManager) {
421
- const cacheKey = `schema:${Buffer.from(rawSchema).toString('base64').substring(0, 50)}`;
422
- const cached = cacheManager.schema.get(cacheKey);
423
- if (cached)
424
- return cached;
425
- let parsedSchema;
426
- try {
427
- parsedSchema = JSON.parse(rawSchema);
428
- }
429
- catch (err) {
430
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), 'Schema is not valid JSON: ' + err.message);
431
- }
432
- if (!ajv.validateSchema(parsedSchema)) {
433
- throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid JSON Schema: ${ajv.errorsText(ajv.errors)}`);
434
- }
435
- cacheManager.schema.set(cacheKey, parsedSchema);
436
- return parsedSchema;
437
- }
438
- function parseStopSequences(stopSequencesStr) {
439
- if (!stopSequencesStr)
440
- return undefined;
441
- return stopSequencesStr
442
- .split(',')
443
- .map((s) => s.trim())
444
- .filter((s) => s.length > 0);
445
- }
446
- function applyNumericOptions(params, options, keys) {
447
- for (const key of keys) {
448
- const value = options[key];
449
- if (value !== undefined && value !== null && value !== '') {
450
- params[key] = value;
451
- }
452
- }
453
- }
45
+ const inputBuilder_1 = require("./helpers/inputBuilder");
46
+ const responseFormatter_1 = require("./helpers/responseFormatter");
47
+ const utils_1 = require("./helpers/utils");
454
48
  class UniversalAI {
455
49
  constructor() {
456
50
  this.description = descriptions_1.UNIVERSAL_AI_DESCRIPTION;
@@ -480,19 +74,27 @@ class UniversalAI {
480
74
  const items = this.getInputData();
481
75
  const returnData = [];
482
76
  const provider = this.getNodeParameter('provider', 0);
77
+ const options = this.getNodeParameter('options', 0, {});
78
+ const cacheTTL = options.cacheTTL * 1000;
483
79
  const nodeId = this.getNode().id;
484
80
  let cacheManager = nodeCacheManagers.get(nodeId);
485
81
  if (!cacheManager) {
486
- cacheManager = new cache_1.CacheManager();
82
+ cacheManager = new cache_1.CacheManager(cacheTTL);
487
83
  nodeCacheManagers.set(nodeId, cacheManager);
488
84
  }
489
85
  const { apiKey, baseUrl } = await (0, helpers_1.getCredentials)(this, provider);
490
- const customHeaders = provider === 'google' ? getGoogleCustomHeaders(this, 0) : undefined;
86
+ const customHeaders = getCustomHeaders(this, 0);
491
87
  const aiProvider = await (0, helpers_1.getProvider)(this, cacheManager, provider, apiKey, baseUrl, customHeaders);
88
+ const operation = this.getNodeParameter('operation', 0);
89
+ let parsedSchema;
90
+ if (operation === 'generateObject') {
91
+ const rawSchema = this.getNodeParameter('schema', 0);
92
+ parsedSchema = (0, utils_1.parseAndValidateSchema)(rawSchema, this, cacheManager);
93
+ }
492
94
  for (let i = 0; i < items.length; i++) {
493
95
  if (this.continueOnFail()) {
494
96
  try {
495
- const result = await processItem(this, i, provider, aiProvider, apiKey, cacheManager);
97
+ const result = await processItem(this, i, provider, aiProvider, apiKey, cacheManager, parsedSchema);
496
98
  returnData.push(...result);
497
99
  }
498
100
  catch (error) {
@@ -504,7 +106,7 @@ class UniversalAI {
504
106
  }
505
107
  }
506
108
  else {
507
- const result = await processItem(this, i, provider, aiProvider, apiKey, cacheManager);
109
+ const result = await processItem(this, i, provider, aiProvider, apiKey, cacheManager, parsedSchema);
508
110
  returnData.push(...result);
509
111
  }
510
112
  }
@@ -516,39 +118,30 @@ class UniversalAI {
516
118
  }
517
119
  }
518
120
  exports.UniversalAI = UniversalAI;
519
- async function processItem(exec, index, provider, aiProvider, apiKey, cacheManager) {
121
+ async function processItem(exec, index, provider, aiProvider, apiKey, cacheManager, parsedSchema) {
520
122
  const operation = exec.getNodeParameter('operation', index);
521
123
  const model = exec.getNodeParameter('model', index);
522
124
  const options = exec.getNodeParameter('options', index, {});
523
- const input = await buildInput(exec, index);
125
+ const input = await (0, inputBuilder_1.buildInput)(exec, index);
524
126
  const modelSettings = getModelSettings(exec, index, provider, operation, options);
525
127
  return operation === 'generateText'
526
128
  ? await generateTextOperation(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey)
527
- : await generateObjectOperation(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey, cacheManager);
129
+ : await generateObjectOperation(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey, cacheManager, parsedSchema);
528
130
  }
529
131
  function getModelSettings(exec, index, provider, operation, options) {
530
132
  const settings = {};
531
- const stopSequences = parseStopSequences(options.stopSequences);
532
- if (stopSequences && (provider === 'google' || provider === 'openrouter')) {
133
+ const stopSequences = (0, utils_1.parseStopSequences)(options.stopSequences);
134
+ if (stopSequences) {
533
135
  settings.stopSequences = stopSequences;
534
136
  }
535
- if (provider === 'google') {
536
- const safetySettingsRaw = exec.getNodeParameter('safetySettings.settings', index, []);
537
- if (safetySettingsRaw.length > 0) {
538
- settings.safetySettings = safetySettingsRaw.map((s) => ({
539
- category: s.category,
540
- threshold: s.threshold,
541
- }));
542
- }
543
- settings.structuredOutputs = operation === 'generateObject';
544
- const responseModalities = exec.getNodeParameter('responseModalities', index, []);
545
- if (responseModalities.length > 0) {
546
- settings.responseModalities = responseModalities;
547
- }
137
+ const strategy = (0, providers_1.getProviderStrategy)(provider);
138
+ if (strategy.getModelSettings) {
139
+ const providerSettings = strategy.getModelSettings(exec, index, operation);
140
+ Object.assign(settings, providerSettings);
548
141
  }
549
142
  return settings;
550
143
  }
551
- function getGoogleCustomHeaders(exec, index) {
144
+ function getCustomHeaders(exec, index) {
552
145
  const headersCollection = exec.getNodeParameter('customHeaders', index, {});
553
146
  const entries = headersCollection?.headers ?? [];
554
147
  if (!entries || entries.length === 0) {
@@ -565,41 +158,24 @@ function getGoogleCustomHeaders(exec, index) {
565
158
  }
566
159
  return Object.keys(headers).length > 0 ? headers : undefined;
567
160
  }
568
- function getGroqProviderOptions(exec, index, options) {
569
- const reasoningFormat = options.reasoningFormat;
570
- if (!reasoningFormat) {
571
- return undefined;
572
- }
573
- return {
574
- reasoningFormat,
575
- };
576
- }
577
161
  async function buildRequestParams(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey) {
578
- const googleProviderOptions = provider === 'google'
579
- ? await (0, helpers_1.setupGoogleProviderOptions)(exec, index, input, model, apiKey)
580
- : undefined;
581
- const groqProviderOptions = provider === 'groq' ? getGroqProviderOptions(exec, index, options) : undefined;
582
- const params = {
583
- model: aiProvider(model, modelSettings),
584
- };
585
- if (input.prompt)
586
- params.prompt = input.prompt;
587
- if (input.system)
588
- params.system = input.system;
589
- if (input.messages)
590
- params.messages = input.messages;
591
- if (provider === 'google' && googleProviderOptions) {
592
- params.providerOptions = {
593
- google: googleProviderOptions,
594
- };
595
- }
596
- if (provider === 'groq' && groqProviderOptions) {
597
- params.providerOptions = {
598
- groq: groqProviderOptions,
599
- };
600
- }
601
- if (provider === 'google' && !googleProviderOptions?.cachedContent) {
602
- (0, helpers_1.restoreCacheableContent)(params, input);
162
+ const strategy = (0, providers_1.getProviderStrategy)(provider);
163
+ const params = await strategy.buildApiParams(exec, index, aiProvider, model, modelSettings, input, options, apiKey);
164
+ const customTools = exec.getNodeParameter('customTools.tools', index, []);
165
+ if (customTools.length > 0) {
166
+ params.tools = {};
167
+ for (const tool of customTools) {
168
+ try {
169
+ const parameters = JSON.parse(tool.parameters);
170
+ params.tools[tool.name] = {
171
+ description: tool.description,
172
+ parameters: parameters,
173
+ };
174
+ }
175
+ catch (error) {
176
+ throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid JSON in parameters for tool "${tool.name}": ${error.message}`);
177
+ }
178
+ }
603
179
  }
604
180
  return params;
605
181
  }
@@ -616,12 +192,12 @@ async function generateTextOperation(exec, index, provider, aiProvider, model, m
616
192
  'presencePenalty',
617
193
  'seed',
618
194
  ];
619
- applyNumericOptions(params, options, textNumericKeys);
195
+ (0, utils_1.applyNumericOptions)(params, options, textNumericKeys);
620
196
  if (enableStreaming) {
621
197
  return await handleStreaming(params, provider, includeRequestBody);
622
198
  }
623
199
  const result = await (0, ai_1.generateText)(params);
624
- const formattedResult = formatTextResult(result, includeRequestBody, provider);
200
+ const formattedResult = (0, responseFormatter_1.formatTextResult)(result, includeRequestBody, provider);
625
201
  return [{ json: formattedResult }];
626
202
  }
627
203
  async function handleStreaming(params, provider, includeRequestBody) {
@@ -645,7 +221,7 @@ async function handleStreaming(params, provider, includeRequestBody) {
645
221
  toolCalls: stream.toolCalls || [],
646
222
  toolResults: stream.toolResults || [],
647
223
  finishReason: stream.finishReason,
648
- usage: finalUsage ? formatUsage({ usage: finalUsage }, provider) : undefined,
224
+ usage: finalUsage ? (0, responseFormatter_1.formatUsage)({ usage: finalUsage }, provider) : undefined,
649
225
  isStreaming: false,
650
226
  isFinal: true,
651
227
  };
@@ -663,11 +239,9 @@ async function handleStreaming(params, provider, includeRequestBody) {
663
239
  chunks.push({ json: finalJson });
664
240
  return chunks;
665
241
  }
666
- async function generateObjectOperation(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey, cacheManager) {
242
+ async function generateObjectOperation(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey, cacheManager, parsedSchema) {
667
243
  const schemaName = exec.getNodeParameter('schemaName', index, '');
668
244
  const schemaDescription = exec.getNodeParameter('schemaDescription', index, '');
669
- const rawSchema = exec.getNodeParameter('schema', index);
670
- const parsedSchema = parseAndValidateSchema(rawSchema, exec, cacheManager);
671
245
  const params = await buildRequestParams(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey);
672
246
  params.schema = (0, ai_1.jsonSchema)(parsedSchema);
673
247
  params.schemaName = schemaName;
@@ -680,9 +254,9 @@ async function generateObjectOperation(exec, index, provider, aiProvider, model,
680
254
  'presencePenalty',
681
255
  'seed',
682
256
  ];
683
- applyNumericOptions(params, options, objectNumericKeys);
257
+ (0, utils_1.applyNumericOptions)(params, options, objectNumericKeys);
684
258
  const result = await (0, ai_1.generateObject)(params);
685
- const formattedResult = formatObjectResult(result, options.includeRequestBody, provider);
259
+ const formattedResult = (0, responseFormatter_1.formatObjectResult)(result, options.includeRequestBody, provider);
686
260
  return [{ json: formattedResult }];
687
261
  }
688
262
  //# sourceMappingURL=UniversalAI.node.js.map