@tanstack/ai-gemini 0.0.3 → 0.1.0

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 (41) hide show
  1. package/README.md +26 -0
  2. package/dist/esm/adapters/image.d.ts +83 -0
  3. package/dist/esm/adapters/image.js +60 -0
  4. package/dist/esm/adapters/image.js.map +1 -0
  5. package/dist/esm/adapters/summarize.d.ts +53 -0
  6. package/dist/esm/adapters/summarize.js +139 -0
  7. package/dist/esm/adapters/summarize.js.map +1 -0
  8. package/dist/esm/adapters/text.d.ts +63 -0
  9. package/dist/esm/{gemini-adapter.js → adapters/text.js} +86 -132
  10. package/dist/esm/adapters/text.js.map +1 -0
  11. package/dist/esm/adapters/tts.d.ts +129 -0
  12. package/dist/esm/adapters/tts.js +78 -0
  13. package/dist/esm/adapters/tts.js.map +1 -0
  14. package/dist/esm/image/image-provider-options.d.ts +139 -0
  15. package/dist/esm/image/image-provider-options.js +53 -0
  16. package/dist/esm/image/image-provider-options.js.map +1 -0
  17. package/dist/esm/index.d.ts +15 -2
  18. package/dist/esm/index.js +22 -4
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/model-meta.d.ts +128 -1
  21. package/dist/esm/model-meta.js +71 -5
  22. package/dist/esm/model-meta.js.map +1 -1
  23. package/dist/esm/tools/tool-converter.js +5 -3
  24. package/dist/esm/tools/tool-converter.js.map +1 -1
  25. package/dist/esm/utils/client.d.ts +17 -0
  26. package/dist/esm/utils/client.js +25 -0
  27. package/dist/esm/utils/client.js.map +1 -0
  28. package/dist/esm/utils/index.d.ts +1 -0
  29. package/package.json +5 -4
  30. package/src/adapters/image.ts +188 -0
  31. package/src/adapters/summarize.ts +242 -0
  32. package/src/{gemini-adapter.ts → adapters/text.ts} +196 -245
  33. package/src/adapters/tts.ts +223 -0
  34. package/src/image/image-provider-options.ts +239 -0
  35. package/src/index.ts +66 -2
  36. package/src/model-meta.ts +87 -62
  37. package/src/tools/tool-converter.ts +6 -5
  38. package/src/utils/client.ts +43 -0
  39. package/src/utils/index.ts +6 -0
  40. package/dist/esm/gemini-adapter.d.ts +0 -71
  41. package/dist/esm/gemini-adapter.js.map +0 -1
package/src/model-meta.ts CHANGED
@@ -121,7 +121,7 @@ const GEMINI_2_5_PRO = {
121
121
  GeminiThinkingOptions
122
122
  >
123
123
 
124
- /* const GEMINI_2_5_PRO_TTS = {
124
+ const GEMINI_2_5_PRO_TTS = {
125
125
  name: 'gemini-2.5-pro-preview-tts',
126
126
  max_input_tokens: 8_192,
127
127
  max_output_tokens: 16_384,
@@ -141,10 +141,10 @@ const GEMINI_2_5_PRO = {
141
141
  },
142
142
  } as const satisfies ModelMeta<
143
143
  GeminiToolConfigOptions &
144
- GeminiSafetyOptions &
145
- GeminiGenerationConfigOptions &
146
- GeminiCachedContentOptions
147
- > */
144
+ GeminiSafetyOptions &
145
+ GeminiGenerationConfigOptions &
146
+ GeminiCachedContentOptions
147
+ >
148
148
 
149
149
  const GEMINI_2_5_FLASH = {
150
150
  name: 'gemini-2.5-flash',
@@ -220,7 +220,7 @@ const GEMINI_2_5_FLASH_PREVIEW = {
220
220
  GeminiStructuredOutputOptions &
221
221
  GeminiThinkingOptions
222
222
  >
223
- /*
223
+
224
224
  const GEMINI_2_5_FLASH_IMAGE = {
225
225
  name: 'gemini-2.5-flash-image',
226
226
  max_input_tokens: 1_048_576,
@@ -247,11 +247,11 @@ const GEMINI_2_5_FLASH_IMAGE = {
247
247
  },
248
248
  } as const satisfies ModelMeta<
249
249
  GeminiToolConfigOptions &
250
- GeminiSafetyOptions &
251
- GeminiGenerationConfigOptions &
252
- GeminiCachedContentOptions
250
+ GeminiSafetyOptions &
251
+ GeminiGenerationConfigOptions &
252
+ GeminiCachedContentOptions
253
253
  >
254
-
254
+ /**
255
255
  const GEMINI_2_5_FLASH_LIVE = {
256
256
  name: 'gemini-2.5-flash-native-audio-preview-09-2025',
257
257
  max_input_tokens: 141_072,
@@ -285,7 +285,7 @@ const GEMINI_2_5_FLASH_LIVE = {
285
285
  GeminiCachedContentOptions &
286
286
  GeminiThinkingOptions
287
287
  >
288
-
288
+ */
289
289
  const GEMINI_2_5_FLASH_TTS = {
290
290
  name: 'gemini-2.5-flash-preview-tts',
291
291
  max_input_tokens: 8_192,
@@ -306,10 +306,10 @@ const GEMINI_2_5_FLASH_TTS = {
306
306
  },
307
307
  } as const satisfies ModelMeta<
308
308
  GeminiToolConfigOptions &
309
- GeminiSafetyOptions &
310
- GeminiGenerationConfigOptions &
311
- GeminiCachedContentOptions
312
- > */
309
+ GeminiSafetyOptions &
310
+ GeminiGenerationConfigOptions &
311
+ GeminiCachedContentOptions
312
+ >
313
313
 
314
314
  const GEMINI_2_5_FLASH_LITE = {
315
315
  name: 'gemini-2.5-flash-lite',
@@ -418,7 +418,7 @@ const GEMINI_2_FLASH = {
418
418
  GeminiCachedContentOptions &
419
419
  GeminiStructuredOutputOptions
420
420
  >
421
- /*
421
+
422
422
  const GEMINI_2_FLASH_IMAGE = {
423
423
  name: 'gemini-2.0-flash-preview-image-generation',
424
424
  max_input_tokens: 32_768,
@@ -444,10 +444,10 @@ const GEMINI_2_FLASH_IMAGE = {
444
444
  },
445
445
  } as const satisfies ModelMeta<
446
446
  GeminiToolConfigOptions &
447
- GeminiSafetyOptions &
448
- GeminiGenerationConfigOptions &
449
- GeminiCachedContentOptions
450
- > */
447
+ GeminiSafetyOptions &
448
+ GeminiGenerationConfigOptions &
449
+ GeminiCachedContentOptions
450
+ >
451
451
  /*
452
452
  const GEMINI_2_FLASH_LIVE = {
453
453
  name: 'gemini-2.0-flash-live-001',
@@ -514,7 +514,7 @@ const GEMINI_2_FLASH_LITE = {
514
514
  GeminiStructuredOutputOptions
515
515
  >
516
516
 
517
- /* const IMAGEN_4_GENERATE = {
517
+ const IMAGEN_4_GENERATE = {
518
518
  name: 'imagen-4.0-generate-001',
519
519
  max_input_tokens: 480,
520
520
  max_output_tokens: 4,
@@ -532,9 +532,9 @@ const GEMINI_2_FLASH_LITE = {
532
532
  },
533
533
  } as const satisfies ModelMeta<
534
534
  GeminiToolConfigOptions &
535
- GeminiSafetyOptions &
536
- GeminiGenerationConfigOptions &
537
- GeminiCachedContentOptions
535
+ GeminiSafetyOptions &
536
+ GeminiGenerationConfigOptions &
537
+ GeminiCachedContentOptions
538
538
  >
539
539
 
540
540
  const IMAGEN_4_GENERATE_ULTRA = {
@@ -555,9 +555,9 @@ const IMAGEN_4_GENERATE_ULTRA = {
555
555
  },
556
556
  } as const satisfies ModelMeta<
557
557
  GeminiToolConfigOptions &
558
- GeminiSafetyOptions &
559
- GeminiGenerationConfigOptions &
560
- GeminiCachedContentOptions
558
+ GeminiSafetyOptions &
559
+ GeminiGenerationConfigOptions &
560
+ GeminiCachedContentOptions
561
561
  >
562
562
 
563
563
  const IMAGEN_4_GENERATE_FAST = {
@@ -578,9 +578,9 @@ const IMAGEN_4_GENERATE_FAST = {
578
578
  },
579
579
  } as const satisfies ModelMeta<
580
580
  GeminiToolConfigOptions &
581
- GeminiSafetyOptions &
582
- GeminiGenerationConfigOptions &
583
- GeminiCachedContentOptions
581
+ GeminiSafetyOptions &
582
+ GeminiGenerationConfigOptions &
583
+ GeminiCachedContentOptions
584
584
  >
585
585
 
586
586
  const IMAGEN_3 = {
@@ -600,11 +600,11 @@ const IMAGEN_3 = {
600
600
  },
601
601
  } as const satisfies ModelMeta<
602
602
  GeminiToolConfigOptions &
603
- GeminiSafetyOptions &
604
- GeminiGenerationConfigOptions &
605
- GeminiCachedContentOptions
603
+ GeminiSafetyOptions &
604
+ GeminiGenerationConfigOptions &
605
+ GeminiCachedContentOptions
606
606
  >
607
-
607
+ /**
608
608
  const VEO_3_1_PREVIEW = {
609
609
  name: 'veo-3.1-generate-preview',
610
610
  max_input_tokens: 1024,
@@ -719,28 +719,6 @@ const VEO_2 = {
719
719
  GeminiCachedContentOptions
720
720
  > */
721
721
 
722
- const GEMINI_EMBEDDING = {
723
- name: 'gemini-embedding-001',
724
- max_input_tokens: 2048,
725
- supports: {
726
- input: ['text'],
727
- output: ['text'],
728
- },
729
- pricing: {
730
- input: {
731
- normal: 0,
732
- },
733
- output: {
734
- normal: 0.15,
735
- },
736
- },
737
- } as const satisfies ModelMeta<
738
- GeminiToolConfigOptions &
739
- GeminiSafetyOptions &
740
- GeminiGenerationConfigOptions &
741
- GeminiCachedContentOptions
742
- >
743
-
744
722
  /* const GEMINI_MODEL_META = {
745
723
  [GEMINI_3_PRO.name]: GEMINI_3_PRO,
746
724
  [GEMINI_2_5_PRO.name]: GEMINI_2_5_PRO,
@@ -765,7 +743,6 @@ const GEMINI_EMBEDDING = {
765
743
  [VEO_3.name]: VEO_3,
766
744
  [VEO_3_FAST.name]: VEO_3_FAST,
767
745
  [VEO_2.name]: VEO_2,
768
- [GEMINI_EMBEDDING.name]: GEMINI_EMBEDDING,
769
746
  } as const */
770
747
 
771
748
  export const GEMINI_MODELS = [
@@ -779,16 +756,66 @@ export const GEMINI_MODELS = [
779
756
  GEMINI_2_FLASH_LITE.name,
780
757
  ] as const
781
758
 
782
- /* const GEMINI_IMAGE_MODELS = [
759
+ export type GeminiModels = (typeof GEMINI_MODELS)[number]
760
+
761
+ export type GeminiImageModels = (typeof GEMINI_IMAGE_MODELS)[number]
762
+
763
+ export const GEMINI_IMAGE_MODELS = [
783
764
  GEMINI_2_5_FLASH_IMAGE.name,
784
765
  GEMINI_2_FLASH_IMAGE.name,
785
766
  IMAGEN_3.name,
786
767
  IMAGEN_4_GENERATE.name,
787
768
  IMAGEN_4_GENERATE_FAST.name,
788
769
  IMAGEN_4_GENERATE_ULTRA.name,
789
- ] as const */
770
+ ] as const
771
+
772
+ /**
773
+ * Text-to-speech models
774
+ * @experimental Gemini TTS is an experimental feature and may change.
775
+ */
776
+ export const GEMINI_TTS_MODELS = [
777
+ GEMINI_2_5_FLASH_TTS.name,
778
+ GEMINI_2_5_PRO_TTS.name,
779
+ ] as const
780
+
781
+ /**
782
+ * Available voice names for Gemini TTS
783
+ * @see https://ai.google.dev/gemini-api/docs/speech-generation
784
+ */
785
+ export const GEMINI_TTS_VOICES = [
786
+ 'Zephyr',
787
+ 'Puck',
788
+ 'Charon',
789
+ 'Kore',
790
+ 'Fenrir',
791
+ 'Leda',
792
+ 'Orus',
793
+ 'Aoede',
794
+ 'Callirrhoe',
795
+ 'Autonoe',
796
+ 'Enceladus',
797
+ 'Iapetus',
798
+ 'Umbriel',
799
+ 'Algieba',
800
+ 'Despina',
801
+ 'Erinome',
802
+ 'Algenib',
803
+ 'Rasalgethi',
804
+ 'Laomedeia',
805
+ 'Achernar',
806
+ 'Alnilam',
807
+ 'Schedar',
808
+ 'Gacrux',
809
+ 'Pulcherrima',
810
+ 'Achird',
811
+ 'Zubenelgenubi',
812
+ 'Vindemiatrix',
813
+ 'Sadachbia',
814
+ 'Sadaltager',
815
+ 'Sulafat',
816
+ ] as const
790
817
 
791
- export const GEMINI_EMBEDDING_MODELS = [GEMINI_EMBEDDING.name] as const
818
+ export type GeminiTTSVoice = (typeof GEMINI_TTS_VOICES)[number]
792
819
 
793
820
  /* const GEMINI_AUDIO_MODELS = [
794
821
  GEMINI_2_5_PRO_TTS.name,
@@ -805,8 +832,6 @@ export const GEMINI_EMBEDDING_MODELS = [GEMINI_EMBEDDING.name] as const
805
832
  VEO_2.name,
806
833
  ] as const */
807
834
 
808
- // export type GeminiChatModels = (typeof GEMINI_MODELS)[number]
809
-
810
835
  // Manual type map for per-model provider options
811
836
  export type GeminiChatModelProviderOptionsByName = {
812
837
  // Models with thinking and structured output support
@@ -1,4 +1,3 @@
1
- import { convertZodToJsonSchema } from '@tanstack/ai'
2
1
  import { convertCodeExecutionToolToAdapterFormat } from './code-execution-tool'
3
2
  import { convertComputerUseToolToAdapterFormat } from './computer-use-tool'
4
3
  import { convertFileSearchToolToAdapterFormat } from './file-search-tool'
@@ -76,13 +75,15 @@ export function convertToolsToProviderFormat<TTool extends Tool>(
76
75
  )
77
76
  }
78
77
 
79
- // Convert Zod schema to JSON Schema
80
- const jsonSchema = convertZodToJsonSchema(tool.inputSchema)
81
-
78
+ // Tool schemas are already converted to JSON Schema in the ai layer
82
79
  functionDeclarations.push({
83
80
  name: tool.name,
84
81
  description: tool.description,
85
- parameters: jsonSchema,
82
+ parameters: tool.inputSchema ?? {
83
+ type: 'object',
84
+ properties: {},
85
+ required: [],
86
+ },
86
87
  })
87
88
  break
88
89
  }
@@ -0,0 +1,43 @@
1
+ import { GoogleGenAI } from '@google/genai'
2
+
3
+ export interface GeminiClientConfig {
4
+ apiKey: string
5
+ }
6
+
7
+ /**
8
+ * Creates a Google Generative AI client instance
9
+ */
10
+ export function createGeminiClient(config: GeminiClientConfig): GoogleGenAI {
11
+ return new GoogleGenAI({
12
+ apiKey: config.apiKey,
13
+ })
14
+ }
15
+
16
+ /**
17
+ * Gets Google API key from environment variables
18
+ * @throws Error if GOOGLE_API_KEY or GEMINI_API_KEY is not found
19
+ */
20
+ export function getGeminiApiKeyFromEnv(): string {
21
+ const env =
22
+ typeof globalThis !== 'undefined' && (globalThis as any).window?.env
23
+ ? (globalThis as any).window.env
24
+ : typeof process !== 'undefined'
25
+ ? process.env
26
+ : undefined
27
+ const key = env?.GOOGLE_API_KEY || env?.GEMINI_API_KEY
28
+
29
+ if (!key) {
30
+ throw new Error(
31
+ 'GOOGLE_API_KEY or GEMINI_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key.',
32
+ )
33
+ }
34
+
35
+ return key
36
+ }
37
+
38
+ /**
39
+ * Generates a unique ID with a prefix
40
+ */
41
+ export function generateId(prefix: string): string {
42
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`
43
+ }
@@ -0,0 +1,6 @@
1
+ export {
2
+ createGeminiClient,
3
+ generateId,
4
+ getGeminiApiKeyFromEnv,
5
+ type GeminiClientConfig,
6
+ } from './client'
@@ -1,71 +0,0 @@
1
- import { BaseAdapter, AIAdapterConfig, ChatOptions, EmbeddingOptions, EmbeddingResult, StreamChunk, SummarizationOptions, SummarizationResult } from '@tanstack/ai';
2
- import { GEMINI_EMBEDDING_MODELS, GEMINI_MODELS, GeminiChatModelProviderOptionsByName, GeminiModelInputModalitiesByName } from './model-meta.js';
3
- import { ExternalTextProviderOptions } from './text/text-provider-options.js';
4
- import { GeminiMessageMetadataByModality } from './message-types.js';
5
- export interface GeminiAdapterConfig extends AIAdapterConfig {
6
- apiKey: string;
7
- }
8
- /**
9
- * Gemini-specific provider options
10
- * Based on Google Generative AI SDK
11
- * @see https://ai.google.dev/api/rest/v1/GenerationConfig
12
- */
13
- export type GeminiProviderOptions = ExternalTextProviderOptions;
14
- export declare class GeminiAdapter extends BaseAdapter<typeof GEMINI_MODELS, typeof GEMINI_EMBEDDING_MODELS, GeminiProviderOptions, Record<string, any>, GeminiChatModelProviderOptionsByName, GeminiModelInputModalitiesByName, GeminiMessageMetadataByModality> {
15
- name: string;
16
- models: readonly ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-preview-09-2025", "gemini-2.5-flash-lite", "gemini-2.5-flash-lite-preview-09-2025", "gemini-2.0-flash", "gemini-2.0-flash-lite"];
17
- embeddingModels: readonly ["gemini-embedding-001"];
18
- _modelProviderOptionsByName: GeminiChatModelProviderOptionsByName;
19
- _modelInputModalitiesByName: GeminiModelInputModalitiesByName;
20
- _messageMetadataByModality: GeminiMessageMetadataByModality;
21
- private client;
22
- constructor(config: GeminiAdapterConfig);
23
- chatStream(options: ChatOptions<string, GeminiProviderOptions>): AsyncIterable<StreamChunk>;
24
- summarize(options: SummarizationOptions): Promise<SummarizationResult>;
25
- createEmbeddings(options: EmbeddingOptions): Promise<EmbeddingResult>;
26
- private buildSummarizationPrompt;
27
- private estimateTokens;
28
- private processStreamChunks;
29
- private convertContentPartToGemini;
30
- private formatMessages;
31
- /**
32
- * Maps common options to Gemini-specific format
33
- * Handles translation of normalized options to Gemini's API format
34
- */
35
- private mapCommonOptionsToGemini;
36
- }
37
- /**
38
- * Creates a Gemini adapter with simplified configuration
39
- * @param apiKey - Your Google API key
40
- * @returns A fully configured Gemini adapter instance
41
- *
42
- * @example
43
- * ```typescript
44
- * const gemini = createGemini("AIza...");
45
- *
46
- * const ai = new AI({
47
- * adapters: {
48
- * gemini,
49
- * }
50
- * });
51
- * ```
52
- */
53
- export declare function createGemini(apiKey: string, config?: Omit<GeminiAdapterConfig, 'apiKey'>): GeminiAdapter;
54
- /**
55
- * Create a Gemini adapter with automatic API key detection from environment variables.
56
- *
57
- * Looks for `GOOGLE_API_KEY` or `GEMINI_API_KEY` in:
58
- * - `process.env` (Node.js)
59
- * - `window.env` (Browser with injected env)
60
- *
61
- * @param config - Optional configuration (excluding apiKey which is auto-detected)
62
- * @returns Configured Gemini adapter instance
63
- * @throws Error if API key is not found in environment
64
- *
65
- * @example
66
- * ```typescript
67
- * // Automatically uses GOOGLE_API_KEY or GEMINI_API_KEY from environment
68
- * const aiInstance = ai(gemini());
69
- * ```
70
- */
71
- export declare function gemini(config?: Omit<GeminiAdapterConfig, 'apiKey'>): GeminiAdapter;
@@ -1 +0,0 @@
1
- {"version":3,"file":"gemini-adapter.js","sources":["../../src/gemini-adapter.ts"],"sourcesContent":["import { FinishReason, GoogleGenAI } from '@google/genai'\nimport { BaseAdapter } from '@tanstack/ai'\nimport { GEMINI_EMBEDDING_MODELS, GEMINI_MODELS } from './model-meta'\nimport { convertToolsToProviderFormat } from './tools/tool-converter'\nimport type {\n AIAdapterConfig,\n ChatOptions,\n ContentPart,\n EmbeddingOptions,\n EmbeddingResult,\n ModelMessage,\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n} from '@tanstack/ai'\nimport type {\n GeminiChatModelProviderOptionsByName,\n GeminiModelInputModalitiesByName,\n} from './model-meta'\nimport type { ExternalTextProviderOptions } from './text/text-provider-options'\nimport type {\n GenerateContentParameters,\n GenerateContentResponse,\n Part,\n} from '@google/genai'\nimport type {\n GeminiAudioMetadata,\n GeminiDocumentMetadata,\n GeminiImageMetadata,\n GeminiMessageMetadataByModality,\n GeminiVideoMetadata,\n} from './message-types'\n\nexport interface GeminiAdapterConfig extends AIAdapterConfig {\n apiKey: string\n}\n\n/**\n * Gemini-specific provider options\n * Based on Google Generative AI SDK\n * @see https://ai.google.dev/api/rest/v1/GenerationConfig\n */\nexport type GeminiProviderOptions = ExternalTextProviderOptions\n\nexport class GeminiAdapter extends BaseAdapter<\n typeof GEMINI_MODELS,\n typeof GEMINI_EMBEDDING_MODELS,\n GeminiProviderOptions,\n Record<string, any>,\n GeminiChatModelProviderOptionsByName,\n GeminiModelInputModalitiesByName,\n GeminiMessageMetadataByModality\n> {\n name = 'gemini'\n models = GEMINI_MODELS\n embeddingModels = GEMINI_EMBEDDING_MODELS\n declare _modelProviderOptionsByName: GeminiChatModelProviderOptionsByName\n declare _modelInputModalitiesByName: GeminiModelInputModalitiesByName\n declare _messageMetadataByModality: GeminiMessageMetadataByModality\n private client: GoogleGenAI\n\n constructor(config: GeminiAdapterConfig) {\n super(config)\n this.client = new GoogleGenAI({\n apiKey: config.apiKey,\n })\n }\n\n async *chatStream(\n options: ChatOptions<string, GeminiProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n // Map common options to Gemini format\n const mappedOptions = this.mapCommonOptionsToGemini(options)\n\n try {\n const result =\n await this.client.models.generateContentStream(mappedOptions)\n\n yield* this.processStreamChunks(result, options.model)\n } catch (error) {\n const timestamp = Date.now()\n yield {\n type: 'error',\n id: this.generateId(),\n model: options.model,\n timestamp,\n error: {\n message:\n error instanceof Error\n ? error.message\n : 'An unknown error occurred during the chat stream.',\n },\n }\n }\n }\n\n async summarize(options: SummarizationOptions): Promise<SummarizationResult> {\n const prompt = this.buildSummarizationPrompt(options, options.text)\n\n // Use models API like chatCompletion\n const result = await this.client.models.generateContent({\n model: options.model,\n contents: [{ role: 'user', parts: [{ text: prompt }] }],\n config: {\n temperature: 0.3,\n maxOutputTokens: options.maxLength || 500,\n },\n })\n\n // Extract text from candidates or use .text() method\n let summary = ''\n if (result.candidates?.[0]?.content?.parts) {\n const parts = result.candidates[0].content.parts\n for (const part of parts) {\n if (part.text) {\n summary += part.text\n }\n }\n }\n\n if (!summary && typeof result.text === 'string') {\n summary = result.text\n }\n\n const promptTokens = this.estimateTokens(prompt)\n const completionTokens = this.estimateTokens(summary)\n\n return {\n id: this.generateId(),\n model: options.model,\n summary,\n usage: {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n },\n }\n }\n\n async createEmbeddings(options: EmbeddingOptions): Promise<EmbeddingResult> {\n const inputs = Array.isArray(options.input)\n ? options.input\n : [options.input]\n\n // According to docs: contents can be a string or array of strings\n // Response has embeddings (plural) array with values property\n const result = await this.client.models.embedContent({\n model: options.model,\n contents: inputs,\n })\n\n // Extract embeddings from result.embeddings array\n const embeddings: Array<Array<number>> = []\n if (result.embeddings && Array.isArray(result.embeddings)) {\n for (const embedding of result.embeddings) {\n if (embedding.values && Array.isArray(embedding.values)) {\n embeddings.push(embedding.values)\n } else if (Array.isArray(embedding)) {\n embeddings.push(embedding)\n }\n }\n }\n\n const promptTokens = inputs.reduce(\n (sum, input) => sum + this.estimateTokens(input),\n 0,\n )\n\n return {\n id: this.generateId(),\n model: options.model || 'gemini-embedding-001',\n embeddings,\n usage: {\n promptTokens,\n totalTokens: promptTokens,\n },\n }\n }\n\n private buildSummarizationPrompt(\n options: SummarizationOptions,\n text: string,\n ): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n prompt += `\\n\\nText to summarize:\\n${text}\\n\\nSummary:`\n\n return prompt\n }\n\n private estimateTokens(text: string): number {\n // Rough approximation: 1 token ≈ 4 characters\n return Math.ceil(text.length / 4)\n }\n\n private async *processStreamChunks(\n result: AsyncGenerator<GenerateContentResponse, any, any>,\n model: string,\n ): AsyncIterable<StreamChunk> {\n const timestamp = Date.now()\n let accumulatedContent = ''\n const toolCallMap = new Map<\n string,\n { name: string; args: string; index: number }\n >()\n let nextToolIndex = 0\n // Iterate over the stream result (it's already an AsyncGenerator)\n for await (const chunk of result) {\n // Extract content from candidates[0].content.parts\n // Parts can contain text or functionCall\n if (chunk.candidates?.[0]?.content?.parts) {\n const parts = chunk.candidates[0].content.parts\n\n for (const part of parts) {\n // Handle text content\n if (part.text) {\n accumulatedContent += part.text\n yield {\n type: 'content',\n id: this.generateId(),\n model,\n timestamp,\n delta: part.text,\n content: accumulatedContent,\n role: 'assistant',\n }\n }\n\n // Handle function calls (tool calls)\n // Check both camelCase (SDK) and snake_case (direct API) formats\n const functionCall = part.functionCall\n if (functionCall) {\n const toolCallId =\n functionCall.name || `call_${Date.now()}_${nextToolIndex}`\n const functionArgs = functionCall.args || {}\n\n // Check if we've seen this tool call before (for streaming args)\n let toolCallData = toolCallMap.get(toolCallId)\n if (!toolCallData) {\n toolCallData = {\n name: functionCall.name || '',\n args:\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs),\n index: nextToolIndex++,\n }\n toolCallMap.set(toolCallId, toolCallData)\n } else {\n // Merge arguments if streaming\n\n try {\n const existingArgs = JSON.parse(toolCallData.args)\n const newArgs =\n typeof functionArgs === 'string'\n ? JSON.parse(functionArgs)\n : functionArgs\n const mergedArgs = { ...existingArgs, ...newArgs }\n toolCallData.args = JSON.stringify(mergedArgs)\n } catch {\n // If parsing fails, use new args\n toolCallData.args =\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs)\n }\n }\n\n yield {\n type: 'tool_call',\n id: this.generateId(),\n model,\n timestamp,\n toolCall: {\n id: toolCallId,\n type: 'function',\n function: {\n name: toolCallData.name,\n arguments: toolCallData.args,\n },\n },\n index: toolCallData.index,\n }\n }\n }\n } else if (chunk.data) {\n // Fallback to chunk.data if available\n accumulatedContent += chunk.data\n yield {\n type: 'content',\n id: this.generateId(),\n model,\n timestamp,\n delta: chunk.data,\n content: accumulatedContent,\n role: 'assistant',\n }\n }\n\n // Check for finish reason\n if (chunk.candidates?.[0]?.finishReason) {\n const finishReason = chunk.candidates[0].finishReason\n\n // UNEXPECTED_TOOL_CALL means Gemini tried to call a function but it wasn't properly declared\n // This typically means there's an issue with the tool declaration format\n // We should map it to tool_calls to try to process it anyway\n if (finishReason === FinishReason.UNEXPECTED_TOOL_CALL) {\n // Try to extract function call from content.parts if available\n if (chunk.candidates[0].content?.parts) {\n for (const part of chunk.candidates[0].content.parts) {\n const functionCall = part.functionCall\n if (functionCall) {\n // We found a function call - process it\n const toolCallId =\n functionCall.name || `call_${Date.now()}_${nextToolIndex}`\n const functionArgs = functionCall.args || {}\n\n toolCallMap.set(toolCallId, {\n name: functionCall.name || '',\n args:\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs),\n index: nextToolIndex++,\n })\n\n yield {\n type: 'tool_call',\n id: this.generateId(),\n model,\n timestamp,\n toolCall: {\n id: toolCallId,\n type: 'function',\n function: {\n name: functionCall.name || '',\n arguments:\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs),\n },\n },\n index: nextToolIndex - 1,\n }\n }\n }\n }\n }\n if (finishReason === FinishReason.MAX_TOKENS) {\n yield {\n type: 'error',\n id: this.generateId(),\n model,\n timestamp,\n error: {\n message:\n 'The response was cut off because the maximum token limit was reached.',\n },\n }\n }\n\n yield {\n type: 'done',\n id: this.generateId(),\n model,\n timestamp,\n finishReason: toolCallMap.size > 0 ? 'tool_calls' : 'stop',\n usage: chunk.usageMetadata\n ? {\n promptTokens: chunk.usageMetadata.promptTokenCount ?? 0,\n completionTokens: chunk.usageMetadata.thoughtsTokenCount ?? 0,\n totalTokens: chunk.usageMetadata.totalTokenCount ?? 0,\n }\n : undefined,\n }\n }\n }\n }\n\n private convertContentPartToGemini(part: ContentPart): Part {\n switch (part.type) {\n case 'text':\n return { text: part.content }\n case 'image':\n case 'audio':\n case 'video':\n case 'document': {\n const metadata = part.metadata as\n | GeminiDocumentMetadata\n | GeminiImageMetadata\n | GeminiVideoMetadata\n | GeminiAudioMetadata\n | undefined\n // Gemini uses inlineData for base64 and fileData for URLs\n if (part.source.type === 'data') {\n return {\n inlineData: {\n data: part.source.value,\n mimeType: metadata?.mimeType ?? 'image/jpeg',\n },\n }\n } else {\n return {\n fileData: {\n fileUri: part.source.value,\n mimeType: metadata?.mimeType ?? 'image/jpeg',\n },\n }\n }\n }\n default: {\n // Exhaustive check - this should never happen with known types\n const _exhaustiveCheck: never = part\n throw new Error(\n `Unsupported content part type: ${(_exhaustiveCheck as ContentPart).type}`,\n )\n }\n }\n }\n\n private formatMessages(\n messages: Array<ModelMessage>,\n ): GenerateContentParameters['contents'] {\n return messages.map((msg) => {\n const role: 'user' | 'model' = msg.role === 'assistant' ? 'model' : 'user'\n const parts: Array<Part> = []\n\n // Handle multimodal content (array of ContentPart)\n if (Array.isArray(msg.content)) {\n for (const contentPart of msg.content) {\n parts.push(this.convertContentPartToGemini(contentPart))\n }\n } else if (msg.content) {\n // Handle string content (backward compatibility)\n parts.push({ text: msg.content })\n }\n\n // Handle tool calls (from assistant)\n if (msg.role === 'assistant' && msg.toolCalls?.length) {\n for (const toolCall of msg.toolCalls) {\n let parsedArgs: Record<string, unknown> = {}\n try {\n parsedArgs = toolCall.function.arguments\n ? JSON.parse(toolCall.function.arguments)\n : {}\n } catch {\n parsedArgs = toolCall.function.arguments as any\n }\n\n parts.push({\n functionCall: {\n name: toolCall.function.name,\n args: parsedArgs,\n },\n })\n }\n }\n\n // Handle tool results (from tool role)\n if (msg.role === 'tool' && msg.toolCallId) {\n parts.push({\n functionResponse: {\n name: msg.toolCallId, // Gemini uses function name here\n response: {\n content: msg.content || '',\n },\n },\n })\n }\n\n return {\n role,\n parts: parts.length > 0 ? parts : [{ text: '' }],\n }\n })\n }\n /**\n * Maps common options to Gemini-specific format\n * Handles translation of normalized options to Gemini's API format\n */\n private mapCommonOptionsToGemini(options: ChatOptions) {\n const providerOpts = options.providerOptions\n const requestOptions: GenerateContentParameters = {\n model: options.model,\n contents: this.formatMessages(options.messages),\n config: {\n ...providerOpts,\n temperature: options.options?.temperature,\n topP: options.options?.topP,\n maxOutputTokens: options.options?.maxTokens,\n systemInstruction: options.systemPrompts?.join('\\n'),\n ...providerOpts?.generationConfig,\n tools: convertToolsToProviderFormat(options.tools),\n },\n }\n\n return requestOptions\n }\n}\n\n/**\n * Creates a Gemini adapter with simplified configuration\n * @param apiKey - Your Google API key\n * @returns A fully configured Gemini adapter instance\n *\n * @example\n * ```typescript\n * const gemini = createGemini(\"AIza...\");\n *\n * const ai = new AI({\n * adapters: {\n * gemini,\n * }\n * });\n * ```\n */\nexport function createGemini(\n apiKey: string,\n config?: Omit<GeminiAdapterConfig, 'apiKey'>,\n): GeminiAdapter {\n return new GeminiAdapter({ apiKey, ...config })\n}\n\n/**\n * Create a Gemini adapter with automatic API key detection from environment variables.\n *\n * Looks for `GOOGLE_API_KEY` or `GEMINI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Gemini adapter instance\n * @throws Error if API key is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses GOOGLE_API_KEY or GEMINI_API_KEY from environment\n * const aiInstance = ai(gemini());\n * ```\n */\nexport function gemini(\n config?: Omit<GeminiAdapterConfig, 'apiKey'>,\n): GeminiAdapter {\n const env =\n typeof globalThis !== 'undefined' && (globalThis as any).window?.env\n ? (globalThis as any).window.env\n : typeof process !== 'undefined'\n ? process.env\n : undefined\n const key = env?.GOOGLE_API_KEY || env?.GEMINI_API_KEY\n\n if (!key) {\n throw new Error(\n 'GOOGLE_API_KEY or GEMINI_API_KEY is required. Please set it in your environment variables or use createGemini(apiKey, config) instead.',\n )\n }\n\n return createGemini(key, config)\n}\n"],"names":[],"mappings":"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"}