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.
- package/dist/nodes/UniversalAI/UniversalAI.node.js +49 -475
- package/dist/nodes/UniversalAI/UniversalAI.node.js.map +1 -1
- package/dist/nodes/UniversalAI/helpers/cacheMetrics.d.ts +3 -0
- package/dist/nodes/UniversalAI/helpers/cacheMetrics.js +12 -0
- package/dist/nodes/UniversalAI/helpers/cacheMetrics.js.map +1 -0
- package/dist/nodes/UniversalAI/helpers/inputBuilder.d.ts +8 -0
- package/dist/nodes/UniversalAI/helpers/inputBuilder.js +232 -0
- package/dist/nodes/UniversalAI/helpers/inputBuilder.js.map +1 -0
- package/dist/nodes/UniversalAI/helpers/responseFormatter.d.ts +7 -0
- package/dist/nodes/UniversalAI/helpers/responseFormatter.js +78 -0
- package/dist/nodes/UniversalAI/helpers/responseFormatter.js.map +1 -0
- package/dist/nodes/UniversalAI/helpers/utils.d.ts +5 -0
- package/dist/nodes/UniversalAI/helpers/utils.js +50 -0
- package/dist/nodes/UniversalAI/helpers/utils.js.map +1 -0
- package/dist/nodes/UniversalAI/providers/google.d.ts +16 -0
- package/dist/nodes/UniversalAI/providers/google.js +105 -0
- package/dist/nodes/UniversalAI/providers/google.js.map +1 -0
- package/dist/nodes/UniversalAI/providers/index.d.ts +3 -0
- package/dist/nodes/UniversalAI/providers/index.js +16 -0
- package/dist/nodes/UniversalAI/providers/index.js.map +1 -0
- package/dist/nodes/UniversalAI/providers/strategy.d.ts +15 -0
- package/dist/nodes/UniversalAI/providers/strategy.js +3 -0
- package/dist/nodes/UniversalAI/providers/strategy.js.map +1 -0
- package/dist/nodes/UniversalAI/providers/types.d.ts +15 -0
- package/dist/nodes/UniversalAI/providers/types.js +3 -0
- package/dist/nodes/UniversalAI/providers/types.js.map +1 -0
- package/dist/nodes/shared/DescriptionBuilder.d.ts +10 -0
- package/dist/nodes/shared/DescriptionBuilder.js +46 -0
- package/dist/nodes/shared/DescriptionBuilder.js.map +1 -0
- package/dist/nodes/shared/cache/cache.d.ts +1 -1
- package/dist/nodes/shared/cache/cache.js +4 -4
- package/dist/nodes/shared/cache/cache.js.map +1 -1
- package/dist/nodes/shared/descriptions.js +74 -271
- package/dist/nodes/shared/descriptions.js.map +1 -1
- package/dist/nodes/shared/helpers.js +4 -4
- package/dist/nodes/shared/helpers.js.map +1 -1
- package/dist/nodes/shared/icons/ai-chip.svg +32 -0
- package/dist/nodes/shared/icons/anthropic.svg +1 -0
- package/dist/nodes/shared/icons/gemini.svg +10 -0
- package/dist/nodes/shared/icons/groq.svg +1 -0
- package/dist/nodes/shared/icons/openai.svg +1 -0
- package/dist/nodes/shared/icons/openrouter.svg +39 -0
- package/dist/nodes/shared/icons.d.ts +1 -0
- package/dist/nodes/shared/icons.js +14 -0
- package/dist/nodes/shared/icons.js.map +1 -0
- package/dist/nodes/shared/letta/client.js +25 -12
- package/dist/nodes/shared/letta/client.js.map +1 -1
- package/dist/nodes/shared/providers.d.ts +7 -0
- package/dist/nodes/shared/providers.js +41 -0
- package/dist/nodes/shared/providers.js.map +1 -0
- 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
|
|
50
|
-
|
|
51
|
-
|
|
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 =
|
|
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
|
|
133
|
+
const stopSequences = (0, utils_1.parseStopSequences)(options.stopSequences);
|
|
134
|
+
if (stopSequences) {
|
|
533
135
|
settings.stopSequences = stopSequences;
|
|
534
136
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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
|
|
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
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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
|