@happyvertical/ai 0.74.8

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