@olane/o-intelligence 0.7.59 → 0.7.61

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.
@@ -0,0 +1,153 @@
1
+ /**
2
+ * BaseIntelligenceTool - Abstract base class for LLM provider tools
3
+ *
4
+ * This base class extracts common patterns from all provider intelligence tools:
5
+ * - Validation (API keys, messages, prompts)
6
+ * - Error handling (throw errors, no error returns)
7
+ * - Streaming vs non-streaming patterns
8
+ * - Tool method templates (_tool_completion, _tool_generate, etc.)
9
+ *
10
+ * Provider-specific implementations extend this class and implement:
11
+ * - getApiKeyEnvVar(): Returns the environment variable name for the API key
12
+ * - callCompletion(params): Makes the actual API call for completion
13
+ * - streamCompletion(params): Handles streaming completion
14
+ * - callGenerate(params): Makes the actual API call for generation
15
+ * - streamGenerate(params): Handles streaming generation
16
+ *
17
+ * Subclasses can use either HTTP fetch() or official SDKs with Braintrust instrumentation.
18
+ */
19
+ import { oLaneTool } from '@olane/o-lane';
20
+ import { StreamUtils } from '@olane/o-node';
21
+ /**
22
+ * Abstract base class for intelligence provider tools
23
+ *
24
+ * Usage (subclass example):
25
+ * ```typescript
26
+ * export class AnthropicIntelligenceTool extends BaseIntelligenceTool {
27
+ * constructor(config: oNodeToolConfig) {
28
+ * super({
29
+ * ...config,
30
+ * address: new oAddress('o://anthropic'),
31
+ * description: 'Anthropic LLM provider',
32
+ * defaultModel: 'claude-sonnet-4-5-20250929',
33
+ * });
34
+ * }
35
+ *
36
+ * protected getApiKeyEnvVar(): string {
37
+ * return 'ANTHROPIC_API_KEY';
38
+ * }
39
+ *
40
+ * protected async callCompletion(params: any): Promise<ToolResult> {
41
+ * // Anthropic-specific HTTP implementation or SDK call
42
+ * }
43
+ *
44
+ * protected async *streamCompletion(params: any): AsyncGenerator<ToolResult> {
45
+ * // Anthropic-specific streaming implementation
46
+ * }
47
+ * }
48
+ * ```
49
+ */
50
+ export class BaseIntelligenceTool extends oLaneTool {
51
+ constructor(config) {
52
+ super({
53
+ ...config,
54
+ dependencies: config.dependencies || [],
55
+ });
56
+ this.defaultModel = config.defaultModel || '';
57
+ this.apiKey = config.apiKey || process.env[this.getApiKeyEnvVar()] || '';
58
+ }
59
+ /**
60
+ * Shared validation: API key
61
+ * ✅ Throws error for validation failure
62
+ */
63
+ validateApiKey(apiKey) {
64
+ if (!apiKey) {
65
+ throw new Error(`${this.getApiKeyEnvVar()} is required`);
66
+ }
67
+ }
68
+ /**
69
+ * Shared validation: Messages array
70
+ * ✅ Throws error for validation failure
71
+ */
72
+ validateMessages(messages) {
73
+ if (!messages || !Array.isArray(messages)) {
74
+ throw new Error('"messages" array is required');
75
+ }
76
+ if (messages.length === 0) {
77
+ throw new Error('"messages" array cannot be empty');
78
+ }
79
+ }
80
+ /**
81
+ * Shared validation: Prompt string
82
+ * ✅ Throws error for validation failure
83
+ */
84
+ validatePrompt(prompt) {
85
+ if (!prompt) {
86
+ throw new Error('Prompt is required');
87
+ }
88
+ if (typeof prompt !== 'string') {
89
+ throw new Error('Prompt must be a string');
90
+ }
91
+ }
92
+ /**
93
+ * Tool method: Chat completion
94
+ * ✅ Template method pattern - delegates to subclass
95
+ * ✅ Handles streaming vs non-streaming
96
+ * ✅ Throws errors (base class wraps them)
97
+ */
98
+ async _tool_completion(request) {
99
+ const params = request.params;
100
+ const { _isStreaming = false } = params;
101
+ if (_isStreaming) {
102
+ this.logger.debug('Streaming completion...');
103
+ const gen = this.streamCompletion(params);
104
+ return StreamUtils.processGenerator(request, gen, request.stream);
105
+ }
106
+ try {
107
+ return await this.callCompletion(params);
108
+ }
109
+ catch (error) {
110
+ throw new Error(`Failed to complete chat: ${error.message}`);
111
+ }
112
+ }
113
+ /**
114
+ * Tool method: Text generation
115
+ * ✅ Template method pattern - delegates to subclass
116
+ * ✅ Handles streaming vs non-streaming
117
+ * ✅ Throws errors (base class wraps them)
118
+ */
119
+ async _tool_generate(request) {
120
+ const params = request.params;
121
+ const { _isStreaming = false } = params;
122
+ if (_isStreaming) {
123
+ return StreamUtils.processGenerator(request, this.streamGenerate(params), request.stream);
124
+ }
125
+ try {
126
+ return await this.callGenerate(params);
127
+ }
128
+ catch (error) {
129
+ throw new Error(`Failed to generate text: ${error.message}`);
130
+ }
131
+ }
132
+ /**
133
+ * Tool method: List models
134
+ * Default implementation - subclasses can override
135
+ */
136
+ async _tool_list_models(request) {
137
+ throw new Error('list_models not implemented for this provider');
138
+ }
139
+ /**
140
+ * Tool method: Get model info
141
+ * Default implementation - subclasses can override
142
+ */
143
+ async _tool_model_info(request) {
144
+ throw new Error('model_info not implemented for this provider');
145
+ }
146
+ /**
147
+ * Tool method: Check API status
148
+ * Default implementation - subclasses can override
149
+ */
150
+ async _tool_status(request) {
151
+ throw new Error('status check not implemented for this provider');
152
+ }
153
+ }
@@ -3,9 +3,9 @@ import { ToolResult } from '@olane/o-tool';
3
3
  import { oLaneTool } from '@olane/o-lane';
4
4
  import { oNodeToolConfig, oStreamRequest } from '@olane/o-node';
5
5
  export declare class GeminiIntelligenceTool extends oLaneTool {
6
- private apiKey;
7
- private baseUrl;
8
- private defaultModel;
6
+ protected apiKey: string;
7
+ protected baseUrl: string;
8
+ protected defaultModel: string;
9
9
  constructor(config: oNodeToolConfig);
10
10
  /**
11
11
  * Chat completion with Gemini
@@ -35,5 +35,17 @@ export declare class GeminiIntelligenceTool extends oLaneTool {
35
35
  * Check Gemini API status
36
36
  */
37
37
  _tool_status(request: oRequest): Promise<ToolResult>;
38
+ /**
39
+ * Generate image from text prompt using Gemini nano-banana models
40
+ */
41
+ _tool_generate_image(request: oRequest): Promise<ToolResult>;
42
+ /**
43
+ * Edit or transform an existing image using Gemini nano-banana models
44
+ */
45
+ _tool_edit_image(request: oRequest): Promise<ToolResult>;
46
+ /**
47
+ * Helper method to encode image file to base64
48
+ */
49
+ private encodeImageToBase64;
38
50
  }
39
51
  //# sourceMappingURL=gemini-intelligence.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gemini-intelligence.tool.d.ts","sourceRoot":"","sources":["../../src/gemini-intelligence.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAEL,eAAe,EACf,cAAc,EAEf,MAAM,eAAe,CAAC;AAgHvB,qBAAa,sBAAuB,SAAQ,SAAS;IACnD,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,YAAY,CAAU;gBAElB,MAAM,EAAE,eAAe;IAUnC;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA6FpE;;OAEG;YACY,iBAAiB;IA8HhC;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA8FlE;;OAEG;YACY,eAAe;IA+H9B;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IA0C/D;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IA4C9D;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;CAiC3D"}
1
+ {"version":3,"file":"gemini-intelligence.tool.d.ts","sourceRoot":"","sources":["../../src/gemini-intelligence.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAEL,eAAe,EACf,cAAc,EAEf,MAAM,eAAe,CAAC;AA2JvB,qBAAa,sBAAuB,SAAQ,SAAS;IACnD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAoC;IAC5D,SAAS,CAAC,OAAO,EAAE,MAAM,CAC4B;IACrD,SAAS,CAAC,YAAY,EAAE,MAAM,CAA0B;gBAE5C,MAAM,EAAE,eAAe;IAUnC;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA6FpE;;OAEG;YACY,iBAAiB;IA+HhC;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA8FlE;;OAEG;YACY,eAAe;IAgI9B;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAwC/D;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IA0C9D;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAgC1D;;OAEG;IACG,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAgHlE;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IA0J9D;;OAEG;YACW,mBAAmB;CA0BlC"}
@@ -2,6 +2,7 @@ import { oAddress } from '@olane/o-core';
2
2
  import { LLM_PARAMS } from './methods/llm.methods.js';
3
3
  import { oLaneTool } from '@olane/o-lane';
4
4
  import { StreamUtils, } from '@olane/o-node';
5
+ import { readFile } from 'fs/promises';
5
6
  export class GeminiIntelligenceTool extends oLaneTool {
6
7
  constructor(config) {
7
8
  super({
@@ -12,6 +13,8 @@ export class GeminiIntelligenceTool extends oLaneTool {
12
13
  dependencies: [],
13
14
  });
14
15
  this.apiKey = process.env.GEMINI_API_KEY || '';
16
+ this.baseUrl = 'https://generativelanguage.googleapis.com/v1beta';
17
+ this.defaultModel = 'gemini-3-pro-preview';
15
18
  }
16
19
  /**
17
20
  * Chat completion with Gemini
@@ -53,10 +56,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
53
56
  },
54
57
  safetySettings: options.safetySettings,
55
58
  };
56
- const response = await fetch(`${this.baseUrl}/models/${model}:generateContent?key=${this.apiKey}`, {
59
+ const response = await fetch(`${this.baseUrl}/models/${model}:generateContent`, {
57
60
  method: 'POST',
58
61
  headers: {
59
62
  'Content-Type': 'application/json',
63
+ 'x-goog-api-key': this.apiKey,
60
64
  },
61
65
  body: JSON.stringify(chatRequest),
62
66
  });
@@ -75,8 +79,7 @@ export class GeminiIntelligenceTool extends oLaneTool {
75
79
  };
76
80
  }
77
81
  return {
78
- success: true,
79
- response: result.candidates[0].content.parts[0]?.text || '',
82
+ message: result.candidates[0].content.parts[0]?.text || '',
80
83
  model: model,
81
84
  usage: result.usageMetadata,
82
85
  finish_reason: result.candidates[0].finishReason,
@@ -127,10 +130,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
127
130
  },
128
131
  safetySettings: options.safetySettings,
129
132
  };
130
- const response = await fetch(`${this.baseUrl}/models/${model}:streamGenerateContent?key=${this.apiKey}&alt=sse`, {
133
+ const response = await fetch(`${this.baseUrl}/models/${model}:streamGenerateContent?alt=sse`, {
131
134
  method: 'POST',
132
135
  headers: {
133
136
  'Content-Type': 'application/json',
137
+ 'x-goog-api-key': this.apiKey,
134
138
  },
135
139
  body: JSON.stringify(chatRequest),
136
140
  });
@@ -241,10 +245,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
241
245
  },
242
246
  safetySettings: options.safetySettings,
243
247
  };
244
- const response = await fetch(`${this.baseUrl}/models/${model}:generateContent?key=${this.apiKey}`, {
248
+ const response = await fetch(`${this.baseUrl}/models/${model}:generateContent`, {
245
249
  method: 'POST',
246
250
  headers: {
247
251
  'Content-Type': 'application/json',
252
+ 'x-goog-api-key': this.apiKey,
248
253
  },
249
254
  body: JSON.stringify(generateRequest),
250
255
  });
@@ -263,8 +268,7 @@ export class GeminiIntelligenceTool extends oLaneTool {
263
268
  };
264
269
  }
265
270
  return {
266
- success: true,
267
- response: result.candidates[0].content.parts[0]?.text || '',
271
+ message: result.candidates[0].content.parts[0]?.text || '',
268
272
  model: model,
269
273
  usage: result.usageMetadata,
270
274
  finish_reason: result.candidates[0].finishReason,
@@ -316,10 +320,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
316
320
  },
317
321
  safetySettings: options.safetySettings,
318
322
  };
319
- const response = await fetch(`${this.baseUrl}/models/${model}:streamGenerateContent?key=${this.apiKey}&alt=sse`, {
323
+ const response = await fetch(`${this.baseUrl}/models/${model}:streamGenerateContent?alt=sse`, {
320
324
  method: 'POST',
321
325
  headers: {
322
326
  'Content-Type': 'application/json',
327
+ 'x-goog-api-key': this.apiKey,
323
328
  },
324
329
  body: JSON.stringify(generateRequest),
325
330
  });
@@ -400,10 +405,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
400
405
  error: 'Gemini API key is required',
401
406
  };
402
407
  }
403
- const response = await fetch(`${this.baseUrl}/models?key=${this.apiKey}`, {
408
+ const response = await fetch(`${this.baseUrl}/models`, {
404
409
  method: 'GET',
405
410
  headers: {
406
411
  'Content-Type': 'application/json',
412
+ 'x-goog-api-key': this.apiKey,
407
413
  },
408
414
  });
409
415
  if (!response.ok) {
@@ -439,10 +445,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
439
445
  error: 'Gemini API key is required',
440
446
  };
441
447
  }
442
- const response = await fetch(`${this.baseUrl}/models/${model}?key=${this.apiKey}`, {
448
+ const response = await fetch(`${this.baseUrl}/models/${model}`, {
443
449
  method: 'GET',
444
450
  headers: {
445
451
  'Content-Type': 'application/json',
452
+ 'x-goog-api-key': this.apiKey,
446
453
  },
447
454
  });
448
455
  if (!response.ok) {
@@ -477,10 +484,11 @@ export class GeminiIntelligenceTool extends oLaneTool {
477
484
  error: 'Gemini API key is required',
478
485
  };
479
486
  }
480
- const response = await fetch(`${this.baseUrl}/models?key=${this.apiKey}`, {
487
+ const response = await fetch(`${this.baseUrl}/models`, {
481
488
  method: 'GET',
482
489
  headers: {
483
490
  'Content-Type': 'application/json',
491
+ 'x-goog-api-key': this.apiKey,
484
492
  },
485
493
  });
486
494
  return {
@@ -497,4 +505,264 @@ export class GeminiIntelligenceTool extends oLaneTool {
497
505
  };
498
506
  }
499
507
  }
508
+ /**
509
+ * Generate image from text prompt using Gemini nano-banana models
510
+ */
511
+ async _tool_generate_image(request) {
512
+ try {
513
+ const params = request.params;
514
+ const { model = 'gemini-2.5-flash-image', prompt, aspectRatio = '1:1', imageSize = '2K', negativePrompt, } = params;
515
+ if (!this.apiKey) {
516
+ return {
517
+ success: false,
518
+ error: 'Gemini API key is required',
519
+ };
520
+ }
521
+ if (!prompt) {
522
+ return {
523
+ success: false,
524
+ error: 'Prompt is required',
525
+ };
526
+ }
527
+ // Build the full prompt with negative prompt if provided
528
+ const fullPrompt = negativePrompt
529
+ ? `${prompt}\n\nAvoid: ${negativePrompt}`
530
+ : prompt;
531
+ const imageRequest = {
532
+ contents: [
533
+ {
534
+ parts: [{ text: fullPrompt }],
535
+ },
536
+ ],
537
+ generationConfig: {
538
+ responseModalities: ['TEXT', 'IMAGE'],
539
+ imageConfig: {
540
+ aspectRatio: aspectRatio,
541
+ imageSize: imageSize,
542
+ },
543
+ },
544
+ };
545
+ const response = await fetch(`${this.baseUrl}/models/${model}:generateContent`, {
546
+ method: 'POST',
547
+ headers: {
548
+ 'Content-Type': 'application/json',
549
+ 'x-goog-api-key': this.apiKey,
550
+ },
551
+ body: JSON.stringify(imageRequest),
552
+ });
553
+ if (!response.ok) {
554
+ const errorText = await response.text();
555
+ return {
556
+ success: false,
557
+ error: `Gemini API error: ${response.status} - ${errorText}`,
558
+ };
559
+ }
560
+ const result = (await response.json());
561
+ if (!result.candidates || result.candidates.length === 0) {
562
+ return {
563
+ success: false,
564
+ error: 'No response generated from Gemini',
565
+ };
566
+ }
567
+ // Extract image and text from response parts
568
+ const parts = result.candidates[0].content.parts;
569
+ let imageData;
570
+ let description;
571
+ for (const part of parts) {
572
+ if (part.inline_data) {
573
+ imageData = part.inline_data.data;
574
+ }
575
+ else if (part.text) {
576
+ description = part.text;
577
+ }
578
+ }
579
+ if (!imageData) {
580
+ return {
581
+ success: false,
582
+ error: 'No image data in response',
583
+ };
584
+ }
585
+ return {
586
+ success: true,
587
+ imageData,
588
+ description,
589
+ model,
590
+ aspectRatio,
591
+ imageSize,
592
+ usage: result.usageMetadata,
593
+ };
594
+ }
595
+ catch (error) {
596
+ return {
597
+ success: false,
598
+ error: `Failed to generate image: ${error.message}`,
599
+ };
600
+ }
601
+ }
602
+ /**
603
+ * Edit or transform an existing image using Gemini nano-banana models
604
+ */
605
+ async _tool_edit_image(request) {
606
+ try {
607
+ const params = request.params;
608
+ const { model = 'gemini-2.5-flash-image', prompt, image, aspectRatio, imageSize = '2K', } = params;
609
+ if (!this.apiKey) {
610
+ return {
611
+ success: false,
612
+ error: 'Gemini API key is required',
613
+ };
614
+ }
615
+ if (!prompt) {
616
+ return {
617
+ success: false,
618
+ error: 'Prompt is required',
619
+ };
620
+ }
621
+ if (!image) {
622
+ return {
623
+ success: false,
624
+ error: 'Image is required',
625
+ };
626
+ }
627
+ // Process image input (base64 or file path)
628
+ let imageBase64;
629
+ let mimeType = 'image/jpeg';
630
+ if (image.startsWith('data:')) {
631
+ // Extract base64 from data URL
632
+ const matches = image.match(/^data:([^;]+);base64,(.+)$/);
633
+ if (matches) {
634
+ mimeType = matches[1];
635
+ imageBase64 = matches[2];
636
+ }
637
+ else {
638
+ return {
639
+ success: false,
640
+ error: 'Invalid data URL format',
641
+ };
642
+ }
643
+ }
644
+ else if (image.startsWith('/') || image.includes(':\\')) {
645
+ // File path - convert to base64
646
+ const result = await this.encodeImageToBase64(image);
647
+ imageBase64 = result.data;
648
+ mimeType = result.mimeType;
649
+ }
650
+ else {
651
+ // Assume it's raw base64
652
+ imageBase64 = image;
653
+ // Try to detect mime type from base64 header
654
+ if (image.startsWith('/9j/')) {
655
+ mimeType = 'image/jpeg';
656
+ }
657
+ else if (image.startsWith('iVBORw0KGgo')) {
658
+ mimeType = 'image/png';
659
+ }
660
+ }
661
+ const imageRequest = {
662
+ contents: [
663
+ {
664
+ parts: [
665
+ { text: prompt },
666
+ {
667
+ inline_data: {
668
+ mime_type: mimeType,
669
+ data: imageBase64,
670
+ },
671
+ },
672
+ ],
673
+ },
674
+ ],
675
+ generationConfig: {
676
+ responseModalities: ['TEXT', 'IMAGE'],
677
+ imageConfig: {
678
+ aspectRatio: aspectRatio,
679
+ imageSize: imageSize,
680
+ },
681
+ },
682
+ };
683
+ const response = await fetch(`${this.baseUrl}/models/${model}:generateContent`, {
684
+ method: 'POST',
685
+ headers: {
686
+ 'Content-Type': 'application/json',
687
+ 'x-goog-api-key': this.apiKey,
688
+ },
689
+ body: JSON.stringify(imageRequest),
690
+ });
691
+ if (!response.ok) {
692
+ const errorText = await response.text();
693
+ return {
694
+ success: false,
695
+ error: `Gemini API error: ${response.status} - ${errorText}`,
696
+ };
697
+ }
698
+ const result = (await response.json());
699
+ if (!result.candidates || result.candidates.length === 0) {
700
+ return {
701
+ success: false,
702
+ error: 'No response generated from Gemini',
703
+ };
704
+ }
705
+ // Extract image and text from response parts
706
+ const parts = result.candidates[0].content.parts;
707
+ let outputImageData;
708
+ let description;
709
+ for (const part of parts) {
710
+ if (part.inline_data) {
711
+ outputImageData = part.inline_data.data;
712
+ }
713
+ else if (part.text) {
714
+ description = part.text;
715
+ }
716
+ }
717
+ if (!outputImageData) {
718
+ return {
719
+ success: false,
720
+ error: 'No image data in response',
721
+ };
722
+ }
723
+ return {
724
+ success: true,
725
+ imageData: outputImageData,
726
+ description,
727
+ model,
728
+ aspectRatio,
729
+ imageSize,
730
+ usage: result.usageMetadata,
731
+ };
732
+ }
733
+ catch (error) {
734
+ return {
735
+ success: false,
736
+ error: `Failed to edit image: ${error.message}`,
737
+ };
738
+ }
739
+ }
740
+ /**
741
+ * Helper method to encode image file to base64
742
+ */
743
+ async encodeImageToBase64(filePath) {
744
+ try {
745
+ const buffer = await readFile(filePath);
746
+ const base64 = buffer.toString('base64');
747
+ // Detect MIME type from file extension
748
+ let mimeType = 'image/jpeg';
749
+ const lowerPath = filePath.toLowerCase();
750
+ if (lowerPath.endsWith('.png')) {
751
+ mimeType = 'image/png';
752
+ }
753
+ else if (lowerPath.endsWith('.jpg') || lowerPath.endsWith('.jpeg')) {
754
+ mimeType = 'image/jpeg';
755
+ }
756
+ else if (lowerPath.endsWith('.gif')) {
757
+ mimeType = 'image/gif';
758
+ }
759
+ else if (lowerPath.endsWith('.webp')) {
760
+ mimeType = 'image/webp';
761
+ }
762
+ return { data: base64, mimeType };
763
+ }
764
+ catch (error) {
765
+ throw new Error(`Failed to read image file: ${error.message}`);
766
+ }
767
+ }
500
768
  }
@@ -5,4 +5,5 @@ export * from './gemini-intelligence.tool.js';
5
5
  export * from './grok-intelligence.tool.js';
6
6
  export * from './o-intelligence.tool.js';
7
7
  export * from './methods/intelligence.methods.js';
8
+ export * from './perplexity-intelligence.tool.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC"}
package/dist/src/index.js CHANGED
@@ -5,3 +5,4 @@ export * from './gemini-intelligence.tool.js';
5
5
  export * from './grok-intelligence.tool.js';
6
6
  export * from './o-intelligence.tool.js';
7
7
  export * from './methods/intelligence.methods.js';
8
+ export * from './perplexity-intelligence.tool.js';