@happyvertical/ai 0.79.0 → 0.80.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/AGENT.md +1 -1
  2. package/dist/chunks/anthropic-DA8sdt12.js +438 -0
  3. package/dist/chunks/anthropic-DA8sdt12.js.map +1 -0
  4. package/dist/chunks/bedrock-DDiYFUw0.js +699 -0
  5. package/dist/chunks/bedrock-DDiYFUw0.js.map +1 -0
  6. package/dist/chunks/bifrost-fM9FpW_w.js +198 -0
  7. package/dist/chunks/bifrost-fM9FpW_w.js.map +1 -0
  8. package/dist/chunks/claude-cli-CnJh5KQT.js +498 -0
  9. package/dist/chunks/claude-cli-CnJh5KQT.js.map +1 -0
  10. package/dist/chunks/gateway-admin-CiKvHst7.js +283 -0
  11. package/dist/chunks/gateway-admin-CiKvHst7.js.map +1 -0
  12. package/dist/chunks/gemini-Bu7Fke7c.js +593 -0
  13. package/dist/chunks/gemini-Bu7Fke7c.js.map +1 -0
  14. package/dist/chunks/huggingface-B07_6wHW.js +295 -0
  15. package/dist/chunks/huggingface-B07_6wHW.js.map +1 -0
  16. package/dist/chunks/litellm-D_Oo9OQ_.js +185 -0
  17. package/dist/chunks/litellm-D_Oo9OQ_.js.map +1 -0
  18. package/dist/chunks/ollama-D4ksOTO8.js +626 -0
  19. package/dist/chunks/ollama-D4ksOTO8.js.map +1 -0
  20. package/dist/chunks/openai--F38QHiJ.js +691 -0
  21. package/dist/chunks/openai--F38QHiJ.js.map +1 -0
  22. package/dist/chunks/qwen-tts-DRRbOrhA.js +333 -0
  23. package/dist/chunks/qwen-tts-DRRbOrhA.js.map +1 -0
  24. package/dist/chunks/rate-limit-BwyPGXFW.js +199 -0
  25. package/dist/chunks/rate-limit-BwyPGXFW.js.map +1 -0
  26. package/dist/chunks/safety-CEnoJS6X.js +260 -0
  27. package/dist/chunks/safety-CEnoJS6X.js.map +1 -0
  28. package/dist/chunks/types-FHs-KbGL.js +117 -0
  29. package/dist/chunks/types-FHs-KbGL.js.map +1 -0
  30. package/dist/chunks/usage-C1Y1Nlg4.js +35 -0
  31. package/dist/chunks/usage-C1Y1Nlg4.js.map +1 -0
  32. package/dist/cli/claude-context.js +17 -17
  33. package/dist/cli/claude-context.js.map +1 -1
  34. package/dist/index.js +717 -23
  35. package/dist/index.js.map +1 -1
  36. package/metadata.json +1 -1
  37. package/package.json +5 -5
  38. package/dist/chunks/anthropic-2z-82zgr.js +0 -530
  39. package/dist/chunks/anthropic-2z-82zgr.js.map +0 -1
  40. package/dist/chunks/bedrock-Dc2eVPUD.js +0 -920
  41. package/dist/chunks/bedrock-Dc2eVPUD.js.map +0 -1
  42. package/dist/chunks/bifrost-CEnCsciy.js +0 -258
  43. package/dist/chunks/bifrost-CEnCsciy.js.map +0 -1
  44. package/dist/chunks/claude-cli-X1ONjE8K.js +0 -603
  45. package/dist/chunks/claude-cli-X1ONjE8K.js.map +0 -1
  46. package/dist/chunks/gateway-admin-BUhBzXZb.js +0 -359
  47. package/dist/chunks/gateway-admin-BUhBzXZb.js.map +0 -1
  48. package/dist/chunks/gemini-CS56gY0D.js +0 -768
  49. package/dist/chunks/gemini-CS56gY0D.js.map +0 -1
  50. package/dist/chunks/huggingface-wQSfO5xA.js +0 -411
  51. package/dist/chunks/huggingface-wQSfO5xA.js.map +0 -1
  52. package/dist/chunks/index-DCXO0nZA.js +0 -1293
  53. package/dist/chunks/index-DCXO0nZA.js.map +0 -1
  54. package/dist/chunks/litellm-BMFTYbWc.js +0 -245
  55. package/dist/chunks/litellm-BMFTYbWc.js.map +0 -1
  56. package/dist/chunks/ollama-DsGDrA-c.js +0 -962
  57. package/dist/chunks/ollama-DsGDrA-c.js.map +0 -1
  58. package/dist/chunks/openai-CJEo69jb.js +0 -882
  59. package/dist/chunks/openai-CJEo69jb.js.map +0 -1
  60. package/dist/chunks/qwen-tts-BLYZ6d9s.js +0 -365
  61. package/dist/chunks/qwen-tts-BLYZ6d9s.js.map +0 -1
  62. package/dist/chunks/usage-DMWiJ2oB.js +0 -21
  63. package/dist/chunks/usage-DMWiJ2oB.js.map +0 -1
@@ -1,768 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { b as normalizeBaseAIOptions, A as AIError, n as normalizeChatOptions, p as prepareRequestControls, a as normalizeImageGenerationOptions, f as extractTextContent, d as AuthenticationError, R as RateLimitError, e as extractRetryAfterSeconds, M as ModelNotFoundError } from "./index-DCXO0nZA.js";
3
- import { e as emitUsage } from "./usage-DMWiJ2oB.js";
4
- class GeminiProvider {
5
- options;
6
- client;
7
- // GoogleGenAI instance from @google/genai
8
- constructor(options) {
9
- this.options = normalizeBaseAIOptions({
10
- defaultModel: "gemini-2.5-flash",
11
- ...options
12
- });
13
- this.initializeClientSync();
14
- }
15
- initializeClientSync() {
16
- try {
17
- import("@google/genai").then(({ GoogleGenAI }) => {
18
- this.client = new GoogleGenAI(this.buildClientConfig());
19
- }).catch(() => {
20
- });
21
- } catch (_error) {
22
- }
23
- }
24
- async ensureClient() {
25
- if (!this.client) {
26
- try {
27
- const { GoogleGenAI } = await import("@google/genai");
28
- this.client = new GoogleGenAI(this.buildClientConfig());
29
- } catch (_error) {
30
- throw new AIError(
31
- "Failed to initialize Gemini client. Make sure @google/genai is installed.",
32
- "INITIALIZATION_ERROR",
33
- "gemini"
34
- );
35
- }
36
- }
37
- }
38
- /**
39
- * Build the GoogleGenAI client configuration based on provided options.
40
- * Supports both Google AI Studio (apiKey only) and Vertex AI (projectId + location).
41
- */
42
- buildClientConfig() {
43
- if (this.options.projectId && this.options.location) {
44
- return {
45
- vertexai: true,
46
- project: this.options.projectId,
47
- location: this.options.location,
48
- apiKey: this.options.apiKey,
49
- // Optional for Vertex AI with ADC
50
- httpOptions: {
51
- timeout: this.options.timeout,
52
- retryOptions: { attempts: (this.options.maxRetries || 0) + 1 }
53
- }
54
- };
55
- }
56
- return {
57
- apiKey: this.options.apiKey,
58
- httpOptions: {
59
- timeout: this.options.timeout,
60
- retryOptions: { attempts: (this.options.maxRetries || 0) + 1 }
61
- }
62
- };
63
- }
64
- async chat(messages, options = {}) {
65
- const startTime = Date.now();
66
- let controls;
67
- try {
68
- await this.ensureClient();
69
- const model = options.model || this.options.defaultModel;
70
- options = normalizeChatOptions(this.options, options, "gemini", model);
71
- controls = prepareRequestControls(this.options, options);
72
- const requestConfig = {
73
- model,
74
- contents: this.messagesToGeminiFormat(messages),
75
- config: this.buildGenerateContentConfig(options, controls)
76
- };
77
- const result = await this.client.models.generateContent(requestConfig);
78
- let toolCalls;
79
- const firstCandidate = result.candidates?.[0];
80
- if (firstCandidate?.content?.parts) {
81
- const functionCalls = firstCandidate.content.parts.filter(
82
- (part) => part.functionCall
83
- );
84
- if (functionCalls.length > 0) {
85
- toolCalls = functionCalls.map((part) => ({
86
- id: `call_${crypto.randomUUID()}`,
87
- type: "function",
88
- function: {
89
- name: part.functionCall.name,
90
- arguments: JSON.stringify(part.functionCall.args || {})
91
- }
92
- }));
93
- }
94
- }
95
- let content = result.text || "";
96
- if (options.responseFormat?.type === "json_object") {
97
- content = this.stripMarkdownCodeBlock(content);
98
- }
99
- const usage = {
100
- promptTokens: result.usageMetadata?.promptTokenCount || 0,
101
- completionTokens: result.usageMetadata?.candidatesTokenCount || 0,
102
- totalTokens: result.usageMetadata?.totalTokenCount || 0
103
- };
104
- emitUsage(
105
- this.options,
106
- "gemini",
107
- "chat",
108
- model,
109
- usage,
110
- startTime,
111
- options.usageTags
112
- );
113
- return {
114
- content,
115
- model,
116
- finishReason: this.mapFinishReason(result),
117
- usage,
118
- toolCalls: toolCalls && toolCalls.length > 0 ? toolCalls : void 0
119
- };
120
- } catch (error) {
121
- if (controls?.didTimeout()) {
122
- throw new AIError(
123
- `AI request timed out after ${controls.timeout}ms`,
124
- "AI_TIMEOUT",
125
- "gemini",
126
- options.model
127
- );
128
- }
129
- if (options.signal?.aborted) {
130
- throw new AIError(
131
- "AI request aborted by caller",
132
- "AI_ABORTED",
133
- "gemini",
134
- options.model
135
- );
136
- }
137
- throw this.mapError(error);
138
- } finally {
139
- controls?.cleanup();
140
- }
141
- }
142
- async complete(prompt, options = {}) {
143
- return this.chat([{ role: "user", content: prompt }], {
144
- model: options.model,
145
- maxTokens: options.maxTokens,
146
- temperature: options.temperature,
147
- topP: options.topP,
148
- n: options.n,
149
- stop: options.stop,
150
- stream: options.stream,
151
- onProgress: options.onProgress,
152
- signal: options.signal,
153
- timeout: options.timeout,
154
- reasoning: options.reasoning,
155
- usageTags: options.usageTags
156
- });
157
- }
158
- /**
159
- * Simple message interface for single-turn interactions with optional history
160
- *
161
- * @param text - The message text to send
162
- * @param options - Configuration options including history, model, etc.
163
- * @returns Promise resolving to the response content string
164
- *
165
- * @example
166
- * ```typescript
167
- * // Simple usage
168
- * const response = await provider.message('Hello!');
169
- *
170
- * // With history
171
- * const response = await provider.message('What was my question?', {
172
- * history: [
173
- * { role: 'user', content: 'What is 2+2?' },
174
- * { role: 'assistant', content: '4' }
175
- * ]
176
- * });
177
- * ```
178
- */
179
- async message(text, options = {}) {
180
- const messages = [
181
- ...options.history || [],
182
- { role: options.role || "user", content: text }
183
- ];
184
- const response = await this.chat(messages, {
185
- model: options.model,
186
- maxTokens: options.maxTokens,
187
- temperature: options.temperature,
188
- topP: options.topP,
189
- stop: options.stop,
190
- stream: options.stream,
191
- frequencyPenalty: options.frequencyPenalty,
192
- presencePenalty: options.presencePenalty,
193
- responseFormat: options.responseFormat,
194
- seed: options.seed,
195
- tools: options.tools,
196
- toolChoice: options.toolChoice,
197
- onProgress: options.onProgress,
198
- signal: options.signal,
199
- timeout: options.timeout,
200
- reasoning: options.reasoning,
201
- usageTags: options.usageTags
202
- });
203
- return response.content;
204
- }
205
- /**
206
- * Generate embeddings for text using Gemini embedding models
207
- * @param text - Single text string or array of texts to embed
208
- * @param options - Optional configuration for embeddings
209
- * @returns Promise resolving to embeddings response
210
- *
211
- * @example
212
- * ```typescript
213
- * const embedding = await provider.embed('Hello world');
214
- * const embeddings = await provider.embed(['Text 1', 'Text 2']);
215
- * ```
216
- */
217
- async embed(text, options = {}) {
218
- const startTime = Date.now();
219
- try {
220
- await this.ensureClient();
221
- const model = options.model || "text-embedding-004";
222
- const input = Array.isArray(text) ? text : [text];
223
- const embeddings = [];
224
- let totalTokens = 0;
225
- for (const content of input) {
226
- const config = {};
227
- if (options.dimensions) {
228
- config.outputDimensionality = options.dimensions;
229
- }
230
- const result = await this.client.models.embedContent({
231
- model,
232
- contents: content,
233
- config: Object.keys(config).length > 0 ? config : void 0
234
- });
235
- if (result.embeddings?.[0]?.values) {
236
- embeddings.push(result.embeddings[0].values);
237
- }
238
- if (result.metadata?.tokenCount) {
239
- totalTokens += result.metadata.tokenCount;
240
- }
241
- }
242
- const usage = totalTokens > 0 ? {
243
- promptTokens: totalTokens,
244
- completionTokens: 0,
245
- totalTokens
246
- } : void 0;
247
- emitUsage(
248
- this.options,
249
- "gemini",
250
- "embed",
251
- model,
252
- usage,
253
- startTime,
254
- options.usageTags
255
- );
256
- return {
257
- embeddings,
258
- model,
259
- usage
260
- };
261
- } catch (error) {
262
- throw this.mapError(error);
263
- }
264
- }
265
- /**
266
- * Convert an image to Gemini inline format
267
- * @param image - Image as URL, base64 data URL, or Buffer
268
- * @returns Gemini inline data format
269
- * @private
270
- */
271
- async imageToGeminiFormat(image, signal) {
272
- let mimeType = "image/png";
273
- let base64Data;
274
- if (Buffer.isBuffer(image)) {
275
- base64Data = image.toString("base64");
276
- } else if (image.startsWith("data:")) {
277
- const match = image.match(/^data:([^;]+);base64,(.+)$/);
278
- if (match) {
279
- mimeType = match[1];
280
- base64Data = match[2];
281
- } else {
282
- throw new AIError(
283
- "Invalid base64 data URL format",
284
- "INVALID_INPUT",
285
- "gemini"
286
- );
287
- }
288
- } else {
289
- const response = await fetch(image, { signal });
290
- if (!response.ok) {
291
- throw new AIError(
292
- `Failed to fetch image: ${response.status} ${response.statusText}`,
293
- "IMAGE_FETCH_ERROR",
294
- "gemini"
295
- );
296
- }
297
- const arrayBuffer = await response.arrayBuffer();
298
- base64Data = Buffer.from(arrayBuffer).toString("base64");
299
- mimeType = response.headers.get("content-type") || "image/png";
300
- }
301
- return {
302
- inlineData: { mimeType, data: base64Data }
303
- };
304
- }
305
- /**
306
- * Generate a text description of an image
307
- * @param image - Image as URL, base64 data URL, or Buffer
308
- * @param prompt - Custom prompt for description (optional)
309
- * @param options - Optional configuration
310
- * @returns Promise resolving to the description string
311
- *
312
- * @example
313
- * ```typescript
314
- * const description = await provider.describeImage('https://example.com/image.jpg');
315
- * ```
316
- */
317
- async describeImage(image, prompt, options = {}) {
318
- let controls;
319
- try {
320
- await this.ensureClient();
321
- const defaultPrompt = "Describe this image for a search index. Include objects, mood, lighting, and any visible text.";
322
- const model = options.model || this.options.defaultModel || "gemini-2.5-flash";
323
- const normalized = normalizeChatOptions(
324
- this.options,
325
- { ...options, maxTokens: options.maxTokens ?? 500 },
326
- "gemini",
327
- model
328
- );
329
- controls = prepareRequestControls(this.options, normalized);
330
- const imageData = await this.imageToGeminiFormat(image, controls.signal);
331
- const response = await this.client.models.generateContent({
332
- model,
333
- contents: [{ text: prompt || defaultPrompt }, imageData],
334
- config: this.buildGenerateContentConfig(normalized, controls)
335
- });
336
- return response.text || "";
337
- } catch (error) {
338
- if (controls?.didTimeout()) {
339
- throw new AIError(
340
- `AI request timed out after ${controls.timeout}ms`,
341
- "AI_TIMEOUT",
342
- "gemini",
343
- options.model
344
- );
345
- }
346
- if (options.signal?.aborted) {
347
- throw new AIError(
348
- "AI request aborted by caller",
349
- "AI_ABORTED",
350
- "gemini",
351
- options.model
352
- );
353
- }
354
- throw this.mapError(error);
355
- } finally {
356
- controls?.cleanup();
357
- }
358
- }
359
- /**
360
- * Generate embeddings for an image using native multimodal embeddings
361
- * @param image - Image as URL, base64 data URL, or Buffer
362
- * @param options - Optional configuration for image embeddings
363
- * @returns Promise resolving to embeddings response
364
- *
365
- * @example
366
- * ```typescript
367
- * const embedding = await provider.embedImage('https://example.com/image.jpg');
368
- * ```
369
- */
370
- async embedImage(image, options = {}) {
371
- try {
372
- await this.ensureClient();
373
- const model = options.model || "multimodalembedding@001";
374
- const imageData = await this.imageToGeminiFormat(image);
375
- const config = {};
376
- if (options.dimensions) {
377
- config.outputDimensionality = options.dimensions;
378
- }
379
- const result = await this.client.models.embedContent({
380
- model,
381
- contents: [imageData],
382
- config: Object.keys(config).length > 0 ? config : void 0
383
- });
384
- return {
385
- embeddings: result.embeddings?.[0]?.values ? [result.embeddings[0].values] : [],
386
- model
387
- };
388
- } catch (error) {
389
- throw this.mapError(error);
390
- }
391
- }
392
- /**
393
- * Generate an image from a text prompt using Imagen 3
394
- * @param prompt - Text description of the image to generate
395
- * @param options - Optional configuration for image generation
396
- * @returns Promise resolving to generated image(s)
397
- *
398
- * @example
399
- * ```typescript
400
- * const result = await provider.generateImage('A sunset over mountains');
401
- * fs.writeFileSync('image.png', result.images[0].data);
402
- * ```
403
- */
404
- async generateImage(prompt, options = {}) {
405
- let controls;
406
- try {
407
- await this.ensureClient();
408
- const model = options.model || "imagen-3.0-generate-002";
409
- options = normalizeImageGenerationOptions(
410
- this.options,
411
- options,
412
- "gemini",
413
- model
414
- );
415
- controls = prepareRequestControls(this.options, options);
416
- const config = {
417
- numberOfImages: options.n,
418
- abortSignal: controls.signal,
419
- httpOptions: {
420
- timeout: controls.timeout,
421
- retryOptions: { attempts: (this.options.maxRetries || 0) + 1 }
422
- }
423
- };
424
- if (options.aspectRatio) {
425
- config.aspectRatio = options.aspectRatio;
426
- }
427
- const response = await this.client.models.generateImages({
428
- model,
429
- prompt,
430
- config
431
- });
432
- const images = (response.generatedImages || []).map((img) => {
433
- let data;
434
- const mimeType = "image/png";
435
- const imageBytes = img.image?.imageBytes;
436
- if (options.outputFormat === "base64") {
437
- data = typeof imageBytes === "string" ? imageBytes : Buffer.from(imageBytes).toString("base64");
438
- } else if (options.outputFormat === "url") {
439
- const b64 = typeof imageBytes === "string" ? imageBytes : Buffer.from(imageBytes).toString("base64");
440
- data = `data:${mimeType};base64,${b64}`;
441
- } else {
442
- data = typeof imageBytes === "string" ? Buffer.from(imageBytes, "base64") : Buffer.from(imageBytes);
443
- }
444
- return {
445
- data,
446
- mimeType
447
- };
448
- });
449
- return {
450
- images,
451
- model
452
- };
453
- } catch (error) {
454
- if (controls?.didTimeout()) {
455
- throw new AIError(
456
- `AI request timed out after ${controls.timeout}ms`,
457
- "AI_TIMEOUT",
458
- "gemini",
459
- options.model
460
- );
461
- }
462
- if (options.signal?.aborted) {
463
- throw new AIError(
464
- "AI request aborted by caller",
465
- "AI_ABORTED",
466
- "gemini",
467
- options.model
468
- );
469
- }
470
- throw this.mapError(error);
471
- } finally {
472
- controls?.cleanup();
473
- }
474
- }
475
- async *stream(messages, options = {}) {
476
- const startTime = Date.now();
477
- let controls;
478
- try {
479
- await this.ensureClient();
480
- const model = options.model || this.options.defaultModel;
481
- options = normalizeChatOptions(this.options, options, "gemini", model);
482
- controls = prepareRequestControls(this.options, options);
483
- const stream = await this.client.models.generateContentStream({
484
- model,
485
- contents: this.messagesToGeminiFormat(messages),
486
- config: this.buildGenerateContentConfig(options, controls)
487
- });
488
- let usage;
489
- for await (const chunk of stream) {
490
- if (chunk.usageMetadata) {
491
- usage = {
492
- promptTokens: chunk.usageMetadata.promptTokenCount || 0,
493
- completionTokens: chunk.usageMetadata.candidatesTokenCount || 0,
494
- totalTokens: chunk.usageMetadata.totalTokenCount || 0
495
- };
496
- }
497
- const text = chunk.text || "";
498
- if (!text) {
499
- continue;
500
- }
501
- if (options.onProgress) {
502
- options.onProgress(text);
503
- }
504
- yield text;
505
- }
506
- emitUsage(
507
- this.options,
508
- "gemini",
509
- "stream",
510
- model,
511
- usage,
512
- startTime,
513
- options.usageTags
514
- );
515
- } catch (error) {
516
- if (controls?.didTimeout()) {
517
- throw new AIError(
518
- `AI request timed out after ${controls.timeout}ms`,
519
- "AI_TIMEOUT",
520
- "gemini",
521
- options.model
522
- );
523
- }
524
- if (options.signal?.aborted) {
525
- throw new AIError(
526
- "AI request aborted by caller",
527
- "AI_ABORTED",
528
- "gemini",
529
- options.model
530
- );
531
- }
532
- throw this.mapError(error);
533
- } finally {
534
- controls?.cleanup();
535
- }
536
- }
537
- async countTokens(text) {
538
- try {
539
- await this.ensureClient();
540
- const model = this.options.defaultModel || "gemini-2.5-flash";
541
- const response = await this.client.models.countTokens({
542
- model,
543
- contents: text
544
- });
545
- return response.totalTokens || Math.ceil(text.length / 4);
546
- } catch (error) {
547
- throw this.mapError(error);
548
- }
549
- }
550
- async getModels() {
551
- return [
552
- {
553
- id: "gemini-3-flash-preview",
554
- name: "Gemini 3 Flash Preview",
555
- description: "Preview of Gemini 3 Flash model. Available on Vertex AI in us-central1 only.",
556
- contextLength: 1e6,
557
- capabilities: ["text", "chat", "vision", "functions"],
558
- supportsFunctions: true,
559
- supportsVision: true
560
- },
561
- {
562
- id: "gemini-2.0-flash-001",
563
- name: "Gemini 2.0 Flash",
564
- description: "Latest fast and efficient Gemini model with function calling",
565
- contextLength: 1e6,
566
- capabilities: ["text", "chat", "vision", "functions"],
567
- supportsFunctions: true,
568
- supportsVision: true
569
- },
570
- {
571
- id: "gemini-2.5-flash",
572
- name: "Gemini 2.5 Flash",
573
- description: "Experimental next-generation Gemini model",
574
- contextLength: 1e6,
575
- capabilities: ["text", "chat", "vision", "functions"],
576
- supportsFunctions: true,
577
- supportsVision: true
578
- },
579
- {
580
- id: "gemini-1.5-pro",
581
- name: "Gemini 1.5 Pro (Legacy)",
582
- description: "Previous generation model (may not be available)",
583
- contextLength: 2e6,
584
- capabilities: ["text", "chat", "vision", "functions"],
585
- supportsFunctions: true,
586
- supportsVision: true
587
- }
588
- ];
589
- }
590
- async getCapabilities() {
591
- return {
592
- chat: true,
593
- completion: true,
594
- embeddings: true,
595
- streaming: true,
596
- functions: true,
597
- vision: true,
598
- fineTuning: false,
599
- imageEmbeddings: true,
600
- imageGeneration: true,
601
- tts: false,
602
- voiceCloning: false,
603
- voiceDesign: false,
604
- maxContextLength: 2e6,
605
- supportedOperations: [
606
- "chat",
607
- "completion",
608
- "embedding",
609
- "streaming",
610
- "functions",
611
- "vision",
612
- "image_embedding",
613
- "image_generation"
614
- ]
615
- };
616
- }
617
- // ============================================================================
618
- // TTS Methods (Not supported - use Qwen3-TTS provider)
619
- // ============================================================================
620
- async synthesizeSpeech(_text, _options) {
621
- throw new AIError(
622
- "TTS is not supported by Gemini provider. Use Qwen3-TTS provider.",
623
- "NOT_IMPLEMENTED",
624
- "gemini"
625
- );
626
- }
627
- streamSpeech(_text, _options) {
628
- const error = new AIError(
629
- "TTS streaming is not supported by Gemini provider. Use Qwen3-TTS provider.",
630
- "NOT_IMPLEMENTED",
631
- "gemini"
632
- );
633
- return {
634
- [Symbol.asyncIterator]: () => ({
635
- next: () => Promise.reject(error)
636
- })
637
- };
638
- }
639
- async cloneVoice(_options) {
640
- throw new AIError(
641
- "Voice cloning is not supported by Gemini provider. Use Qwen3-TTS provider.",
642
- "NOT_IMPLEMENTED",
643
- "gemini"
644
- );
645
- }
646
- async designVoice(_options) {
647
- throw new AIError(
648
- "Voice design is not supported by Gemini provider. Use Qwen3-TTS provider.",
649
- "NOT_IMPLEMENTED",
650
- "gemini"
651
- );
652
- }
653
- async getVoices(_options) {
654
- throw new AIError(
655
- "Voice listing is not supported by Gemini provider. Use Qwen3-TTS provider.",
656
- "NOT_IMPLEMENTED",
657
- "gemini"
658
- );
659
- }
660
- mapToolChoice(toolChoice) {
661
- if (!toolChoice || toolChoice === "auto") {
662
- return { functionCallingConfig: { mode: "AUTO" } };
663
- }
664
- if (toolChoice === "none") {
665
- return { functionCallingConfig: { mode: "NONE" } };
666
- }
667
- if (typeof toolChoice === "object" && toolChoice.type === "function") {
668
- return {
669
- functionCallingConfig: {
670
- mode: "ANY",
671
- allowedFunctionNames: [toolChoice.function.name]
672
- }
673
- };
674
- }
675
- return { functionCallingConfig: { mode: "AUTO" } };
676
- }
677
- buildGenerateContentConfig(options, controls) {
678
- const config = {
679
- abortSignal: controls.signal,
680
- httpOptions: {
681
- timeout: controls.timeout,
682
- retryOptions: { attempts: (this.options.maxRetries || 0) + 1 }
683
- },
684
- maxOutputTokens: options.maxTokens,
685
- temperature: options.temperature,
686
- topP: options.topP,
687
- stopSequences: Array.isArray(options.stop) ? options.stop : options.stop ? [options.stop] : void 0,
688
- responseMimeType: options.responseFormat?.type === "json_object" ? "application/json" : void 0,
689
- frequencyPenalty: options.frequencyPenalty,
690
- presencePenalty: options.presencePenalty,
691
- seed: options.seed
692
- };
693
- if (options.tools && options.tools.length > 0) {
694
- config.tools = [
695
- {
696
- functionDeclarations: options.tools.map((tool) => ({
697
- name: tool.function.name,
698
- description: tool.function.description || "",
699
- parameters: tool.function.parameters || { type: "object" }
700
- }))
701
- }
702
- ];
703
- config.toolConfig = this.mapToolChoice(options.toolChoice);
704
- }
705
- const reasoning = options.reasoning;
706
- if (reasoning?.maxTokens !== void 0 && reasoning.maxTokens > 0) {
707
- config.thinkingConfig = {
708
- thinkingBudget: reasoning.maxTokens,
709
- includeThoughts: reasoning.includeThoughts
710
- };
711
- }
712
- return Object.fromEntries(
713
- Object.entries(config).filter(([, value]) => value !== void 0)
714
- );
715
- }
716
- mapFinishReason(response) {
717
- const firstCandidate = response.candidates?.[0];
718
- if (firstCandidate?.content?.parts) {
719
- const hasFunctionCall = firstCandidate.content.parts.some(
720
- (part) => part.functionCall
721
- );
722
- if (hasFunctionCall) {
723
- return "tool_calls";
724
- }
725
- }
726
- return "stop";
727
- }
728
- messagesToGeminiFormat(messages) {
729
- return messages.map((message) => {
730
- const textContent = extractTextContent(message.content);
731
- switch (message.role) {
732
- case "system":
733
- return `Instructions: ${textContent}`;
734
- case "user":
735
- return `Human: ${textContent}`;
736
- case "assistant":
737
- return `Assistant: ${textContent}`;
738
- default:
739
- return textContent;
740
- }
741
- }).join("\n\n");
742
- }
743
- stripMarkdownCodeBlock(text) {
744
- const codeBlockRegex = /^```(?:json|javascript|typescript)?\s*\n?([\s\S]*?)\n?```\s*$/;
745
- const match = text.match(codeBlockRegex);
746
- return match ? match[1].trim() : text.trim();
747
- }
748
- mapError(error) {
749
- if (error instanceof AIError) {
750
- return error;
751
- }
752
- const message = error instanceof Error ? error.message : "Unknown Gemini error occurred";
753
- if (message.includes("API_KEY_INVALID") || message.includes("401")) {
754
- return new AuthenticationError("gemini");
755
- }
756
- if (message.includes("QUOTA_EXCEEDED") || message.includes("429")) {
757
- return new RateLimitError("gemini", extractRetryAfterSeconds(error));
758
- }
759
- if (message.includes("MODEL_NOT_FOUND") || message.includes("404")) {
760
- return new ModelNotFoundError(message, "gemini");
761
- }
762
- return new AIError(message, "UNKNOWN_ERROR", "gemini");
763
- }
764
- }
765
- export {
766
- GeminiProvider
767
- };
768
- //# sourceMappingURL=gemini-CS56gY0D.js.map