n8n-nodes-vercel-ai-sdk-universal-temp 0.1.68 → 0.1.70

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.
@@ -42,135 +42,7 @@ const ai_1 = require("ai");
42
42
  const zod_1 = require("zod");
43
43
  const ajv_1 = __importDefault(require("ajv"));
44
44
  const descriptions_1 = require("../shared/descriptions");
45
- class Cache {
46
- constructor(maxSize = 100, ttl = 5 * 60 * 1000) {
47
- this.cache = new Map();
48
- this.totalHits = 0;
49
- this.totalMisses = 0;
50
- this.totalEvictions = 0;
51
- this.maxSize = maxSize;
52
- this.ttl = ttl;
53
- }
54
- get(key) {
55
- const item = this.cache.get(key);
56
- if (!item) {
57
- this.totalMisses++;
58
- return undefined;
59
- }
60
- const now = Date.now();
61
- if (item.expiresAt && now > item.expiresAt) {
62
- this.cache.delete(key);
63
- this.totalEvictions++;
64
- this.totalMisses++;
65
- return undefined;
66
- }
67
- item.hits++;
68
- this.totalHits++;
69
- return item.value;
70
- }
71
- set(key, value, customTTL) {
72
- const now = Date.now();
73
- const expiresAt = customTTL ? now + customTTL : (this.ttl > 0 ? now + this.ttl : undefined);
74
- if (this.cache.size >= this.maxSize) {
75
- let oldestKey;
76
- let oldestTime = now;
77
- for (const [k, v] of this.cache.entries()) {
78
- if (v.timestamp < oldestTime) {
79
- oldestTime = v.timestamp;
80
- oldestKey = k;
81
- }
82
- }
83
- if (oldestKey) {
84
- this.cache.delete(oldestKey);
85
- this.totalEvictions++;
86
- }
87
- }
88
- this.cache.set(key, { value, timestamp: now, hits: 0, expiresAt });
89
- }
90
- delete(key) {
91
- return this.cache.delete(key);
92
- }
93
- clear() {
94
- this.cache.clear();
95
- this.totalHits = 0;
96
- this.totalMisses = 0;
97
- this.totalEvictions = 0;
98
- }
99
- getStats() {
100
- return {
101
- size: this.cache.size,
102
- maxSize: this.maxSize,
103
- hitRate: this.totalHits / (this.totalHits + this.totalMisses) || 0,
104
- totalHits: this.totalHits,
105
- totalMisses: this.totalMisses,
106
- totalEvictions: this.totalEvictions,
107
- ttl: this.ttl,
108
- };
109
- }
110
- }
111
- const modelCache = new Cache(50);
112
- const providerCache = new Cache(20);
113
- const schemaCache = new Cache(30);
114
- const googleCacheClients = new Cache(10, 60 * 60 * 1000);
115
- const googleCachedContexts = new Cache(50, 55 * 60 * 1000);
116
- async function getGoogleCacheManager(apiKey) {
117
- let client = googleCacheClients.get(apiKey);
118
- if (!client) {
119
- const { GoogleGenAI } = await Promise.resolve().then(() => __importStar(require('@google/genai')));
120
- client = new GoogleGenAI({ apiKey });
121
- googleCacheClients.set(apiKey, client);
122
- }
123
- return client;
124
- }
125
- async function createGoogleCache(exec, index, apiKey, cacheableContent, modelId, thinkingBudgetValue, includeThoughts, tools, ttlSeconds) {
126
- try {
127
- if (!cacheableContent || cacheableContent.length === 0) {
128
- return null;
129
- }
130
- const googleCacheManager = await getGoogleCacheManager(apiKey);
131
- const cacheKeyData = {
132
- content: JSON.stringify(cacheableContent),
133
- tools: tools ? Object.keys(tools).sort() : [],
134
- model: modelId,
135
- };
136
- const cacheKey = JSON.stringify(cacheKeyData, Object.keys(cacheKeyData).sort());
137
- const existingCache = googleCachedContexts.get(cacheKey);
138
- if (existingCache) {
139
- console.log(`UniversalAI: Reusing existing cache: ${existingCache.name}`);
140
- return existingCache.name;
141
- }
142
- const ttl = ttlSeconds || 3600;
143
- const displayName = `universal_ai_cache_${Date.now()}`;
144
- const cacheConfig = {
145
- model: modelId,
146
- config: {
147
- displayName,
148
- ttl: `${ttl}s`,
149
- contents: cacheableContent,
150
- },
151
- };
152
- if (tools && Object.keys(tools).length > 0) {
153
- cacheConfig.config.tools = Object.values(tools);
154
- }
155
- console.log(`UniversalAI: Creating new cache...`);
156
- const result = await googleCacheManager.caches.create(cacheConfig);
157
- const cachedContentName = result === null || result === void 0 ? void 0 : result.name;
158
- if (!cachedContentName) {
159
- throw new Error('Cache creation returned no name identifier');
160
- }
161
- console.log(`UniversalAI: Cache created successfully: ${cachedContentName}`);
162
- googleCachedContexts.set(cacheKey, { name: cachedContentName }, (ttl - 300) * 1000);
163
- return cachedContentName;
164
- }
165
- catch (error) {
166
- const errorMessage = error instanceof Error ? error.message : String(error);
167
- console.error('UniversalAI: Google cache creation failed:', errorMessage);
168
- if (errorMessage.includes('INVALID_ARGUMENT') || errorMessage.includes('content is too small')) {
169
- console.warn('UniversalAI: Content may be below minimum token requirement (1,024 tokens (~4800 symbols) for 2.5 Flash and 2,048 tokens (~9600 symbols) for 2.5 Pro)');
170
- }
171
- return null;
172
- }
173
- }
45
+ const helpers_1 = require("../shared/helpers");
174
46
  const messageSchema = zod_1.z.object({
175
47
  role: zod_1.z.enum(['system', 'user', 'assistant']),
176
48
  content: zod_1.z.any(),
@@ -308,78 +180,75 @@ async function buildMessageWithAttachments(role, content, attachments, itemBinar
308
180
  if (content) {
309
181
  parts.push({ type: 'text', text: content });
310
182
  }
311
- const MAX_CONCURRENT_ATTACHMENTS = 3;
312
- const processedAttachments = [];
313
- for (let i = 0; i < attachments.length; i += MAX_CONCURRENT_ATTACHMENTS) {
314
- const batch = attachments.slice(i, i + MAX_CONCURRENT_ATTACHMENTS);
315
- const batchPromises = batch.map(attachment => processAttachment(attachment, itemBinary, exec, itemIndex, shouldCacheMessage, cacheableContent));
316
- const batchResults = await Promise.all(batchPromises);
317
- processedAttachments.push(...batchResults);
318
- }
319
- for (const attachment of processedAttachments) {
320
- if (attachment) {
321
- parts.push(attachment);
183
+ for (const attachment of attachments) {
184
+ const filePart = await processAttachment(attachment, itemBinary, exec, itemIndex, shouldCacheMessage, cacheableContent);
185
+ if (filePart) {
186
+ parts.push(filePart);
322
187
  }
323
188
  }
324
189
  return parts.length > 0 ? { role, content: parts } : null;
325
190
  }
326
191
  async function processAttachment(attachment, itemBinary, exec, itemIndex, shouldCacheMessage, cacheableContent) {
327
- const fileContentInput = attachment.fileContent;
328
- if (!fileContentInput || typeof fileContentInput !== 'string')
192
+ const fileResult = await processFileData(attachment.fileContent, itemBinary, attachment, cacheableContent, exec, itemIndex);
193
+ if (!fileResult)
329
194
  return null;
330
- let mimeType = getMimeType(attachment);
331
- let fileData;
332
- if (isUrl(fileContentInput)) {
333
- fileData = fileContentInput;
334
- if (attachment.cacheAttachment === true) {
335
- cacheableContent.push({
336
- role: 'user',
337
- parts: [{ fileUri: fileContentInput, mimeType: mimeType || 'application/octet-stream' }],
338
- });
339
- return null;
340
- }
341
- }
342
- else {
343
- const result = await getBinaryData(fileContentInput, itemBinary, exec, itemIndex);
344
- fileData = result.data;
345
- if (!mimeType && result.mimeType) {
346
- mimeType = result.mimeType;
347
- }
348
- }
349
- if (!fileData || (Buffer.isBuffer(fileData) && fileData.length === 0)) {
350
- return null;
351
- }
352
195
  return {
353
196
  type: 'file',
354
- data: fileData,
355
- mediaType: mimeType || 'application/octet-stream',
197
+ data: fileResult.data,
198
+ mediaType: fileResult.mimeType,
356
199
  };
357
200
  }
358
- function getMimeType(attachment) {
359
- return attachment.mimeType === 'other'
360
- ? attachment.mimeTypeOther
361
- : attachment.mimeType;
362
- }
363
- async function getBinaryData(fileContentInput, itemBinary, exec, itemIndex) {
364
- if (itemBinary === null || itemBinary === void 0 ? void 0 : itemBinary[fileContentInput]) {
365
- const binaryData = itemBinary[fileContentInput];
366
- return {
367
- data: Buffer.from(binaryData.data, 'base64'),
368
- mimeType: binaryData.mimeType,
369
- };
201
+ async function processFileData(fileContentInput, itemBinary, attachment, cacheableContent, exec, itemIndex) {
202
+ if (!fileContentInput || typeof fileContentInput !== 'string') {
203
+ return null;
370
204
  }
205
+ let mimeType = attachment.mimeType === 'other' ? attachment.mimeTypeOther : attachment.mimeType;
206
+ let fileData;
207
+ let shouldCache = attachment.cacheAttachment === true;
371
208
  try {
372
- if (isLikelyBase64(fileContentInput)) {
373
- const buffer = Buffer.from(fileContentInput, 'base64');
374
- if (buffer.length > 0 && buffer.length < 50 * 1024 * 1024) {
375
- return { data: buffer, mimeType: undefined };
209
+ if (isUrl(fileContentInput)) {
210
+ fileData = fileContentInput;
211
+ if (shouldCache) {
212
+ cacheableContent.push({
213
+ role: 'user',
214
+ parts: [{ fileUri: fileContentInput, mimeType: mimeType || 'application/octet-stream' }],
215
+ });
216
+ return null;
217
+ }
218
+ }
219
+ else if (fileContentInput.startsWith('data:')) {
220
+ const dataUriMatch = fileContentInput.match(/^data:([^;]+);base64,(.+)$/);
221
+ if (!dataUriMatch)
222
+ return null;
223
+ const [, extractedMimeType, base64Data] = dataUriMatch;
224
+ fileData = Buffer.from(base64Data, 'base64');
225
+ if (fileData.length > 20 * 1024 * 1024) {
226
+ throw new Error('Base64 data exceeds 20MB limit');
227
+ }
228
+ mimeType = mimeType || extractedMimeType;
229
+ }
230
+ else if (isLikelyBase64(fileContentInput)) {
231
+ fileData = Buffer.from(fileContentInput, 'base64');
232
+ if (fileData.length > 20 * 1024 * 1024) {
233
+ throw new Error('Base64 data exceeds 20MB limit');
376
234
  }
377
235
  }
236
+ else if (itemBinary === null || itemBinary === void 0 ? void 0 : itemBinary[fileContentInput]) {
237
+ const binaryData = itemBinary[fileContentInput];
238
+ fileData = Buffer.from(binaryData.data, 'base64');
239
+ mimeType = mimeType || binaryData.mimeType;
240
+ }
241
+ else {
242
+ return null;
243
+ }
244
+ if (!fileData || (Buffer.isBuffer(fileData) && fileData.length === 0)) {
245
+ return null;
246
+ }
247
+ return { data: fileData, mimeType: mimeType || 'application/octet-stream', shouldCache };
378
248
  }
379
249
  catch (error) {
380
250
  throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid file content for attachment: ${error.message}`);
381
251
  }
382
- return { data: null, mimeType: undefined };
383
252
  }
384
253
  function formatTextResult(result, includeRequestBody, provider) {
385
254
  var _a, _b, _c, _d, _e;
@@ -511,52 +380,9 @@ function formatResponse(result) {
511
380
  headers: (_d = result.response) === null || _d === void 0 ? void 0 : _d.headers,
512
381
  };
513
382
  }
514
- async function getProvider(provider, apiKey, baseURL, customHeaders) {
515
- const headersKey = customHeaders
516
- ? JSON.stringify(Object.keys(customHeaders)
517
- .sort()
518
- .map((key) => [key, customHeaders[key]]))
519
- : '';
520
- const cacheKey = `${provider}:${apiKey}:${baseURL || ''}:${headersKey}`;
521
- const cached = providerCache.get(cacheKey);
522
- if (cached)
523
- return cached;
524
- let providerInstance;
525
- try {
526
- switch (provider) {
527
- case 'google':
528
- const { createGoogleGenerativeAI } = await Promise.resolve().then(() => __importStar(require('@ai-sdk/google')));
529
- providerInstance = createGoogleGenerativeAI({
530
- apiKey,
531
- ...(baseURL && { baseURL }),
532
- ...(customHeaders && Object.keys(customHeaders).length > 0 && { headers: customHeaders }),
533
- });
534
- break;
535
- case 'deepseek':
536
- const { createDeepSeek } = await Promise.resolve().then(() => __importStar(require('@ai-sdk/deepseek')));
537
- providerInstance = createDeepSeek({ apiKey, ...(baseURL && { baseURL }) });
538
- break;
539
- case 'groq':
540
- const { createGroq } = await Promise.resolve().then(() => __importStar(require('@ai-sdk/groq')));
541
- providerInstance = createGroq({ apiKey, ...(baseURL && { baseURL }) });
542
- break;
543
- case 'openrouter':
544
- const { createOpenRouter } = await Promise.resolve().then(() => __importStar(require('@openrouter/ai-sdk-provider')));
545
- providerInstance = createOpenRouter({ apiKey, ...(baseURL && { baseURL }) });
546
- break;
547
- default:
548
- throw new Error(`Unsupported provider: ${provider}`);
549
- }
550
- providerCache.set(cacheKey, providerInstance);
551
- return providerInstance;
552
- }
553
- catch (error) {
554
- throw new Error(`Failed to initialize ${provider} provider: ${error.message}`);
555
- }
556
- }
557
383
  function parseAndValidateSchema(rawSchema, exec) {
558
384
  const cacheKey = `schema:${Buffer.from(rawSchema).toString('base64').substring(0, 50)}`;
559
- const cached = schemaCache.get(cacheKey);
385
+ const cached = helpers_1.schemaCache.get(cacheKey);
560
386
  if (cached)
561
387
  return cached;
562
388
  let parsedSchema;
@@ -569,7 +395,7 @@ function parseAndValidateSchema(rawSchema, exec) {
569
395
  if (!ajv.validateSchema(parsedSchema)) {
570
396
  throw new n8n_workflow_1.NodeOperationError(exec.getNode(), `Invalid JSON Schema: ${ajv.errorsText(ajv.errors)}`);
571
397
  }
572
- schemaCache.set(cacheKey, parsedSchema);
398
+ helpers_1.schemaCache.set(cacheKey, parsedSchema);
573
399
  return parsedSchema;
574
400
  }
575
401
  function parseStopSequences(stopSequencesStr) {
@@ -593,17 +419,17 @@ class UniversalAI {
593
419
  async getModels() {
594
420
  const provider = this.getCurrentNodeParameter('provider');
595
421
  const cacheKey = `models:${provider}`;
596
- const cached = modelCache.get(cacheKey);
422
+ const cached = helpers_1.modelCache.get(cacheKey);
597
423
  if (cached)
598
424
  return cached;
599
- const { OPENROUTER_MODELS, GOOGLE_GEMINI_MODELS, DEEPSEEK_MODELS, GROQ_MODELS } = await Promise.resolve().then(() => __importStar(require('./model-lists')));
425
+ const { OPENROUTER_MODELS, GOOGLE_GEMINI_MODELS, DEEPSEEK_MODELS, GROQ_MODELS } = await Promise.resolve().then(() => __importStar(require('../shared//model-lists')));
600
426
  const models = {
601
427
  google: GOOGLE_GEMINI_MODELS,
602
428
  deepseek: DEEPSEEK_MODELS,
603
429
  groq: GROQ_MODELS,
604
430
  openrouter: OPENROUTER_MODELS,
605
431
  }[provider] || [];
606
- modelCache.set(cacheKey, models);
432
+ helpers_1.modelCache.set(cacheKey, models);
607
433
  return models;
608
434
  },
609
435
  },
@@ -613,25 +439,13 @@ class UniversalAI {
613
439
  const items = this.getInputData();
614
440
  const returnData = [];
615
441
  const provider = this.getNodeParameter('provider', 0);
616
- const credentialType = {
617
- google: 'googleGenerativeAIApi',
618
- deepseek: 'deepSeekApi',
619
- groq: 'groqApi',
620
- openrouter: 'openRouterApi',
621
- }[provider];
622
- if (!credentialType) {
623
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported provider: ${provider}`);
624
- }
625
- const credentials = await this.getCredentials(credentialType);
626
- if (!(credentials === null || credentials === void 0 ? void 0 : credentials.apiKey)) {
627
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No API key provided in credentials');
628
- }
442
+ const { apiKey, baseUrl } = await (0, helpers_1.getCredentials)(this, provider);
629
443
  const customHeaders = provider === 'google' ? getGoogleCustomHeaders(this, 0) : undefined;
630
- const aiProvider = await getProvider(provider, credentials.apiKey, credentials.baseUrl, customHeaders);
444
+ const aiProvider = await (0, helpers_1.getProvider)(this, provider, apiKey, baseUrl, customHeaders);
631
445
  for (let i = 0; i < items.length; i++) {
632
446
  if (this.continueOnFail()) {
633
447
  try {
634
- const result = await processItem(this, i, provider, aiProvider, credentials.apiKey);
448
+ const result = await processItem(this, i, provider, aiProvider, apiKey);
635
449
  returnData.push(...result);
636
450
  }
637
451
  catch (error) {
@@ -643,7 +457,7 @@ class UniversalAI {
643
457
  }
644
458
  }
645
459
  else {
646
- const result = await processItem(this, i, provider, aiProvider, credentials.apiKey);
460
+ const result = await processItem(this, i, provider, aiProvider, apiKey);
647
461
  returnData.push(...result);
648
462
  }
649
463
  }
@@ -683,21 +497,6 @@ function getModelSettings(exec, index, provider, operation, options) {
683
497
  }
684
498
  return settings;
685
499
  }
686
- function buildGoogleProviderOptions(exec, index, cachedContentName, thinkingBudgetOverride, includeThoughtsOverride) {
687
- const thinkingBudgetValue = thinkingBudgetOverride !== null && thinkingBudgetOverride !== void 0 ? thinkingBudgetOverride : Number(exec.getNodeParameter('thinkingBudget', index, -1));
688
- const includeThoughts = includeThoughtsOverride !== null && includeThoughtsOverride !== void 0 ? includeThoughtsOverride : exec.getNodeParameter('includeThoughts', index, false);
689
- const options = {};
690
- if (!Number.isNaN(thinkingBudgetValue) && thinkingBudgetValue > -1) {
691
- options.thinkingConfig = {
692
- thinkingBudget: Math.max(0, thinkingBudgetValue),
693
- includeThoughts,
694
- };
695
- }
696
- if (cachedContentName) {
697
- options.cachedContent = cachedContentName;
698
- }
699
- return Object.keys(options).length > 0 ? options : undefined;
700
- }
701
500
  function getGoogleCustomHeaders(exec, index) {
702
501
  var _a, _b;
703
502
  const headersCollection = exec.getNodeParameter('customHeaders', index, {});
@@ -719,30 +518,9 @@ function getGoogleCustomHeaders(exec, index) {
719
518
  async function generateTextOperation(exec, index, provider, aiProvider, model, modelSettings, input, options, apiKey) {
720
519
  const enableStreaming = exec.getNodeParameter('enableStreaming', index, false);
721
520
  const includeRequestBody = options.includeRequestBody;
722
- const tools = provider === 'google' ? await buildGoogleTools(exec, index) : undefined;
723
- let googleProviderOptions;
724
- let thinkingBudgetValue;
725
- let includeThoughts;
726
- if (provider === 'google') {
727
- thinkingBudgetValue = Number(exec.getNodeParameter('thinkingBudget', index, -1));
728
- includeThoughts = exec.getNodeParameter('includeThoughts', index, false);
729
- }
730
- if (provider === 'google' &&
731
- input.cacheableContent &&
732
- input.cacheableContent.length > 0) {
733
- const cacheTTL = exec.getNodeParameter('cacheTTL', index, 3600);
734
- const cachedContentName = await createGoogleCache(exec, index, apiKey, input.cacheableContent, model, thinkingBudgetValue !== null && thinkingBudgetValue !== void 0 ? thinkingBudgetValue : -1, includeThoughts !== null && includeThoughts !== void 0 ? includeThoughts : false, tools, cacheTTL);
735
- if (cachedContentName) {
736
- googleProviderOptions = buildGoogleProviderOptions(exec, index, cachedContentName, thinkingBudgetValue, includeThoughts);
737
- }
738
- else {
739
- googleProviderOptions = buildGoogleProviderOptions(exec, index, undefined, thinkingBudgetValue, includeThoughts);
740
- console.log('UniversalAI: Cache creation failed, falling back to regular content');
741
- }
742
- }
743
- else if (provider === 'google') {
744
- googleProviderOptions = buildGoogleProviderOptions(exec, index, undefined, thinkingBudgetValue, includeThoughts);
745
- }
521
+ const googleProviderOptions = provider === 'google'
522
+ ? await (0, helpers_1.setupGoogleProviderOptions)(exec, index, input, model, apiKey)
523
+ : undefined;
746
524
  const params = {
747
525
  model: aiProvider(model, modelSettings),
748
526
  };
@@ -752,50 +530,13 @@ async function generateTextOperation(exec, index, provider, aiProvider, model, m
752
530
  params.system = input.system;
753
531
  if (input.messages)
754
532
  params.messages = input.messages;
755
- if (tools && Object.keys(tools).length > 0) {
756
- params.tools = tools;
757
- }
758
533
  if (provider === 'google' && googleProviderOptions) {
759
534
  params.providerOptions = {
760
535
  google: googleProviderOptions,
761
536
  };
762
537
  }
763
- if (provider === 'google' &&
764
- input.cacheableContent &&
765
- input.cacheableContent.length > 0 &&
766
- !(googleProviderOptions === null || googleProviderOptions === void 0 ? void 0 : googleProviderOptions.cachedContent)) {
767
- if (input.messages && input.messages.length > 0) {
768
- const fallbackMessages = input.cacheableContent.map(content => {
769
- const role = content.role === 'model' ? 'assistant' : (content.role === 'user' ? 'user' : 'system');
770
- const textParts = content.parts
771
- .filter(part => 'text' in part)
772
- .map(part => part.text);
773
- return {
774
- role: role,
775
- content: textParts.join('\n')
776
- };
777
- });
778
- params.messages = [...fallbackMessages, ...(params.messages || [])];
779
- }
780
- else {
781
- for (const content of input.cacheableContent) {
782
- const textParts = content.parts
783
- .filter(part => 'text' in part)
784
- .map(part => part.text)
785
- .join('\n');
786
- if (textParts.trim()) {
787
- if (!params.system) {
788
- params.system = textParts.trim();
789
- }
790
- else if (!params.prompt) {
791
- params.prompt = textParts.trim();
792
- }
793
- else {
794
- params.prompt = params.prompt + '\n\n' + textParts.trim();
795
- }
796
- }
797
- }
798
- }
538
+ if (provider === 'google' && !(googleProviderOptions === null || googleProviderOptions === void 0 ? void 0 : googleProviderOptions.cachedContent)) {
539
+ (0, helpers_1.restoreCacheableContent)(params, input);
799
540
  }
800
541
  const textNumericKeys = [
801
542
  'maxTokens',
@@ -814,25 +555,6 @@ async function generateTextOperation(exec, index, provider, aiProvider, model, m
814
555
  const formattedResult = formatTextResult(result, includeRequestBody, provider);
815
556
  return [{ json: formattedResult }];
816
557
  }
817
- async function buildGoogleTools(exec, index) {
818
- const googleTools = exec.getNodeParameter('googleTools', index, []);
819
- if (!googleTools || googleTools.length === 0) {
820
- return undefined;
821
- }
822
- const tools = {};
823
- const { google } = await Promise.resolve().then(() => __importStar(require('@ai-sdk/google')));
824
- const toolSet = new Set(googleTools);
825
- if (toolSet.has('google_search')) {
826
- tools.google_search = google.tools.googleSearch({});
827
- }
828
- if (toolSet.has('url_context')) {
829
- tools.url_context = google.tools.urlContext({});
830
- }
831
- if (toolSet.has('code_execution')) {
832
- tools.code_execution = google.tools.codeExecution({});
833
- }
834
- return tools;
835
- }
836
558
  async function handleStreaming(params, provider, includeRequestBody) {
837
559
  const stream = await (0, ai_1.streamText)(params);
838
560
  const chunks = [];
@@ -877,29 +599,9 @@ async function generateObjectOperation(exec, index, provider, aiProvider, model,
877
599
  const schemaDescription = exec.getNodeParameter('schemaDescription', index, '');
878
600
  const rawSchema = exec.getNodeParameter('schema', index);
879
601
  const parsedSchema = parseAndValidateSchema(rawSchema, exec);
880
- let googleProviderOptions;
881
- let thinkingBudgetValue;
882
- let includeThoughts;
883
- if (provider === 'google') {
884
- thinkingBudgetValue = Number(exec.getNodeParameter('thinkingBudget', index, -1));
885
- includeThoughts = exec.getNodeParameter('includeThoughts', index, false);
886
- }
887
- if (provider === 'google' &&
888
- input.cacheableContent &&
889
- input.cacheableContent.length > 0) {
890
- const cacheTTL = exec.getNodeParameter('cacheTTL', index, 3600);
891
- const cachedContentName = await createGoogleCache(exec, index, apiKey, input.cacheableContent, model, thinkingBudgetValue !== null && thinkingBudgetValue !== void 0 ? thinkingBudgetValue : -1, includeThoughts !== null && includeThoughts !== void 0 ? includeThoughts : false, undefined, cacheTTL);
892
- if (cachedContentName) {
893
- googleProviderOptions = buildGoogleProviderOptions(exec, index, cachedContentName, thinkingBudgetValue, includeThoughts);
894
- }
895
- else {
896
- googleProviderOptions = buildGoogleProviderOptions(exec, index, undefined, thinkingBudgetValue, includeThoughts);
897
- console.log('UniversalAI: Cache creation failed, falling back to regular content');
898
- }
899
- }
900
- else if (provider === 'google') {
901
- googleProviderOptions = buildGoogleProviderOptions(exec, index, undefined, thinkingBudgetValue, includeThoughts);
902
- }
602
+ const googleProviderOptions = provider === 'google'
603
+ ? await (0, helpers_1.setupGoogleProviderOptions)(exec, index, input, model, apiKey)
604
+ : undefined;
903
605
  const params = {
904
606
  model: aiProvider(model, modelSettings),
905
607
  schema: (0, ai_1.jsonSchema)(parsedSchema),
@@ -917,42 +619,8 @@ async function generateObjectOperation(exec, index, provider, aiProvider, model,
917
619
  google: googleProviderOptions,
918
620
  };
919
621
  }
920
- if (provider === 'google' &&
921
- input.cacheableContent &&
922
- input.cacheableContent.length > 0 &&
923
- !(googleProviderOptions === null || googleProviderOptions === void 0 ? void 0 : googleProviderOptions.cachedContent)) {
924
- if (input.messages && input.messages.length > 0) {
925
- const fallbackMessages = input.cacheableContent.map(content => {
926
- const role = content.role === 'model' ? 'assistant' : (content.role === 'user' ? 'user' : 'system');
927
- const textParts = content.parts
928
- .filter(part => 'text' in part)
929
- .map(part => part.text);
930
- return {
931
- role: role,
932
- content: textParts.join('\n')
933
- };
934
- });
935
- params.messages = [...fallbackMessages, ...(params.messages || [])];
936
- }
937
- else {
938
- for (const content of input.cacheableContent) {
939
- const textParts = content.parts
940
- .filter(part => 'text' in part)
941
- .map(part => part.text)
942
- .join('\n');
943
- if (textParts.trim()) {
944
- if (!params.system) {
945
- params.system = textParts.trim();
946
- }
947
- else if (!params.prompt) {
948
- params.prompt = textParts.trim();
949
- }
950
- else {
951
- params.prompt = params.prompt + '\n\n' + textParts.trim();
952
- }
953
- }
954
- }
955
- }
622
+ if (provider === 'google' && !(googleProviderOptions === null || googleProviderOptions === void 0 ? void 0 : googleProviderOptions.cachedContent)) {
623
+ (0, helpers_1.restoreCacheableContent)(params, input);
956
624
  }
957
625
  const objectNumericKeys = [
958
626
  'temperature',