@tanstack/ai-gemini 0.22.0 → 0.24.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.
@@ -65,7 +65,38 @@ var GEMINI_3_FLASH = {
65
65
  output: { normal: 3 }
66
66
  }
67
67
  };
68
+ /**
69
+ * Gemini 3 Pro Image ("Nano Banana Pro") — GA. Accepts the ten standard
70
+ * aspect ratios at 1K / 2K / 4K.
71
+ * @see https://ai.google.dev/gemini-api/docs/models/gemini-3-pro-image
72
+ */
68
73
  var GEMINI_3_PRO_IMAGE = {
74
+ name: "gemini-3-pro-image",
75
+ max_input_tokens: 65536,
76
+ max_output_tokens: 32768,
77
+ knowledge_cutoff: "2025-01-01",
78
+ supports: {
79
+ input: ["text", "image"],
80
+ output: ["text", "image"],
81
+ capabilities: [
82
+ "batch_api",
83
+ "structured_output",
84
+ "thinking"
85
+ ],
86
+ tools: ["google_search"]
87
+ },
88
+ pricing: {
89
+ input: { normal: 2 },
90
+ output: { normal: .134 }
91
+ }
92
+ };
93
+ /**
94
+ * @deprecated `gemini-3-pro-image-preview` was shut down on 2026-06-25. Use
95
+ * the GA id `gemini-3-pro-image` instead — the preview id now 404s.
96
+ * Kept in the model union so existing code still compiles.
97
+ * @see https://ai.google.dev/gemini-api/docs/deprecations
98
+ */
99
+ var GEMINI_3_PRO_IMAGE_PREVIEW = {
69
100
  name: "gemini-3-pro-image-preview",
70
101
  max_input_tokens: 65536,
71
102
  max_output_tokens: 32768,
@@ -85,7 +116,35 @@ var GEMINI_3_PRO_IMAGE = {
85
116
  output: { normal: .134 }
86
117
  }
87
118
  };
119
+ /**
120
+ * Gemini 3.1 Flash Image ("Nano Banana 2") — GA. The only native image model
121
+ * that accepts the four extreme banner ratios (1:4, 4:1, 1:8, 8:1) and the
122
+ * 512 (0.5K) resolution tier.
123
+ * @see https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image
124
+ */
88
125
  var GEMINI_3_1_FLASH_IMAGE = {
126
+ name: "gemini-3.1-flash-image",
127
+ max_input_tokens: 131072,
128
+ max_output_tokens: 32768,
129
+ knowledge_cutoff: "2025-01-01",
130
+ supports: {
131
+ input: ["text", "image"],
132
+ output: ["text", "image"],
133
+ capabilities: ["batch_api", "thinking"],
134
+ tools: ["google_search"]
135
+ },
136
+ pricing: {
137
+ input: { normal: .5 },
138
+ output: { normal: 3 }
139
+ }
140
+ };
141
+ /**
142
+ * @deprecated `gemini-3.1-flash-image-preview` was shut down on 2026-06-25.
143
+ * Use the GA id `gemini-3.1-flash-image` instead — the preview id now 404s.
144
+ * Kept in the model union so existing code still compiles.
145
+ * @see https://ai.google.dev/gemini-api/docs/deprecations
146
+ */
147
+ var GEMINI_3_1_FLASH_IMAGE_PREVIEW = {
89
148
  name: "gemini-3.1-flash-image-preview",
90
149
  max_input_tokens: 65536,
91
150
  max_output_tokens: 65536,
@@ -105,6 +164,10 @@ var GEMINI_3_1_FLASH_IMAGE = {
105
164
  output: { normal: 1.5 }
106
165
  }
107
166
  };
167
+ /**
168
+ * Gemini 3.1 Flash Lite Image ("Nano Banana 2 Lite") — GA. 1K output only.
169
+ * @see https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-lite-image
170
+ */
108
171
  var GEMINI_3_1_FLASH_LITE_IMAGE = {
109
172
  name: "gemini-3.1-flash-lite-image",
110
173
  max_input_tokens: 65536,
@@ -273,6 +336,17 @@ var GEMINI_2_5_FLASH = {
273
336
  output: { normal: 2.5 }
274
337
  }
275
338
  };
339
+ /**
340
+ * Gemini 2.5 Flash Image ("Nano Banana") — still GA, but documented as the
341
+ * legacy member of the family. Google publishes no `image_size` value for it,
342
+ * so its size type is a bare aspect ratio and the adapter sends no
343
+ * `imageConfig.imageSize`.
344
+ * @deprecated `gemini-2.5-flash-image` shuts down on 2026-10-02. Migrate to
345
+ * `gemini-3.1-flash-lite-image` (cheapest successor) or
346
+ * `gemini-3.1-flash-image`. Google's deprecations table still names the
347
+ * already-dead `gemini-3.1-flash-image-preview` as the replacement.
348
+ * @see https://ai.google.dev/gemini-api/docs/deprecations
349
+ */
276
350
  var GEMINI_2_5_FLASH_IMAGE = {
277
351
  name: "gemini-2.5-flash-image",
278
352
  max_input_tokens: 1048576,
@@ -540,6 +614,44 @@ var GEMINI_OMNI_FLASH_PREVIEW = {
540
614
  output: { normal: .1 }
541
615
  }
542
616
  };
617
+ var GEMINI_3_7_FLASH = {
618
+ name: "gemini-3.7-flash",
619
+ max_input_tokens: 1048576,
620
+ max_output_tokens: 65536,
621
+ knowledge_cutoff: "2026-03-01",
622
+ supports: {
623
+ input: [
624
+ "text",
625
+ "image",
626
+ "video",
627
+ "audio",
628
+ "document"
629
+ ],
630
+ output: ["text"],
631
+ capabilities: [
632
+ "batch_api",
633
+ "caching",
634
+ "function_calling",
635
+ "structured_output",
636
+ "thinking"
637
+ ],
638
+ tools: [
639
+ "code_execution",
640
+ "file_search",
641
+ "google_search",
642
+ "google_maps",
643
+ "url_context",
644
+ "computer_use"
645
+ ]
646
+ },
647
+ pricing: {
648
+ input: {
649
+ normal: .75,
650
+ cached: .075
651
+ },
652
+ output: { normal: 3.75 }
653
+ }
654
+ };
543
655
  var GEMINI_3_6_FLASH = {
544
656
  name: "gemini-3.6-flash",
545
657
  max_input_tokens: 1048576,
@@ -653,6 +765,7 @@ var GEMINI_3_5_FLASH_LITE = {
653
765
  }
654
766
  };
655
767
  var GEMINI_MODELS = [
768
+ GEMINI_3_7_FLASH.name,
656
769
  GEMINI_3_6_FLASH.name,
657
770
  GEMINI_3_5_FLASH.name,
658
771
  GEMINI_3_5_FLASH_LITE.name,
@@ -672,6 +785,7 @@ var GEMINI_MODELS = [
672
785
  * brittle and keeps the engine's legacy finalization fallback.
673
786
  */
674
787
  var GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS = /* @__PURE__ */ new Set([
788
+ GEMINI_3_7_FLASH.name,
675
789
  GEMINI_3_6_FLASH.name,
676
790
  GEMINI_3_5_FLASH.name,
677
791
  GEMINI_3_5_FLASH_LITE.name,
@@ -680,6 +794,11 @@ var GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS = /* @__PURE__ */ new Set([
680
794
  GEMINI_3_1_FLASH_LITE.name,
681
795
  GEMINI_3_1_FLASH_LITE_PREVIEW.name
682
796
  ]);
797
+ /**
798
+ * Image generation models. GA ids come first; the trailing `-preview` ids are
799
+ * shut-down aliases kept only so existing code keeps compiling — new code
800
+ * should use the GA id above its alias.
801
+ */
683
802
  var GEMINI_IMAGE_MODELS = [
684
803
  GEMINI_3_1_FLASH_IMAGE.name,
685
804
  GEMINI_3_1_FLASH_LITE_IMAGE.name,
@@ -687,7 +806,9 @@ var GEMINI_IMAGE_MODELS = [
687
806
  GEMINI_2_5_FLASH_IMAGE.name,
688
807
  IMAGEN_4_GENERATE.name,
689
808
  IMAGEN_4_GENERATE_FAST.name,
690
- IMAGEN_4_GENERATE_ULTRA.name
809
+ IMAGEN_4_GENERATE_ULTRA.name,
810
+ GEMINI_3_1_FLASH_IMAGE_PREVIEW.name,
811
+ GEMINI_3_PRO_IMAGE_PREVIEW.name
691
812
  ];
692
813
  /**
693
814
  * Text-to-speech models
@@ -1 +1 @@
1
- {"version":3,"file":"model-meta.js","names":[],"sources":["../../src/model-meta.ts"],"sourcesContent":["import type {\n GeminiCachedContentOptions,\n GeminiCommonConfigOptions,\n GeminiSafetyOptions,\n GeminiStructuredOutputOptions,\n GeminiThinkingOptions,\n GeminiToolConfigOptions,\n} from './text/text-provider-options'\nimport type { GeminiEmbeddingProviderOptions } from './embedding/embedding-provider-options'\n\ninterface ModelMeta<TProviderOptions = unknown> {\n name: string\n supports: {\n input: Array<'text' | 'image' | 'audio' | 'video' | 'document'>\n output: Array<'text' | 'image' | 'audio' | 'video'>\n capabilities?: Array<\n | 'audio_generation'\n | 'batch_api'\n | 'caching'\n | 'function_calling'\n | 'live_api'\n | 'structured_output'\n | 'thinking'\n >\n tools?: Array<\n | 'code_execution'\n | 'file_search'\n | 'google_search'\n | 'google_search_retrieval'\n | 'google_maps'\n | 'url_context'\n | 'computer_use'\n >\n }\n max_input_tokens?: number\n max_output_tokens?: number\n knowledge_cutoff?: string\n pricing?: {\n input: {\n normal: number\n cached?: number\n }\n output: {\n normal: number\n }\n }\n /**\n * Type-level description of which provider options this model supports.\n */\n providerOptions?: TProviderOptions\n}\n\nconst GEMINI_3_1_PRO = {\n name: 'gemini-3.1-pro-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 2.5,\n },\n output: {\n normal: 15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_FLASH = {\n name: 'gemini-3-flash-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.5,\n },\n output: {\n normal: 3,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_PRO_IMAGE = {\n name: 'gemini-3-pro-image-preview',\n max_input_tokens: 65_536,\n max_output_tokens: 32_768,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 2,\n },\n output: {\n normal: 0.134,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_1_FLASH_IMAGE = {\n name: 'gemini-3.1-flash-image-preview',\n max_input_tokens: 65_536,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_1_FLASH_LITE_IMAGE = {\n name: 'gemini-3.1-flash-lite-image',\n max_input_tokens: 65_536,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_1_FLASH_LITE = {\n name: 'gemini-3.1-flash-lite',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_1_FLASH_LITE_PREVIEW = {\n name: 'gemini-3.1-flash-lite-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_2_5_PRO = {\n name: 'gemini-2.5-pro',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_maps',\n 'google_search',\n 'url_context',\n ],\n },\n pricing: {\n input: {\n normal: 2.5,\n },\n output: {\n normal: 15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_2_5_PRO_TTS = {\n name: 'gemini-2.5-pro-preview-tts',\n max_input_tokens: 8_192,\n max_output_tokens: 16_384,\n knowledge_cutoff: '2025-05-01',\n supports: {\n input: ['text'],\n output: ['audio'],\n capabilities: ['audio_generation'],\n },\n pricing: {\n input: {\n normal: 2.5,\n },\n output: {\n normal: 15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst GEMINI_2_5_FLASH = {\n name: 'gemini-2.5-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_maps',\n 'google_search',\n 'url_context',\n ],\n },\n pricing: {\n input: {\n normal: 1,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_2_5_FLASH_IMAGE = {\n name: 'gemini-2.5-flash-image',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-06-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'caching', 'structured_output'],\n tools: ['file_search'],\n },\n pricing: {\n input: {\n normal: 0.3,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n/**\nconst GEMINI_2_5_FLASH_LIVE = {\n name: 'gemini-2.5-flash-native-audio-preview-09-2025',\n max_input_tokens: 141_072,\n max_output_tokens: 8_192,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'audio', 'video'],\n output: ['text', 'audio'],\n capabilities: [\n 'audio_generation',\n 'file_search',\n 'function_calling',\n 'live_api',\n 'search_grounding',\n 'thinking',\n ],\n },\n pricing: {\n // todo find this info\n input: {\n normal: 0,\n },\n output: {\n normal: 0,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiGenerationConfigOptions &\n GeminiCachedContentOptions &\n GeminiThinkingOptions\n>\n*/\nconst GEMINI_2_5_FLASH_TTS = {\n name: 'gemini-2.5-flash-preview-tts',\n max_input_tokens: 8_192,\n max_output_tokens: 16_384,\n knowledge_cutoff: '2025-05-01',\n supports: {\n input: ['text'],\n output: ['audio'],\n capabilities: ['audio_generation', 'batch_api'],\n },\n pricing: {\n input: {\n normal: 1,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Gemini 3.1 Flash TTS Preview - latest expressive TTS model with\n * 200+ audio tags, 70+ languages, and multi-speaker dialogue support.\n * @see https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-tts-preview\n */\nconst GEMINI_3_1_FLASH_TTS = {\n name: 'gemini-3.1-flash-tts-preview',\n max_input_tokens: 32_768,\n max_output_tokens: 16_384,\n knowledge_cutoff: '2025-05-01',\n supports: {\n input: ['text'],\n output: ['audio'],\n capabilities: ['audio_generation', 'batch_api'],\n },\n pricing: {\n input: {\n normal: 0.5,\n },\n output: {\n normal: 10,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Lyria 3 Pro Preview — Google's flagship music generation model.\n * Generates full-length songs with multiple verses, choruses, and bridges.\n * Outputs MP3 or WAV at 48 kHz stereo.\n * @see https://ai.google.dev/gemini-api/docs/models/lyria-3-pro-preview\n */\nconst LYRIA_3_PRO = {\n name: 'lyria-3-pro-preview',\n max_input_tokens: 131_072,\n supports: {\n input: ['text', 'image'],\n output: ['audio'],\n capabilities: ['audio_generation'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0,\n },\n },\n} as const satisfies ModelMeta\n\n/**\n * Lyria 3 Clip Preview — 30-second music clips in MP3 format.\n * @see https://ai.google.dev/gemini-api/docs/music-generation\n */\nconst LYRIA_3_CLIP = {\n name: 'lyria-3-clip-preview',\n max_input_tokens: 131_072,\n supports: {\n input: ['text', 'image'],\n output: ['audio'],\n capabilities: ['audio_generation'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0,\n },\n },\n} as const satisfies ModelMeta\n\nconst GEMINI_2_5_FLASH_LITE = {\n name: 'gemini-2.5-flash-lite',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'google_maps', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.1,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst IMAGEN_4_GENERATE = {\n name: 'imagen-4.0-generate-001',\n max_input_tokens: 480,\n max_output_tokens: 4,\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst IMAGEN_4_GENERATE_ULTRA = {\n name: 'imagen-4.0-ultra-generate-001',\n max_input_tokens: 480,\n max_output_tokens: 4,\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.6,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst IMAGEN_4_GENERATE_FAST = {\n name: 'imagen-4.0-fast-generate-001',\n max_input_tokens: 480,\n max_output_tokens: 4,\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.2,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Veo video generation models. Pricing is per second of generated video\n * (audio+video rate where the model supports audio).\n * @experimental Veo video generation is an experimental feature and may change.\n */\nconst VEO_3_1_PREVIEW = {\n name: 'veo-3.1-generate-preview',\n max_input_tokens: 1024,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst VEO_3_1_FAST_PREVIEW = {\n name: 'veo-3.1-fast-generate-preview',\n max_input_tokens: 1024,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst VEO_3_1_LITE_PREVIEW = {\n name: 'veo-3.1-lite-generate-preview',\n max_input_tokens: 1024,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.05,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Gemini Omni Flash — multimodal video generation with conversational\n * editing. Serves only the Interactions API (`generateContent` rejects it),\n * so it routes through the interactions-based path of the video adapter,\n * not Veo's `:predictLongRunning` flow. Pricing is per second of generated\n * video ($0.10/sec). 720p / 24 FPS, 3–10 second clips (default 10s).\n * @experimental Omni video generation is an experimental feature and may change.\n */\nconst GEMINI_OMNI_FLASH_PREVIEW = {\n name: 'gemini-omni-flash-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image', 'video'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.1,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst GEMINI_3_6_FLASH = {\n name: 'gemini-3.6-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2026-03-01',\n supports: {\n input: ['text', 'image', 'video', 'audio', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n 'computer_use',\n ],\n },\n pricing: {\n input: {\n normal: 1.5,\n cached: 0.15,\n },\n output: {\n normal: 7.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_5_FLASH = {\n name: 'gemini-3.5-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n supports: {\n input: ['text', 'image', 'video', 'document', 'audio'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n 'computer_use',\n ],\n },\n pricing: {\n input: {\n normal: 1.5,\n cached: 0.15,\n },\n output: {\n normal: 9,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_5_FLASH_LITE = {\n name: 'gemini-3.5-flash-lite',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'video', 'audio', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n ],\n },\n pricing: {\n input: {\n normal: 0.3,\n cached: 0.03,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nexport const GEMINI_MODELS = [\n GEMINI_3_6_FLASH.name,\n GEMINI_3_5_FLASH.name,\n GEMINI_3_5_FLASH_LITE.name,\n GEMINI_3_1_PRO.name,\n GEMINI_3_FLASH.name,\n GEMINI_3_1_FLASH_LITE.name,\n GEMINI_3_1_FLASH_LITE_PREVIEW.name,\n GEMINI_2_5_PRO.name,\n GEMINI_2_5_FLASH.name,\n GEMINI_2_5_FLASH_LITE.name,\n] as const\n\n/**\n * Gemini models that support combining `tools` + `responseSchema` in a\n * single streaming `generateContent` call (per issue #605). Per the\n * provider matrix, Gemini 3.x natively interleaves the schema-constrained\n * answer with function-calling on one pass; Gemini 2.x is unsupported /\n * brittle and keeps the engine's legacy finalization fallback.\n */\nexport const GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS = new Set<string>([\n GEMINI_3_6_FLASH.name,\n GEMINI_3_5_FLASH.name,\n GEMINI_3_5_FLASH_LITE.name,\n GEMINI_3_1_PRO.name,\n GEMINI_3_FLASH.name,\n GEMINI_3_1_FLASH_LITE.name,\n GEMINI_3_1_FLASH_LITE_PREVIEW.name,\n])\n\nexport type GeminiModels = (typeof GEMINI_MODELS)[number]\n\nexport type GeminiImageModels = (typeof GEMINI_IMAGE_MODELS)[number]\n\nexport const GEMINI_IMAGE_MODELS = [\n GEMINI_3_1_FLASH_IMAGE.name,\n GEMINI_3_1_FLASH_LITE_IMAGE.name,\n GEMINI_3_PRO_IMAGE.name,\n GEMINI_2_5_FLASH_IMAGE.name,\n IMAGEN_4_GENERATE.name,\n IMAGEN_4_GENERATE_FAST.name,\n IMAGEN_4_GENERATE_ULTRA.name,\n] as const\n\n/**\n * Text-to-speech models\n * @experimental Gemini TTS is an experimental feature and may change.\n */\nexport const GEMINI_TTS_MODELS = [\n GEMINI_3_1_FLASH_TTS.name,\n GEMINI_2_5_FLASH_TTS.name,\n GEMINI_2_5_PRO_TTS.name,\n] as const\n\n/**\n * Audio generation models (Lyria music generation).\n * @experimental Lyria music generation is an experimental feature and may change.\n */\nexport const GEMINI_AUDIO_MODELS = [\n LYRIA_3_PRO.name,\n LYRIA_3_CLIP.name,\n] as const\n\n/**\n * Available voice names for Gemini TTS\n * @see https://ai.google.dev/gemini-api/docs/speech-generation\n */\nexport const GEMINI_TTS_VOICES = [\n 'Zephyr',\n 'Puck',\n 'Charon',\n 'Kore',\n 'Fenrir',\n 'Leda',\n 'Orus',\n 'Aoede',\n 'Callirrhoe',\n 'Autonoe',\n 'Enceladus',\n 'Iapetus',\n 'Umbriel',\n 'Algieba',\n 'Despina',\n 'Erinome',\n 'Algenib',\n 'Rasalgethi',\n 'Laomedeia',\n 'Achernar',\n 'Alnilam',\n 'Schedar',\n 'Gacrux',\n 'Pulcherrima',\n 'Achird',\n 'Zubenelgenubi',\n 'Vindemiatrix',\n 'Sadachbia',\n 'Sadaltager',\n 'Sulafat',\n] as const\n\nexport type GeminiTTSVoice = (typeof GEMINI_TTS_VOICES)[number]\n\n/**\n * Video generation models. Veo models run on the long-running\n * `:predictLongRunning` flow; Gemini Omni Flash runs on the Interactions\n * API — the video adapter routes by model.\n * @experimental Video generation is an experimental feature and may change.\n */\nexport const GEMINI_VIDEO_MODELS = [\n VEO_3_1_PREVIEW.name,\n VEO_3_1_FAST_PREVIEW.name,\n VEO_3_1_LITE_PREVIEW.name,\n GEMINI_OMNI_FLASH_PREVIEW.name,\n] as const\n\n/**\n * Video models served by the Interactions API rather than Veo's\n * `:predictLongRunning` operations flow.\n * @experimental Omni video generation is an experimental feature and may change.\n */\nexport const GEMINI_INTERACTIONS_VIDEO_MODELS = [\n GEMINI_OMNI_FLASH_PREVIEW.name,\n] as const\n\n/**\n * Embedding models\n */\nexport const GEMINI_EMBEDDING_MODELS = ['gemini-embedding-001'] as const\n\nexport type GeminiEmbeddingModel = (typeof GEMINI_EMBEDDING_MODELS)[number]\n\n/**\n * Type-only map from embedding model name to its provider options type.\n */\nexport type GeminiEmbeddingModelProviderOptionsByName = {\n 'gemini-embedding-001': GeminiEmbeddingProviderOptions\n}\n\n/**\n * Per-model input modalities for embedding models. Gemini embedding models\n * are text-only, so image inputs fail at compile time.\n */\nexport type GeminiEmbeddingModelInputModalitiesByName = {\n 'gemini-embedding-001': readonly ['text']\n}\n\n// Manual type map for per-model provider options\nexport type GeminiChatModelProviderOptionsByName = {\n // Models with thinking and structured output support\n [GEMINI_3_6_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_5_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_5_FLASH_LITE.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_1_PRO.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_1_FLASH_LITE.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_2_5_PRO.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_2_5_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_2_5_FLASH_LITE.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n}\n\n/**\n * Type-only map from chat model name to its supported tool capabilities.\n * Based on the 'supports.tools' arrays defined for each model.\n */\nexport type GeminiChatModelToolCapabilitiesByName = {\n [GEMINI_3_6_FLASH.name]: typeof GEMINI_3_6_FLASH.supports.tools\n [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.tools\n [GEMINI_3_5_FLASH_LITE.name]: typeof GEMINI_3_5_FLASH_LITE.supports.tools\n [GEMINI_3_1_PRO.name]: typeof GEMINI_3_1_PRO.supports.tools\n [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.tools\n [GEMINI_3_1_FLASH_LITE.name]: typeof GEMINI_3_1_FLASH_LITE.supports.tools\n [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: typeof GEMINI_3_1_FLASH_LITE_PREVIEW.supports.tools\n [GEMINI_2_5_PRO.name]: typeof GEMINI_2_5_PRO.supports.tools\n [GEMINI_2_5_FLASH.name]: typeof GEMINI_2_5_FLASH.supports.tools\n [GEMINI_2_5_FLASH_LITE.name]: typeof GEMINI_2_5_FLASH_LITE.supports.tools\n}\n\n/**\n * Type-only map from chat model name to its supported input modalities.\n * Based on the 'supports.input' arrays defined for each model.\n * Note: 'document' in the model meta is mapped to 'document' modality.\n * Used by the core AI types to constrain ContentPart types based on the selected model.\n * Note: These must be inlined as readonly arrays (not typeof) because the model\n * constants are not exported and typeof references don't work in .d.ts files\n * when consumed by external packages.\n *\n * @see https://ai.google.dev/gemini-api/docs/vision\n * @see https://ai.google.dev/gemini-api/docs/audio\n * @see https://ai.google.dev/gemini-api/docs/document-processing\n */\nexport type GeminiModelInputModalitiesByName = {\n // Models with full multimodal support (text, image, audio, video, document)\n [GEMINI_3_6_FLASH.name]: typeof GEMINI_3_6_FLASH.supports.input\n [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.input\n [GEMINI_3_5_FLASH_LITE.name]: typeof GEMINI_3_5_FLASH_LITE.supports.input\n [GEMINI_3_1_PRO.name]: typeof GEMINI_3_1_PRO.supports.input\n [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.input\n [GEMINI_3_1_FLASH_LITE.name]: typeof GEMINI_3_1_FLASH_LITE.supports.input\n [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: typeof GEMINI_3_1_FLASH_LITE_PREVIEW.supports.input\n [GEMINI_2_5_PRO.name]: typeof GEMINI_2_5_PRO.supports.input\n [GEMINI_2_5_FLASH_LITE.name]: typeof GEMINI_2_5_FLASH_LITE.supports.input\n\n // Models with text, image, audio, video (no document)\n [GEMINI_2_5_FLASH.name]: typeof GEMINI_2_5_FLASH.supports.input\n}\n"],"mappings":";AAoDA,IAAM,iBAAiB;CACrB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GAAC;GAAkB;GAAe;GAAiB;EAAa;CACzE;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AASA,IAAM,iBAAiB;CACrB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GAAC;GAAkB;GAAe;GAAiB;EAAa;CACzE;CACA,SAAS;EACP,OAAO,EACL,QAAQ,GACV;EACA,QAAQ,EACN,QAAQ,EACV;CACF;AACF;AASA,IAAM,qBAAqB;CACzB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,QAAQ,OAAO;EACxB,cAAc;GAAC;GAAa;GAAqB;EAAU;EAC3D,OAAO,CAAC,eAAe;CACzB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,KACV;CACF;AACF;AASA,IAAM,yBAAyB;CAC7B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,QAAQ,OAAO;EACxB,cAAc;GAAC;GAAa;GAAqB;EAAU;EAC3D,OAAO,CAAC,eAAe;CACzB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAM,8BAA8B;CAClC,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,QAAQ,OAAO;EACxB,cAAc;GAAC;GAAa;GAAqB;EAAU;EAC3D,OAAO,CAAC,eAAe;CACzB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAM,wBAAwB;CAC5B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GAAC;GAAkB;GAAe;GAAiB;EAAa;CACzE;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAM,gCAAgC;CACpC,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GAAC;GAAkB;GAAe;GAAiB;EAAa;CACzE;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAM,iBAAiB;CACrB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;GACA;GACA;EACF;CACF;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AASA,IAAM,qBAAqB;CACzB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,MAAM;EACd,QAAQ,CAAC,OAAO;EAChB,cAAc,CAAC,kBAAkB;CACnC;CACA,SAAS;EACP,OAAO,EACL,QAAQ,IACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AAOA,IAAM,mBAAmB;CACvB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;EAAO;EACzC,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;GACA;GACA;EACF;CACF;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAM,yBAAyB;CAC7B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,QAAQ,OAAO;EACxB,cAAc;GAAC;GAAa;GAAW;EAAmB;EAC1D,OAAO,CAAC,aAAa;CACvB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,GACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAM,uBAAuB;CAC3B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,MAAM;EACd,QAAQ,CAAC,OAAO;EAChB,cAAc,CAAC,oBAAoB,WAAW;CAChD;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;;;;;;AAYA,IAAM,uBAAuB;CAC3B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,MAAM;EACd,QAAQ,CAAC,OAAO;EAChB,cAAc,CAAC,oBAAoB,WAAW;CAChD;CACA,SAAS;EACP,OAAO,EACL,QAAQ,GACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;;;;;;;AAaA,IAAM,cAAc;CAClB,MAAM;CACN,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,OAAO;EAChB,cAAc,CAAC,kBAAkB;CACnC;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,EACV;CACF;AACF;;;;;AAMA,IAAM,eAAe;CACnB,MAAM;CACN,kBAAkB;CAClB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,OAAO;EAChB,cAAc,CAAC,kBAAkB;CACnC;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,EACV;CACF;AACF;AAEA,IAAM,wBAAwB;CAC5B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GAAC;GAAkB;GAAe;GAAiB;EAAa;CACzE;CACA,SAAS;EACP,OAAO,EACL,QAAQ,GACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AASA,IAAM,oBAAoB;CACxB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO,CAAC,MAAM;EACd,QAAQ,CAAC,OAAO;CAClB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AAOA,IAAM,0BAA0B;CAC9B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO,CAAC,MAAM;EACd,QAAQ,CAAC,OAAO;CAClB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AAOA,IAAM,yBAAyB;CAC7B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO,CAAC,MAAM;EACd,QAAQ,CAAC,OAAO;CAClB;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;;;;;;AAYA,IAAM,kBAAkB;CACtB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,SAAS,OAAO;CAC3B;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AAOA,IAAM,uBAAuB;CAC3B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,SAAS,OAAO;CAC3B;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AAOA,IAAM,uBAAuB;CAC3B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO,CAAC,QAAQ,OAAO;EACvB,QAAQ,CAAC,SAAS,OAAO;CAC3B;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;;;;;;;;;AAeA,IAAM,4BAA4B;CAChC,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;EAAO;EAChC,QAAQ,CAAC,SAAS,OAAO;CAC3B;CACA,SAAS;EACP,OAAO,EACL,QAAQ,EACV;EACA,QAAQ,EACN,QAAQ,GACV;CACF;AACF;AAOA,IAAM,mBAAmB;CACvB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CACA,SAAS;EACP,OAAO;GACL,QAAQ;GACR,QAAQ;EACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAM,mBAAmB;CACvB,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAY;EAAO;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CACA,SAAS;EACP,OAAO;GACL,QAAQ;GACR,QAAQ;EACV;EACA,QAAQ,EACN,QAAQ,EACV;CACF;AACF;AASA,IAAM,wBAAwB;CAC5B,MAAM;CACN,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,UAAU;EACR,OAAO;GAAC;GAAQ;GAAS;GAAS;GAAS;EAAU;EACrD,QAAQ,CAAC,MAAM;EACf,cAAc;GACZ;GACA;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;GACA;GACA;EACF;CACF;CACA,SAAS;EACP,OAAO;GACL,QAAQ;GACR,QAAQ;EACV;EACA,QAAQ,EACN,QAAQ,IACV;CACF;AACF;AASA,IAAa,gBAAgB;CAC3B,iBAAiB;CACjB,iBAAiB;CACjB,sBAAsB;CACtB,eAAe;CACf,eAAe;CACf,sBAAsB;CACtB,8BAA8B;CAC9B,eAAe;CACf,iBAAiB;CACjB,sBAAsB;AACxB;;;;;;;;AASA,IAAa,0DAA0C,IAAI,IAAY;CACrE,iBAAiB;CACjB,iBAAiB;CACjB,sBAAsB;CACtB,eAAe;CACf,eAAe;CACf,sBAAsB;CACtB,8BAA8B;AAChC,CAAC;AAMD,IAAa,sBAAsB;CACjC,uBAAuB;CACvB,4BAA4B;CAC5B,mBAAmB;CACnB,uBAAuB;CACvB,kBAAkB;CAClB,uBAAuB;CACvB,wBAAwB;AAC1B;;;;;AAMA,IAAa,oBAAoB;CAC/B,qBAAqB;CACrB,qBAAqB;CACrB,mBAAmB;AACrB;;;;;AAMA,IAAa,sBAAsB,CACjC,YAAY,MACZ,aAAa,IACf;;;;;AAMA,IAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;AAUA,IAAa,sBAAsB;CACjC,gBAAgB;CAChB,qBAAqB;CACrB,qBAAqB;CACrB,0BAA0B;AAC5B;;;;;;AAOA,IAAa,mCAAmC,CAC9C,0BAA0B,IAC5B;;;;AAKA,IAAa,0BAA0B,CAAC,sBAAsB"}
1
+ {"version":3,"file":"model-meta.js","names":[],"sources":["../../src/model-meta.ts"],"sourcesContent":["import type {\n GeminiCachedContentOptions,\n GeminiCommonConfigOptions,\n GeminiSafetyOptions,\n GeminiStructuredOutputOptions,\n GeminiThinkingOptions,\n GeminiToolConfigOptions,\n} from './text/text-provider-options'\nimport type { GeminiEmbeddingProviderOptions } from './embedding/embedding-provider-options'\n\ninterface ModelMeta<TProviderOptions = unknown> {\n name: string\n supports: {\n input: Array<'text' | 'image' | 'audio' | 'video' | 'document'>\n output: Array<'text' | 'image' | 'audio' | 'video'>\n capabilities?: Array<\n | 'audio_generation'\n | 'batch_api'\n | 'caching'\n | 'function_calling'\n | 'live_api'\n | 'structured_output'\n | 'thinking'\n >\n tools?: Array<\n | 'code_execution'\n | 'file_search'\n | 'google_search'\n | 'google_search_retrieval'\n | 'google_maps'\n | 'url_context'\n | 'computer_use'\n >\n }\n max_input_tokens?: number\n max_output_tokens?: number\n knowledge_cutoff?: string\n pricing?: {\n input: {\n normal: number\n cached?: number\n }\n output: {\n normal: number\n }\n }\n /**\n * Type-level description of which provider options this model supports.\n */\n providerOptions?: TProviderOptions\n}\n\nconst GEMINI_3_1_PRO = {\n name: 'gemini-3.1-pro-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 2.5,\n },\n output: {\n normal: 15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_FLASH = {\n name: 'gemini-3-flash-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.5,\n },\n output: {\n normal: 3,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\n/**\n * Gemini 3 Pro Image (\"Nano Banana Pro\") — GA. Accepts the ten standard\n * aspect ratios at 1K / 2K / 4K.\n * @see https://ai.google.dev/gemini-api/docs/models/gemini-3-pro-image\n */\nconst GEMINI_3_PRO_IMAGE = {\n name: 'gemini-3-pro-image',\n max_input_tokens: 65_536,\n max_output_tokens: 32_768,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 2,\n },\n output: {\n normal: 0.134,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\n/**\n * @deprecated `gemini-3-pro-image-preview` was shut down on 2026-06-25. Use\n * the GA id `gemini-3-pro-image` instead — the preview id now 404s.\n * Kept in the model union so existing code still compiles.\n * @see https://ai.google.dev/gemini-api/docs/deprecations\n */\nconst GEMINI_3_PRO_IMAGE_PREVIEW = {\n name: 'gemini-3-pro-image-preview',\n max_input_tokens: 65_536,\n max_output_tokens: 32_768,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 2,\n },\n output: {\n normal: 0.134,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\n/**\n * Gemini 3.1 Flash Image (\"Nano Banana 2\") — GA. The only native image model\n * that accepts the four extreme banner ratios (1:4, 4:1, 1:8, 8:1) and the\n * 512 (0.5K) resolution tier.\n * @see https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image\n */\nconst GEMINI_3_1_FLASH_IMAGE = {\n name: 'gemini-3.1-flash-image',\n max_input_tokens: 131_072,\n max_output_tokens: 32_768,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 0.5,\n },\n output: {\n normal: 3,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiThinkingOptions\n>\n\n/**\n * @deprecated `gemini-3.1-flash-image-preview` was shut down on 2026-06-25.\n * Use the GA id `gemini-3.1-flash-image` instead — the preview id now 404s.\n * Kept in the model union so existing code still compiles.\n * @see https://ai.google.dev/gemini-api/docs/deprecations\n */\nconst GEMINI_3_1_FLASH_IMAGE_PREVIEW = {\n name: 'gemini-3.1-flash-image-preview',\n max_input_tokens: 65_536,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\n/**\n * Gemini 3.1 Flash Lite Image (\"Nano Banana 2 Lite\") — GA. 1K output only.\n * @see https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-lite-image\n */\nconst GEMINI_3_1_FLASH_LITE_IMAGE = {\n name: 'gemini-3.1-flash-lite-image',\n max_input_tokens: 65_536,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'structured_output', 'thinking'],\n tools: ['google_search'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_1_FLASH_LITE = {\n name: 'gemini-3.1-flash-lite',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_1_FLASH_LITE_PREVIEW = {\n name: 'gemini-3.1-flash-lite-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'file_search', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.25,\n },\n output: {\n normal: 1.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_2_5_PRO = {\n name: 'gemini-2.5-pro',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_maps',\n 'google_search',\n 'url_context',\n ],\n },\n pricing: {\n input: {\n normal: 2.5,\n },\n output: {\n normal: 15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_2_5_PRO_TTS = {\n name: 'gemini-2.5-pro-preview-tts',\n max_input_tokens: 8_192,\n max_output_tokens: 16_384,\n knowledge_cutoff: '2025-05-01',\n supports: {\n input: ['text'],\n output: ['audio'],\n capabilities: ['audio_generation'],\n },\n pricing: {\n input: {\n normal: 2.5,\n },\n output: {\n normal: 15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst GEMINI_2_5_FLASH = {\n name: 'gemini-2.5-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_maps',\n 'google_search',\n 'url_context',\n ],\n },\n pricing: {\n input: {\n normal: 1,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\n/**\n * Gemini 2.5 Flash Image (\"Nano Banana\") — still GA, but documented as the\n * legacy member of the family. Google publishes no `image_size` value for it,\n * so its size type is a bare aspect ratio and the adapter sends no\n * `imageConfig.imageSize`.\n * @deprecated `gemini-2.5-flash-image` shuts down on 2026-10-02. Migrate to\n * `gemini-3.1-flash-lite-image` (cheapest successor) or\n * `gemini-3.1-flash-image`. Google's deprecations table still names the\n * already-dead `gemini-3.1-flash-image-preview` as the replacement.\n * @see https://ai.google.dev/gemini-api/docs/deprecations\n */\nconst GEMINI_2_5_FLASH_IMAGE = {\n name: 'gemini-2.5-flash-image',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-06-01',\n supports: {\n input: ['text', 'image'],\n output: ['text', 'image'],\n capabilities: ['batch_api', 'caching', 'structured_output'],\n tools: ['file_search'],\n },\n pricing: {\n input: {\n normal: 0.3,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n/**\nconst GEMINI_2_5_FLASH_LIVE = {\n name: 'gemini-2.5-flash-native-audio-preview-09-2025',\n max_input_tokens: 141_072,\n max_output_tokens: 8_192,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'audio', 'video'],\n output: ['text', 'audio'],\n capabilities: [\n 'audio_generation',\n 'file_search',\n 'function_calling',\n 'live_api',\n 'search_grounding',\n 'thinking',\n ],\n },\n pricing: {\n // todo find this info\n input: {\n normal: 0,\n },\n output: {\n normal: 0,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiGenerationConfigOptions &\n GeminiCachedContentOptions &\n GeminiThinkingOptions\n>\n*/\nconst GEMINI_2_5_FLASH_TTS = {\n name: 'gemini-2.5-flash-preview-tts',\n max_input_tokens: 8_192,\n max_output_tokens: 16_384,\n knowledge_cutoff: '2025-05-01',\n supports: {\n input: ['text'],\n output: ['audio'],\n capabilities: ['audio_generation', 'batch_api'],\n },\n pricing: {\n input: {\n normal: 1,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Gemini 3.1 Flash TTS Preview - latest expressive TTS model with\n * 200+ audio tags, 70+ languages, and multi-speaker dialogue support.\n * @see https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-tts-preview\n */\nconst GEMINI_3_1_FLASH_TTS = {\n name: 'gemini-3.1-flash-tts-preview',\n max_input_tokens: 32_768,\n max_output_tokens: 16_384,\n knowledge_cutoff: '2025-05-01',\n supports: {\n input: ['text'],\n output: ['audio'],\n capabilities: ['audio_generation', 'batch_api'],\n },\n pricing: {\n input: {\n normal: 0.5,\n },\n output: {\n normal: 10,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Lyria 3 Pro Preview — Google's flagship music generation model.\n * Generates full-length songs with multiple verses, choruses, and bridges.\n * Outputs MP3 or WAV at 48 kHz stereo.\n * @see https://ai.google.dev/gemini-api/docs/models/lyria-3-pro-preview\n */\nconst LYRIA_3_PRO = {\n name: 'lyria-3-pro-preview',\n max_input_tokens: 131_072,\n supports: {\n input: ['text', 'image'],\n output: ['audio'],\n capabilities: ['audio_generation'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0,\n },\n },\n} as const satisfies ModelMeta\n\n/**\n * Lyria 3 Clip Preview — 30-second music clips in MP3 format.\n * @see https://ai.google.dev/gemini-api/docs/music-generation\n */\nconst LYRIA_3_CLIP = {\n name: 'lyria-3-clip-preview',\n max_input_tokens: 131_072,\n supports: {\n input: ['text', 'image'],\n output: ['audio'],\n capabilities: ['audio_generation'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0,\n },\n },\n} as const satisfies ModelMeta\n\nconst GEMINI_2_5_FLASH_LITE = {\n name: 'gemini-2.5-flash-lite',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'audio', 'video', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: ['code_execution', 'google_maps', 'google_search', 'url_context'],\n },\n pricing: {\n input: {\n normal: 0.1,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst IMAGEN_4_GENERATE = {\n name: 'imagen-4.0-generate-001',\n max_input_tokens: 480,\n max_output_tokens: 4,\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst IMAGEN_4_GENERATE_ULTRA = {\n name: 'imagen-4.0-ultra-generate-001',\n max_input_tokens: 480,\n max_output_tokens: 4,\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.6,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst IMAGEN_4_GENERATE_FAST = {\n name: 'imagen-4.0-fast-generate-001',\n max_input_tokens: 480,\n max_output_tokens: 4,\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.2,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Veo video generation models. Pricing is per second of generated video\n * (audio+video rate where the model supports audio).\n * @experimental Veo video generation is an experimental feature and may change.\n */\nconst VEO_3_1_PREVIEW = {\n name: 'veo-3.1-generate-preview',\n max_input_tokens: 1024,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.4,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst VEO_3_1_FAST_PREVIEW = {\n name: 'veo-3.1-fast-generate-preview',\n max_input_tokens: 1024,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.15,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst VEO_3_1_LITE_PREVIEW = {\n name: 'veo-3.1-lite-generate-preview',\n max_input_tokens: 1024,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.05,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\n/**\n * Gemini Omni Flash — multimodal video generation with conversational\n * editing. Serves only the Interactions API (`generateContent` rejects it),\n * so it routes through the interactions-based path of the video adapter,\n * not Veo's `:predictLongRunning` flow. Pricing is per second of generated\n * video ($0.10/sec). 720p / 24 FPS, 3–10 second clips (default 10s).\n * @experimental Omni video generation is an experimental feature and may change.\n */\nconst GEMINI_OMNI_FLASH_PREVIEW = {\n name: 'gemini-omni-flash-preview',\n max_input_tokens: 1_048_576,\n max_output_tokens: 1,\n supports: {\n input: ['text', 'image', 'video'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.1,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions\n>\n\nconst GEMINI_3_7_FLASH = {\n name: 'gemini-3.7-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2026-03-01',\n supports: {\n input: ['text', 'image', 'video', 'audio', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n 'computer_use',\n ],\n },\n // Currently 50% off through the end of 2026.\n // https://ai.google.dev/gemini-api/docs/pricing#gemini-3.7-flash\n pricing: {\n input: {\n normal: 0.75,\n cached: 0.075,\n },\n output: {\n normal: 3.75,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_6_FLASH = {\n name: 'gemini-3.6-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2026-03-01',\n supports: {\n input: ['text', 'image', 'video', 'audio', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n 'computer_use',\n ],\n },\n pricing: {\n input: {\n normal: 1.5,\n cached: 0.15,\n },\n output: {\n normal: 7.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_5_FLASH = {\n name: 'gemini-3.5-flash',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n supports: {\n input: ['text', 'image', 'video', 'document', 'audio'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n 'computer_use',\n ],\n },\n pricing: {\n input: {\n normal: 1.5,\n cached: 0.15,\n },\n output: {\n normal: 9,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nconst GEMINI_3_5_FLASH_LITE = {\n name: 'gemini-3.5-flash-lite',\n max_input_tokens: 1_048_576,\n max_output_tokens: 65_536,\n knowledge_cutoff: '2025-01-01',\n supports: {\n input: ['text', 'image', 'video', 'audio', 'document'],\n output: ['text'],\n capabilities: [\n 'batch_api',\n 'caching',\n 'function_calling',\n 'structured_output',\n 'thinking',\n ],\n tools: [\n 'code_execution',\n 'file_search',\n 'google_search',\n 'google_maps',\n 'url_context',\n ],\n },\n pricing: {\n input: {\n normal: 0.3,\n cached: 0.03,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta<\n GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n>\n\nexport const GEMINI_MODELS = [\n GEMINI_3_7_FLASH.name,\n GEMINI_3_6_FLASH.name,\n GEMINI_3_5_FLASH.name,\n GEMINI_3_5_FLASH_LITE.name,\n GEMINI_3_1_PRO.name,\n GEMINI_3_FLASH.name,\n GEMINI_3_1_FLASH_LITE.name,\n GEMINI_3_1_FLASH_LITE_PREVIEW.name,\n GEMINI_2_5_PRO.name,\n GEMINI_2_5_FLASH.name,\n GEMINI_2_5_FLASH_LITE.name,\n] as const\n\n/**\n * Gemini models that support combining `tools` + `responseSchema` in a\n * single streaming `generateContent` call (per issue #605). Per the\n * provider matrix, Gemini 3.x natively interleaves the schema-constrained\n * answer with function-calling on one pass; Gemini 2.x is unsupported /\n * brittle and keeps the engine's legacy finalization fallback.\n */\nexport const GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS = new Set<string>([\n GEMINI_3_7_FLASH.name,\n GEMINI_3_6_FLASH.name,\n GEMINI_3_5_FLASH.name,\n GEMINI_3_5_FLASH_LITE.name,\n GEMINI_3_1_PRO.name,\n GEMINI_3_FLASH.name,\n GEMINI_3_1_FLASH_LITE.name,\n GEMINI_3_1_FLASH_LITE_PREVIEW.name,\n])\n\nexport type GeminiModels = (typeof GEMINI_MODELS)[number]\n\n/**\n * @deprecated Shut down 2026-06-25. Use `gemini-3.1-flash-image`.\n */\ntype Gemini31FlashImagePreviewModel = 'gemini-3.1-flash-image-preview'\n\n/**\n * @deprecated Shut down 2026-06-25. Use `gemini-3-pro-image`.\n */\ntype Gemini3ProImagePreviewModel = 'gemini-3-pro-image-preview'\n\nexport type GeminiImageModels =\n | Exclude<\n (typeof GEMINI_IMAGE_MODELS)[number],\n Gemini31FlashImagePreviewModel | Gemini3ProImagePreviewModel\n >\n | Gemini31FlashImagePreviewModel\n | Gemini3ProImagePreviewModel\n\n/**\n * Image generation models. GA ids come first; the trailing `-preview` ids are\n * shut-down aliases kept only so existing code keeps compiling — new code\n * should use the GA id above its alias.\n */\nexport const GEMINI_IMAGE_MODELS = [\n GEMINI_3_1_FLASH_IMAGE.name,\n GEMINI_3_1_FLASH_LITE_IMAGE.name,\n GEMINI_3_PRO_IMAGE.name,\n GEMINI_2_5_FLASH_IMAGE.name,\n IMAGEN_4_GENERATE.name,\n IMAGEN_4_GENERATE_FAST.name,\n IMAGEN_4_GENERATE_ULTRA.name,\n // Deprecated aliases — shut down 2026-06-25.\n GEMINI_3_1_FLASH_IMAGE_PREVIEW.name,\n GEMINI_3_PRO_IMAGE_PREVIEW.name,\n] as const\n\n/**\n * Text-to-speech models\n * @experimental Gemini TTS is an experimental feature and may change.\n */\nexport const GEMINI_TTS_MODELS = [\n GEMINI_3_1_FLASH_TTS.name,\n GEMINI_2_5_FLASH_TTS.name,\n GEMINI_2_5_PRO_TTS.name,\n] as const\n\n/**\n * Audio generation models (Lyria music generation).\n * @experimental Lyria music generation is an experimental feature and may change.\n */\nexport const GEMINI_AUDIO_MODELS = [\n LYRIA_3_PRO.name,\n LYRIA_3_CLIP.name,\n] as const\n\n/**\n * Available voice names for Gemini TTS\n * @see https://ai.google.dev/gemini-api/docs/speech-generation\n */\nexport const GEMINI_TTS_VOICES = [\n 'Zephyr',\n 'Puck',\n 'Charon',\n 'Kore',\n 'Fenrir',\n 'Leda',\n 'Orus',\n 'Aoede',\n 'Callirrhoe',\n 'Autonoe',\n 'Enceladus',\n 'Iapetus',\n 'Umbriel',\n 'Algieba',\n 'Despina',\n 'Erinome',\n 'Algenib',\n 'Rasalgethi',\n 'Laomedeia',\n 'Achernar',\n 'Alnilam',\n 'Schedar',\n 'Gacrux',\n 'Pulcherrima',\n 'Achird',\n 'Zubenelgenubi',\n 'Vindemiatrix',\n 'Sadachbia',\n 'Sadaltager',\n 'Sulafat',\n] as const\n\nexport type GeminiTTSVoice = (typeof GEMINI_TTS_VOICES)[number]\n\n/**\n * Video generation models. Veo models run on the long-running\n * `:predictLongRunning` flow; Gemini Omni Flash runs on the Interactions\n * API — the video adapter routes by model.\n * @experimental Video generation is an experimental feature and may change.\n */\nexport const GEMINI_VIDEO_MODELS = [\n VEO_3_1_PREVIEW.name,\n VEO_3_1_FAST_PREVIEW.name,\n VEO_3_1_LITE_PREVIEW.name,\n GEMINI_OMNI_FLASH_PREVIEW.name,\n] as const\n\n/**\n * Video models served by the Interactions API rather than Veo's\n * `:predictLongRunning` operations flow.\n * @experimental Omni video generation is an experimental feature and may change.\n */\nexport const GEMINI_INTERACTIONS_VIDEO_MODELS = [\n GEMINI_OMNI_FLASH_PREVIEW.name,\n] as const\n\n/**\n * Embedding models\n */\nexport const GEMINI_EMBEDDING_MODELS = ['gemini-embedding-001'] as const\n\nexport type GeminiEmbeddingModel = (typeof GEMINI_EMBEDDING_MODELS)[number]\n\n/**\n * Type-only map from embedding model name to its provider options type.\n */\nexport type GeminiEmbeddingModelProviderOptionsByName = {\n 'gemini-embedding-001': GeminiEmbeddingProviderOptions\n}\n\n/**\n * Per-model input modalities for embedding models. Gemini embedding models\n * are text-only, so image inputs fail at compile time.\n */\nexport type GeminiEmbeddingModelInputModalitiesByName = {\n 'gemini-embedding-001': readonly ['text']\n}\n\n// Manual type map for per-model provider options\nexport type GeminiChatModelProviderOptionsByName = {\n // Models with thinking and structured output support\n [GEMINI_3_7_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_6_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_5_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_5_FLASH_LITE.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_1_PRO.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_1_FLASH_LITE.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_2_5_PRO.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_2_5_FLASH.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n [GEMINI_2_5_FLASH_LITE.name]: GeminiToolConfigOptions &\n GeminiSafetyOptions &\n GeminiCommonConfigOptions &\n GeminiCachedContentOptions &\n GeminiStructuredOutputOptions &\n GeminiThinkingOptions\n}\n\n/**\n * Type-only map from chat model name to its supported tool capabilities.\n * Based on the 'supports.tools' arrays defined for each model.\n */\nexport type GeminiChatModelToolCapabilitiesByName = {\n [GEMINI_3_7_FLASH.name]: typeof GEMINI_3_7_FLASH.supports.tools\n [GEMINI_3_6_FLASH.name]: typeof GEMINI_3_6_FLASH.supports.tools\n [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.tools\n [GEMINI_3_5_FLASH_LITE.name]: typeof GEMINI_3_5_FLASH_LITE.supports.tools\n [GEMINI_3_1_PRO.name]: typeof GEMINI_3_1_PRO.supports.tools\n [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.tools\n [GEMINI_3_1_FLASH_LITE.name]: typeof GEMINI_3_1_FLASH_LITE.supports.tools\n [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: typeof GEMINI_3_1_FLASH_LITE_PREVIEW.supports.tools\n [GEMINI_2_5_PRO.name]: typeof GEMINI_2_5_PRO.supports.tools\n [GEMINI_2_5_FLASH.name]: typeof GEMINI_2_5_FLASH.supports.tools\n [GEMINI_2_5_FLASH_LITE.name]: typeof GEMINI_2_5_FLASH_LITE.supports.tools\n}\n\n/**\n * Type-only map from chat model name to its supported input modalities.\n * Based on the 'supports.input' arrays defined for each model.\n * Note: 'document' in the model meta is mapped to 'document' modality.\n * Used by the core AI types to constrain ContentPart types based on the selected model.\n * Note: These must be inlined as readonly arrays (not typeof) because the model\n * constants are not exported and typeof references don't work in .d.ts files\n * when consumed by external packages.\n *\n * @see https://ai.google.dev/gemini-api/docs/vision\n * @see https://ai.google.dev/gemini-api/docs/audio\n * @see https://ai.google.dev/gemini-api/docs/document-processing\n */\nexport type GeminiModelInputModalitiesByName = {\n // Models with full multimodal support (text, image, audio, video, document)\n [GEMINI_3_7_FLASH.name]: typeof GEMINI_3_7_FLASH.supports.input\n [GEMINI_3_6_FLASH.name]: typeof GEMINI_3_6_FLASH.supports.input\n [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.input\n [GEMINI_3_5_FLASH_LITE.name]: typeof GEMINI_3_5_FLASH_LITE.supports.input\n [GEMINI_3_1_PRO.name]: typeof GEMINI_3_1_PRO.supports.input\n [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.input\n [GEMINI_3_1_FLASH_LITE.name]: typeof GEMINI_3_1_FLASH_LITE.supports.input\n [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: typeof GEMINI_3_1_FLASH_LITE_PREVIEW.supports.input\n [GEMINI_2_5_PRO.name]: typeof GEMINI_2_5_PRO.supports.input\n [GEMINI_2_5_FLASH_LITE.name]: typeof GEMINI_2_5_FLASH_LITE.supports.input\n\n // Models with text, image, audio, video (no document)\n [GEMINI_2_5_FLASH.name]: typeof GEMINI_2_5_FLASH.supports.input\n}\n"],"mappings":"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"}
@@ -143,11 +143,7 @@ async function createWebSocketConnection(token, model = "gemini-3.1-flash-live-p
143
143
  case "setup_complete":
144
144
  emit("status_change", { status: "connected" });
145
145
  break;
146
- case "error":
147
- emit("error", { error: new Error(response.data) });
148
- break;
149
- case "thought":
150
- case "session_resumption_update": break;
146
+ case "error": emit("error", { error: new Error(response.data) });
151
147
  }
152
148
  };
153
149
  await client.connect();
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":[],"sources":["../../../src/realtime/adapter.ts"],"sourcesContent":["import { createRealtimeEventEmitter } from '@tanstack/ai'\nimport { AudioPlayer, AudioStreamer, base64ToArrayBuffer } from './utils'\nimport { GeminiLiveClient } from './client'\nimport type { LiveResponse } from './client'\nimport type {\n AnyClientTool,\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeMessage,\n RealtimeMode,\n RealtimeToken,\n} from '@tanstack/ai'\nimport type { GeminiRealtimeModel, GeminiRealtimeOptions } from './types'\n\n/**\n * Creates a Gemini realtime adapter for client-side use.\n *\n * @param options - Optional configuration\n * @returns A RealtimeAdapter for use with RealtimeClient\n *\n * @example\n * ```typescript\n * import { RealtimeClient } from '@tanstack/ai-client'\n * import { geminiRealtime } from '@tanstack/ai-gemini'\n *\n * const client = new RealtimeClient({\n * getToken: () => fetch('/api/realtime-token').then(r => r.json()),\n * adapter: geminiRealtime(),\n * onGoAway: () => client.updateSession({ ... }) // Resume session with new config (available only for Gemini Live adapter)\n * })\n *\n * ```\n */\nexport function geminiRealtime(\n options: GeminiRealtimeOptions = {},\n): RealtimeAdapter {\n return {\n provider: 'gemini',\n\n connect(\n token: RealtimeToken,\n clientTools?: ReadonlyArray<AnyClientTool>,\n ): Promise<RealtimeConnection> {\n return createWebSocketConnection(token, options.model, clientTools)\n },\n }\n}\n\n/**\n * Creates a WebSocket connection to Gemini's realtime API\n */\nasync function createWebSocketConnection(\n token: RealtimeToken,\n model: GeminiRealtimeModel = 'gemini-3.1-flash-live-preview',\n tools?: ReadonlyArray<AnyClientTool>,\n): Promise<RealtimeConnection> {\n const { emit, on: realtimeEventEmitterOn } = createRealtimeEventEmitter()\n\n // Current state\n let currentMode: RealtimeMode = 'idle'\n let currentMessageId: string | null = null\n let messageIdCounter = 0\n\n function generateMessageId(): string {\n return `gemini-msg-${Date.now()}-${++messageIdCounter}`\n }\n\n const client = new GeminiLiveClient(token.token, model, tools)\n\n let message: RealtimeMessage = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n\n let pendingAssistantResponse = ''\n\n client.onClose = () => {\n emit('status_change', { status: 'idle' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onError = (error) => {\n emit('error', { error })\n emit('status_change', { status: 'error' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onReceiveResponse = (response: LiveResponse) => {\n switch (response.type) {\n case 'text':\n message.parts.push({\n type: 'text',\n content: response.data,\n })\n break\n case 'audio': {\n // Decode once, then reuse for both the stored message part and playback.\n const pcm = base64ToArrayBuffer(response.data.audioData)\n message.parts.push({\n type: 'audio',\n transcript: response.data.transcript,\n audioData: pcm,\n })\n if (currentMode !== 'speaking') {\n currentMode = 'speaking'\n emit('mode_change', { mode: 'speaking' })\n }\n audioPlayer.play(pcm).catch((error) => emit('error', { error }))\n break\n }\n case 'go_away':\n emit('go_away', { timeLeft: response.data.timeLeft })\n break\n case 'usage_metadata':\n emit('usage', {\n completionTokens: response.data.responseTokenCount ?? 0,\n promptTokens: response.data.promptTokenCount ?? 0,\n totalTokens: response.data.totalTokenCount ?? 0,\n })\n break\n case 'input_transcription':\n if (response.data.finished && currentMode !== 'thinking') {\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n }\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: response.data.text,\n role: 'user',\n })\n break\n case 'output_transcription':\n pendingAssistantResponse += response.data.text\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: pendingAssistantResponse,\n role: 'assistant',\n })\n break\n case 'interrupted':\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n break\n case 'tool_call':\n for (const tool of response.data.functionCalls || []) {\n if (tool.id && tool.name) {\n emit('tool_call', {\n toolCallId: tool.id,\n input: tool.args,\n toolName: tool.name,\n })\n }\n }\n break\n case 'turn_complete':\n currentMessageId = generateMessageId()\n message.id = currentMessageId\n message.timestamp = Date.now()\n message.parts.push({\n type: 'text',\n content: pendingAssistantResponse,\n })\n emit('message_complete', { message })\n\n pendingAssistantResponse = ''\n message = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n break\n case 'setup_complete':\n emit('status_change', { status: 'connected' })\n break\n case 'error':\n emit('error', {\n error: new Error(response.data),\n })\n break\n case 'thought':\n case 'session_resumption_update':\n // Handled internally by GeminiLiveClient; not surfaced to the client.\n break\n }\n }\n\n await client.connect()\n\n const audioStreamer = new AudioStreamer(client)\n const audioPlayer = new AudioPlayer()\n try {\n await audioPlayer.init()\n await audioStreamer.start()\n } catch (error) {\n // Tear down the socket + audio graph if mic/worklet setup fails (e.g. the\n // user denied microphone access) rather than leaking an open connection.\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n throw error\n }\n\n const connection: RealtimeConnection = {\n async disconnect() {\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n currentMode = 'idle'\n emit('status_change', { status: 'idle' })\n },\n\n async startAudioCapture() {\n // Audio capture is established during connection setup\n audioStreamer.startAudioCapture()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n },\n\n stopAudioCapture() {\n audioStreamer.stopAudioCapture()\n currentMode = 'idle'\n emit('mode_change', { mode: 'idle' })\n },\n\n sendText(text: string) {\n client.sendTextMessage(text)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendImage(imageData: string, mimeType: string) {\n client.sendImageMessage(imageData, mimeType)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendToolResult(callId: string, result: string) {\n client.sendToolResponse([\n {\n id: callId,\n response: {\n result,\n },\n },\n ])\n },\n\n updateSession(config) {\n client.updateSession(config).catch((error) => emit('error', { error }))\n emit('status_change', { status: 'reconnecting' })\n },\n\n updateToken(newToken) {\n client.updateToken(newToken)\n emit('status_change', { status: 'reconnecting' })\n },\n\n interrupt() {\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n },\n on: realtimeEventEmitterOn,\n getAudioVisualization(): AudioVisualization {\n return {\n get inputLevel() {\n return audioStreamer.inputLevel\n },\n\n get outputLevel() {\n return audioPlayer.outputLevel\n },\n\n getInputFrequencyData() {\n return audioStreamer.inputFrequencyData\n },\n\n getOutputFrequencyData() {\n return audioPlayer.outputFrequencyData\n },\n\n getInputTimeDomainData() {\n return audioStreamer.inputTimeDomainData\n },\n\n getOutputTimeDomainData() {\n return audioPlayer.outputTimeDomainData\n },\n\n get inputSampleRate() {\n return audioStreamer.inputSampleRate\n },\n\n get outputSampleRate() {\n return audioPlayer.outputSampleRate\n },\n }\n },\n }\n\n return connection\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../src/realtime/adapter.ts"],"sourcesContent":["import { createRealtimeEventEmitter } from '@tanstack/ai'\nimport { AudioPlayer, AudioStreamer, base64ToArrayBuffer } from './utils'\nimport { GeminiLiveClient } from './client'\nimport type { LiveResponse } from './client'\nimport type {\n AnyClientTool,\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeMessage,\n RealtimeMode,\n RealtimeToken,\n} from '@tanstack/ai'\nimport type { GeminiRealtimeModel, GeminiRealtimeOptions } from './types'\n\n/**\n * Creates a Gemini realtime adapter for client-side use.\n *\n * @param options - Optional configuration\n * @returns A RealtimeAdapter for use with RealtimeClient\n *\n * @example\n * ```typescript\n * import { RealtimeClient } from '@tanstack/ai-client'\n * import { geminiRealtime } from '@tanstack/ai-gemini'\n *\n * const client = new RealtimeClient({\n * getToken: () => fetch('/api/realtime-token').then(r => r.json()),\n * adapter: geminiRealtime(),\n * onGoAway: () => client.updateSession({ ... }) // Resume session with new config (available only for Gemini Live adapter)\n * })\n *\n * ```\n */\nexport function geminiRealtime(\n options: GeminiRealtimeOptions = {},\n): RealtimeAdapter {\n return {\n provider: 'gemini',\n\n connect(\n token: RealtimeToken,\n clientTools?: ReadonlyArray<AnyClientTool>,\n ): Promise<RealtimeConnection> {\n return createWebSocketConnection(token, options.model, clientTools)\n },\n }\n}\n\n/**\n * Creates a WebSocket connection to Gemini's realtime API\n */\nasync function createWebSocketConnection(\n token: RealtimeToken,\n model: GeminiRealtimeModel = 'gemini-3.1-flash-live-preview',\n tools?: ReadonlyArray<AnyClientTool>,\n): Promise<RealtimeConnection> {\n const { emit, on: realtimeEventEmitterOn } = createRealtimeEventEmitter()\n\n // Current state\n let currentMode: RealtimeMode = 'idle'\n let currentMessageId: string | null = null\n let messageIdCounter = 0\n\n function generateMessageId(): string {\n return `gemini-msg-${Date.now()}-${++messageIdCounter}`\n }\n\n const client = new GeminiLiveClient(token.token, model, tools)\n\n let message: RealtimeMessage = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n\n let pendingAssistantResponse = ''\n\n client.onClose = () => {\n emit('status_change', { status: 'idle' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onError = (error) => {\n emit('error', { error })\n emit('status_change', { status: 'error' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onReceiveResponse = (response: LiveResponse) => {\n switch (response.type) {\n case 'text':\n message.parts.push({\n type: 'text',\n content: response.data,\n })\n break\n case 'audio': {\n // Decode once, then reuse for both the stored message part and playback.\n const pcm = base64ToArrayBuffer(response.data.audioData)\n message.parts.push({\n type: 'audio',\n transcript: response.data.transcript,\n audioData: pcm,\n })\n if (currentMode !== 'speaking') {\n currentMode = 'speaking'\n emit('mode_change', { mode: 'speaking' })\n }\n audioPlayer.play(pcm).catch((error) => emit('error', { error }))\n break\n }\n case 'go_away':\n emit('go_away', { timeLeft: response.data.timeLeft })\n break\n case 'usage_metadata':\n emit('usage', {\n completionTokens: response.data.responseTokenCount ?? 0,\n promptTokens: response.data.promptTokenCount ?? 0,\n totalTokens: response.data.totalTokenCount ?? 0,\n })\n break\n case 'input_transcription':\n if (response.data.finished && currentMode !== 'thinking') {\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n }\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: response.data.text,\n role: 'user',\n })\n break\n case 'output_transcription':\n pendingAssistantResponse += response.data.text\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: pendingAssistantResponse,\n role: 'assistant',\n })\n break\n case 'interrupted':\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n break\n case 'tool_call':\n for (const tool of response.data.functionCalls || []) {\n if (tool.id && tool.name) {\n emit('tool_call', {\n toolCallId: tool.id,\n input: tool.args,\n toolName: tool.name,\n })\n }\n }\n break\n case 'turn_complete':\n currentMessageId = generateMessageId()\n message.id = currentMessageId\n message.timestamp = Date.now()\n message.parts.push({\n type: 'text',\n content: pendingAssistantResponse,\n })\n emit('message_complete', { message })\n\n pendingAssistantResponse = ''\n message = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n break\n case 'setup_complete':\n emit('status_change', { status: 'connected' })\n break\n case 'error':\n emit('error', {\n error: new Error(response.data),\n })\n break\n case 'thought':\n case 'session_resumption_update':\n // Handled internally by GeminiLiveClient; not surfaced to the client.\n break\n }\n }\n\n await client.connect()\n\n const audioStreamer = new AudioStreamer(client)\n const audioPlayer = new AudioPlayer()\n try {\n await audioPlayer.init()\n await audioStreamer.start()\n } catch (error) {\n // Tear down the socket + audio graph if mic/worklet setup fails (e.g. the\n // user denied microphone access) rather than leaking an open connection.\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n throw error\n }\n\n const connection: RealtimeConnection = {\n async disconnect() {\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n currentMode = 'idle'\n emit('status_change', { status: 'idle' })\n },\n\n async startAudioCapture() {\n // Audio capture is established during connection setup\n audioStreamer.startAudioCapture()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n },\n\n stopAudioCapture() {\n audioStreamer.stopAudioCapture()\n currentMode = 'idle'\n emit('mode_change', { mode: 'idle' })\n },\n\n sendText(text: string) {\n client.sendTextMessage(text)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendImage(imageData: string, mimeType: string) {\n client.sendImageMessage(imageData, mimeType)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendToolResult(callId: string, result: string) {\n client.sendToolResponse([\n {\n id: callId,\n response: {\n result,\n },\n },\n ])\n },\n\n updateSession(config) {\n client.updateSession(config).catch((error) => emit('error', { error }))\n emit('status_change', { status: 'reconnecting' })\n },\n\n updateToken(newToken) {\n client.updateToken(newToken)\n emit('status_change', { status: 'reconnecting' })\n },\n\n interrupt() {\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n },\n on: realtimeEventEmitterOn,\n getAudioVisualization(): AudioVisualization {\n return {\n get inputLevel() {\n return audioStreamer.inputLevel\n },\n\n get outputLevel() {\n return audioPlayer.outputLevel\n },\n\n getInputFrequencyData() {\n return audioStreamer.inputFrequencyData\n },\n\n getOutputFrequencyData() {\n return audioPlayer.outputFrequencyData\n },\n\n getInputTimeDomainData() {\n return audioStreamer.inputTimeDomainData\n },\n\n getOutputTimeDomainData() {\n return audioPlayer.outputTimeDomainData\n },\n\n get inputSampleRate() {\n return audioStreamer.inputSampleRate\n },\n\n get outputSampleRate() {\n return audioPlayer.outputSampleRate\n },\n }\n },\n }\n\n return connection\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../../src/realtime/client.ts"],"sourcesContent":["import { convertSchemaToJsonSchema } from '@tanstack/ai'\nimport {\n ActivityHandling,\n EndSensitivity,\n Modality,\n StartSensitivity,\n TurnCoverage,\n} from '@google/genai'\nimport type {\n ContextWindowCompressionConfig,\n FunctionDeclaration,\n FunctionResponse,\n LiveClientMessage,\n LiveServerGoAway,\n LiveServerMessage,\n LiveServerSessionResumptionUpdate,\n LiveServerToolCall,\n ThinkingConfig,\n UsageMetadata,\n} from '@google/genai'\nimport type {\n AnyClientTool,\n RealtimeSessionConfig,\n RealtimeToken,\n RealtimeToolConfig,\n} from '@tanstack/ai'\nimport type {\n GeminiRealtimeModel,\n GeminiRealtimeProviderOptions,\n GeminiRealtimeVoice,\n} from './types'\n\n/** Build a Gemini FunctionDeclaration from an isomorphic client tool (Zod). */\nfunction clientToolToDeclaration(tool: AnyClientTool): FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parametersJsonSchema: convertSchemaToJsonSchema(tool.inputSchema),\n responseJsonSchema: convertSchemaToJsonSchema(tool.outputSchema),\n }\n}\n\n/** Build a Gemini FunctionDeclaration from an already-serialized tool config. */\nfunction toolConfigToDeclaration(\n tool: RealtimeToolConfig,\n): FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parametersJsonSchema: tool.inputSchema,\n responseJsonSchema: tool.outputSchema,\n }\n}\n\ninterface LiveResponsePayloads {\n text: string\n thought: string\n audio: { audioData: string; transcript: string }\n setup_complete: string\n interrupted: string\n turn_complete: string\n tool_call: LiveServerToolCall\n session_resumption_update: LiveServerSessionResumptionUpdate\n go_away: LiveServerGoAway\n usage_metadata: UsageMetadata\n error: string\n input_transcription: { text: string; finished: boolean }\n output_transcription: { text: string; finished: boolean }\n}\n\nexport type MultimodalLiveResponseType = keyof LiveResponsePayloads\n\nexport type LiveResponse = {\n [K in MultimodalLiveResponseType]: {\n type: K\n data: LiveResponsePayloads[K]\n endOfTurn: boolean\n }\n}[MultimodalLiveResponseType]\n\n/**\n * Parses response messages from the Gemini Live API\n */\n/**\n * Parses ALL response types from a single server message.\n * The server can now bundle multiple fields (e.g. audio + transcription)\n * in the same message. Returns an array of response objects.\n */\nexport function parseResponseMessages(\n data: LiveServerMessage,\n): Array<LiveResponse> {\n const responses: Array<LiveResponse> = []\n const serverContent = data.serverContent\n const parts = serverContent?.modelTurn?.parts\n\n // Setup complete (exclusive — no other fields expected)\n if (data.setupComplete) {\n responses.push({ type: 'setup_complete', data: '', endOfTurn: false })\n return responses\n }\n\n // Tool call (exclusive)\n if (data.toolCall) {\n responses.push({\n type: 'tool_call',\n data: data.toolCall,\n endOfTurn: false,\n })\n return responses\n }\n\n if (data.sessionResumptionUpdate) {\n responses.push({\n type: 'session_resumption_update',\n data: data.sessionResumptionUpdate,\n endOfTurn: false,\n })\n }\n\n if (data.goAway) {\n responses.push({ type: 'go_away', data: data.goAway, endOfTurn: false })\n }\n\n if (data.usageMetadata) {\n responses.push({\n type: 'usage_metadata',\n data: data.usageMetadata,\n endOfTurn: false,\n })\n }\n\n // Audio data from model turn parts\n if (parts?.length) {\n for (const part of parts) {\n if (part.inlineData?.data) {\n responses.push({\n type: 'audio',\n data: {\n audioData: part.inlineData.data,\n // The transcription is independent to the model turn, which means it doesn't imply any ordering between transcription and model turn.\n transcript: '',\n },\n endOfTurn: false,\n })\n } else if (part.text) {\n responses.push({\n type: part.thought ? 'thought' : 'text',\n data: part.text,\n endOfTurn: false,\n })\n }\n }\n }\n\n // Transcriptions — checked independently, NOT in else-if with audio\n if (serverContent?.inputTranscription) {\n responses.push({\n type: 'input_transcription',\n data: {\n text: serverContent.inputTranscription.text || '',\n finished: serverContent.inputTranscription.finished || false,\n },\n endOfTurn: false,\n })\n }\n\n if (serverContent?.outputTranscription) {\n responses.push({\n type: 'output_transcription',\n data: {\n text: serverContent.outputTranscription.text || '',\n finished: serverContent.outputTranscription.finished || false,\n },\n endOfTurn: false,\n })\n }\n\n // Interrupted\n if (serverContent?.interrupted) {\n responses.push({ type: 'interrupted', data: '', endOfTurn: false })\n }\n\n // Turn complete\n if (serverContent?.turnComplete) {\n responses.push({ type: 'turn_complete', data: '', endOfTurn: true })\n }\n\n return responses\n}\n\nexport class GeminiLiveClient {\n private token: string | null = null\n private model: GeminiRealtimeModel | null = null\n\n private readonly responseModalities: Array<Modality> = [Modality.AUDIO]\n private systemInstructions = ''\n private googleGrounding = false\n private voiceName: GeminiRealtimeVoice = 'Puck'\n private temperature = 1.0\n private inputAudioTranscription = false\n private outputAudioTranscription = false\n private contextWindowCompression: ContextWindowCompressionConfig | undefined\n private proactiveAudio = false\n private enableAffectiveDialog = false\n private thinkingConfig: ThinkingConfig | undefined\n private speechLanguageCode: string | undefined\n\n private maxOutputTokens: number | undefined\n private functionDeclarations: Array<FunctionDeclaration> = []\n\n private readonly automaticActivityDetection = {\n disabled: false,\n silence_duration_ms: 2000,\n prefix_padding_ms: 500,\n end_of_speech_sensitivity: EndSensitivity.END_SENSITIVITY_UNSPECIFIED,\n start_of_speech_sensitivity: StartSensitivity.START_SENSITIVITY_UNSPECIFIED,\n }\n\n private readonly activityHandling =\n ActivityHandling.ACTIVITY_HANDLING_UNSPECIFIED\n\n private webSocket: WebSocket | null = null\n private lastResumptionUpdate: LiveServerSessionResumptionUpdate | null = null\n private setupComplete = false\n private connected = false\n\n public onReceiveResponse: (response: LiveResponse) => void = () => {}\n public onOpen: () => void = () => {}\n public onClose: () => void = () => {}\n public onError: (error: Error) => void = () => {}\n\n constructor(\n token: string,\n model: GeminiRealtimeModel,\n tools?: ReadonlyArray<AnyClientTool>,\n ) {\n this.token = token\n this.model = model\n\n if (tools) {\n this.functionDeclarations = tools.map(clientToolToDeclaration)\n }\n }\n\n get isConnected() {\n return this.connected\n }\n\n get isSetupComplete() {\n return this.setupComplete\n }\n\n /**\n * Connection management\n */\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const socket = new WebSocket(\n `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained?access_token=${this.token}`,\n )\n this.webSocket = socket\n\n // The browser fires `onerror` then `onclose` on an abnormal close; this\n // flag stops the close handler from overwriting the surfaced error with a\n // benign \"closed\" signal.\n let errored = false\n\n socket.onclose = () => {\n this.connected = false\n this.setupComplete = false\n if (!errored) this.onClose()\n reject(new Error('WebSocket closed before setup completed'))\n }\n\n socket.onerror = () => {\n errored = true\n this.connected = false\n this.setupComplete = false\n const error = new Error('Gemini realtime WebSocket connection error')\n this.onError(error)\n reject(error)\n }\n\n socket.onopen = () => {\n this.connected = true\n this.onOpen()\n resolve()\n }\n\n socket.onmessage = (event) => {\n void this.onReceiveMessage(event)\n }\n })\n }\n\n disconnect() {\n if (this.webSocket) {\n // Detach handlers first so a deliberate teardown (e.g. during a\n // reconnect) doesn't emit a spurious close/error to the client.\n this.webSocket.onclose = null\n this.webSocket.onerror = null\n this.webSocket.onopen = null\n this.webSocket.onmessage = null\n this.webSocket.close()\n this.webSocket = null\n }\n this.connected = false\n this.setupComplete = false\n }\n\n /**\n * Session management\n */\n sendInitialSetupMessage(resume = false) {\n const tools = this.functionDeclarations\n\n const setup: NonNullable<LiveClientMessage['setup']> = {\n model: `models/${this.model}`,\n generationConfig: {\n responseModalities: this.responseModalities,\n temperature: this.temperature,\n speechConfig: {\n languageCode: this.speechLanguageCode,\n voiceConfig: {\n prebuiltVoiceConfig: {\n voiceName: this.voiceName,\n },\n },\n },\n enableAffectiveDialog: this.enableAffectiveDialog,\n maxOutputTokens: this.maxOutputTokens,\n thinkingConfig: this.thinkingConfig,\n },\n sessionResumption: {\n transparent: true,\n handle: resume ? this.lastResumptionUpdate?.newHandle : undefined,\n },\n contextWindowCompression: this.contextWindowCompression,\n proactivity: {\n proactiveAudio: this.proactiveAudio,\n },\n systemInstruction: { parts: [{ text: this.systemInstructions }] },\n tools: [{ functionDeclarations: tools }],\n realtimeInputConfig: {\n automaticActivityDetection: {\n disabled: this.automaticActivityDetection.disabled,\n silenceDurationMs:\n this.automaticActivityDetection.silence_duration_ms,\n prefixPaddingMs: this.automaticActivityDetection.prefix_padding_ms,\n endOfSpeechSensitivity:\n this.automaticActivityDetection.end_of_speech_sensitivity,\n startOfSpeechSensitivity:\n this.automaticActivityDetection.start_of_speech_sensitivity,\n },\n activityHandling: this.activityHandling,\n turnCoverage: TurnCoverage.TURN_INCLUDES_ONLY_ACTIVITY,\n },\n }\n\n if (this.inputAudioTranscription) {\n setup.inputAudioTranscription = {}\n }\n\n if (this.outputAudioTranscription) {\n setup.outputAudioTranscription = {}\n }\n\n if (this.googleGrounding) {\n // Currently can't have both Google Search with custom tools.\n console.warn(\n 'Google Grounding enabled, removing custom function calls if any.',\n )\n setup.tools = [{ googleSearch: {} }]\n }\n\n this.sendMessage({ setup })\n }\n\n async restartSession(resume = false) {\n this.disconnect()\n await this.connect()\n this.sendInitialSetupMessage(resume)\n }\n\n updateToken(token: RealtimeToken) {\n this.token = token.token\n\n // Restart completely with the new model, or resume the existing session.\n const resume = !(token.config.model && this.model != token.config.model)\n if (!resume) {\n this.model = token.config.model as GeminiRealtimeModel\n }\n this.restartSession(resume).catch((err) =>\n this.onError(err instanceof Error ? err : new Error(String(err))),\n )\n }\n\n async updateSession(config: Partial<RealtimeSessionConfig>) {\n // model can only be set during initial setup\n if (config.model && !this.setupComplete) {\n this.model = config.model as GeminiRealtimeModel\n }\n\n if (config.instructions) {\n this.systemInstructions = config.instructions\n }\n\n if (config.tools) {\n this.functionDeclarations = config.tools.map(toolConfigToDeclaration)\n }\n\n if (config.maxOutputTokens) {\n // Gemini has no \"inf\" sentinel; treat it as \"no explicit limit\".\n this.maxOutputTokens =\n typeof config.maxOutputTokens === 'number'\n ? config.maxOutputTokens\n : undefined\n }\n\n if (config.temperature) {\n this.temperature = config.temperature\n }\n\n if (config.voice) {\n this.voiceName = config.voice as GeminiRealtimeVoice\n }\n\n const providerOptions = config.providerOptions as\n | GeminiRealtimeProviderOptions\n | undefined\n\n if (providerOptions?.googleGrounding) {\n this.googleGrounding = providerOptions.googleGrounding\n }\n\n if (providerOptions?.proactiveAudio) {\n this.proactiveAudio = providerOptions.proactiveAudio\n }\n\n if (providerOptions?.enableAffectiveDialog) {\n this.enableAffectiveDialog = providerOptions.enableAffectiveDialog\n }\n\n if (providerOptions?.contextWindowCompression) {\n this.contextWindowCompression = providerOptions.contextWindowCompression\n }\n\n if (providerOptions?.thinkingConfig) {\n this.thinkingConfig = providerOptions.thinkingConfig\n }\n\n if (providerOptions?.languageCode) {\n this.speechLanguageCode = providerOptions.languageCode\n }\n\n const includeTranscription =\n config.outputModalities?.includes('text') || false\n this.inputAudioTranscription = includeTranscription\n this.outputAudioTranscription = includeTranscription\n\n if (!this.setupComplete) {\n this.sendInitialSetupMessage()\n } else {\n return this.restartSession(true)\n }\n }\n\n /**\n * Message transmission & receiving\n */\n sendMessage(message: LiveClientMessage) {\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(JSON.stringify(message))\n } else {\n this.onError(\n new Error('Cannot send message: Gemini realtime socket is not open'),\n )\n }\n }\n\n async onReceiveMessage(messageEvent: MessageEvent) {\n let jsonData\n if (messageEvent.data instanceof Blob) {\n jsonData = await messageEvent.data.text()\n } else if (messageEvent.data instanceof ArrayBuffer) {\n jsonData = new TextDecoder().decode(messageEvent.data)\n } else {\n jsonData = messageEvent.data\n }\n\n try {\n const messageData = JSON.parse(jsonData)\n // Parse all response types from this message (audio + transcription can coexist)\n const responses = parseResponseMessages(messageData)\n for (const response of responses) {\n if (\n response.type === 'session_resumption_update' &&\n response.data.resumable\n ) {\n this.lastResumptionUpdate = response.data\n }\n if (response.type === 'setup_complete') {\n this.setupComplete = true\n }\n this.onReceiveResponse(response)\n }\n } catch (err) {\n this.onError(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n sendRealtimeInputMessage(data: string, mimeType: string) {\n const blob = { mimeType, data }\n\n if (mimeType.startsWith('audio/')) {\n this.sendMessage({ realtimeInput: { audio: blob } })\n } else if (mimeType.startsWith('image/') || mimeType.startsWith('video/')) {\n this.sendMessage({ realtimeInput: { video: blob } })\n }\n }\n\n sendAudioMessage(base64PCM: string) {\n this.sendRealtimeInputMessage(base64PCM, 'audio/pcm')\n }\n\n sendImageMessage(base64: string, mimeType = 'image/jpeg') {\n this.sendRealtimeInputMessage(base64, mimeType)\n }\n\n sendTextMessage(text: string) {\n const message: LiveClientMessage = {\n realtimeInput: {\n text,\n },\n }\n this.sendMessage(message)\n }\n\n sendToolResponse(functionResponses: Array<FunctionResponse>) {\n const message: LiveClientMessage = {\n toolResponse: {\n functionResponses,\n },\n }\n this.sendMessage(message)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../../src/realtime/client.ts"],"sourcesContent":["import { convertSchemaToJsonSchema } from '@tanstack/ai'\nimport {\n ActivityHandling,\n EndSensitivity,\n Modality,\n StartSensitivity,\n TurnCoverage,\n} from '@google/genai'\nimport type {\n ContextWindowCompressionConfig,\n FunctionDeclaration,\n FunctionResponse,\n LiveClientMessage,\n LiveServerGoAway,\n LiveServerMessage,\n LiveServerSessionResumptionUpdate,\n LiveServerToolCall,\n ThinkingConfig,\n UsageMetadata,\n} from '@google/genai'\nimport type {\n AnyClientTool,\n RealtimeSessionConfig,\n RealtimeToken,\n RealtimeToolConfig,\n} from '@tanstack/ai'\nimport type {\n GeminiRealtimeModel,\n GeminiRealtimeProviderOptions,\n GeminiRealtimeVoice,\n} from './types'\n\n/** Build a Gemini FunctionDeclaration from an isomorphic client tool (Zod). */\nfunction clientToolToDeclaration(tool: AnyClientTool): FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parametersJsonSchema: convertSchemaToJsonSchema(tool.inputSchema),\n responseJsonSchema: convertSchemaToJsonSchema(tool.outputSchema),\n }\n}\n\n/** Build a Gemini FunctionDeclaration from an already-serialized tool config. */\nfunction toolConfigToDeclaration(\n tool: RealtimeToolConfig,\n): FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parametersJsonSchema: tool.inputSchema,\n responseJsonSchema: tool.outputSchema,\n }\n}\n\ninterface LiveResponsePayloads {\n text: string\n thought: string\n audio: { audioData: string; transcript: string }\n setup_complete: string\n interrupted: string\n turn_complete: string\n tool_call: LiveServerToolCall\n session_resumption_update: LiveServerSessionResumptionUpdate\n go_away: LiveServerGoAway\n usage_metadata: UsageMetadata\n error: string\n input_transcription: { text: string; finished: boolean }\n output_transcription: { text: string; finished: boolean }\n}\n\nexport type MultimodalLiveResponseType = keyof LiveResponsePayloads\n\nexport type LiveResponse = {\n [K in MultimodalLiveResponseType]: {\n type: K\n data: LiveResponsePayloads[K]\n endOfTurn: boolean\n }\n}[MultimodalLiveResponseType]\n\n/**\n * Parses response messages from the Gemini Live API\n */\n/**\n * Parses ALL response types from a single server message.\n * The server can now bundle multiple fields (e.g. audio + transcription)\n * in the same message. Returns an array of response objects.\n */\nexport function parseResponseMessages(\n data: LiveServerMessage,\n): Array<LiveResponse> {\n const responses: Array<LiveResponse> = []\n const serverContent = data.serverContent\n const parts = serverContent?.modelTurn?.parts\n\n // Setup complete (exclusive — no other fields expected)\n if (data.setupComplete) {\n responses.push({ type: 'setup_complete', data: '', endOfTurn: false })\n return responses\n }\n\n // Tool call (exclusive)\n if (data.toolCall) {\n responses.push({\n type: 'tool_call',\n data: data.toolCall,\n endOfTurn: false,\n })\n return responses\n }\n\n if (data.sessionResumptionUpdate) {\n responses.push({\n type: 'session_resumption_update',\n data: data.sessionResumptionUpdate,\n endOfTurn: false,\n })\n }\n\n if (data.goAway) {\n responses.push({ type: 'go_away', data: data.goAway, endOfTurn: false })\n }\n\n if (data.usageMetadata) {\n responses.push({\n type: 'usage_metadata',\n data: data.usageMetadata,\n endOfTurn: false,\n })\n }\n\n // Audio data from model turn parts\n if (parts?.length) {\n for (const part of parts) {\n if (part.inlineData?.data) {\n responses.push({\n type: 'audio',\n data: {\n audioData: part.inlineData.data,\n // The transcription is independent to the model turn, which means it doesn't imply any ordering between transcription and model turn.\n transcript: '',\n },\n endOfTurn: false,\n })\n } else if (part.text) {\n responses.push({\n type: part.thought ? 'thought' : 'text',\n data: part.text,\n endOfTurn: false,\n })\n }\n }\n }\n\n // Transcriptions — checked independently, NOT in else-if with audio\n if (serverContent?.inputTranscription) {\n responses.push({\n type: 'input_transcription',\n data: {\n text: serverContent.inputTranscription.text || '',\n finished: serverContent.inputTranscription.finished || false,\n },\n endOfTurn: false,\n })\n }\n\n if (serverContent?.outputTranscription) {\n responses.push({\n type: 'output_transcription',\n data: {\n text: serverContent.outputTranscription.text || '',\n finished: serverContent.outputTranscription.finished || false,\n },\n endOfTurn: false,\n })\n }\n\n // Interrupted\n if (serverContent?.interrupted) {\n responses.push({ type: 'interrupted', data: '', endOfTurn: false })\n }\n\n // Turn complete\n if (serverContent?.turnComplete) {\n responses.push({ type: 'turn_complete', data: '', endOfTurn: true })\n }\n\n return responses\n}\n\nexport class GeminiLiveClient {\n private token: string | null = null\n private model: GeminiRealtimeModel | null = null\n\n private readonly responseModalities: Array<Modality> = [Modality.AUDIO]\n private systemInstructions = ''\n private googleGrounding = false\n private voiceName: GeminiRealtimeVoice = 'Puck'\n private temperature = 1.0\n private inputAudioTranscription = false\n private outputAudioTranscription = false\n private contextWindowCompression: ContextWindowCompressionConfig | undefined\n private proactiveAudio = false\n private enableAffectiveDialog = false\n private thinkingConfig: ThinkingConfig | undefined\n private speechLanguageCode: string | undefined\n\n private maxOutputTokens: number | undefined\n private functionDeclarations: Array<FunctionDeclaration> = []\n\n private readonly automaticActivityDetection = {\n disabled: false,\n silence_duration_ms: 2000,\n prefix_padding_ms: 500,\n end_of_speech_sensitivity: EndSensitivity.END_SENSITIVITY_UNSPECIFIED,\n start_of_speech_sensitivity: StartSensitivity.START_SENSITIVITY_UNSPECIFIED,\n }\n\n private readonly activityHandling =\n ActivityHandling.ACTIVITY_HANDLING_UNSPECIFIED\n\n private webSocket: WebSocket | null = null\n private lastResumptionUpdate: LiveServerSessionResumptionUpdate | null = null\n private setupComplete = false\n private connected = false\n\n public onReceiveResponse: (response: LiveResponse) => void = () => {}\n public onOpen: () => void = () => {}\n public onClose: () => void = () => {}\n public onError: (error: Error) => void = () => {}\n\n constructor(\n token: string,\n model: GeminiRealtimeModel,\n tools?: ReadonlyArray<AnyClientTool>,\n ) {\n this.token = token\n this.model = model\n\n if (tools) {\n this.functionDeclarations = tools.map(clientToolToDeclaration)\n }\n }\n\n get isConnected() {\n return this.connected\n }\n\n get isSetupComplete() {\n return this.setupComplete\n }\n\n /**\n * Connection management\n */\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const socket = new WebSocket(\n `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained?access_token=${this.token}`,\n )\n this.webSocket = socket\n\n // The browser fires `onerror` then `onclose` on an abnormal close; this\n // flag stops the close handler from overwriting the surfaced error with a\n // benign \"closed\" signal.\n let errored = false\n\n socket.onclose = () => {\n this.connected = false\n this.setupComplete = false\n if (!errored) this.onClose()\n reject(new Error('WebSocket closed before setup completed'))\n }\n\n socket.onerror = () => {\n errored = true\n this.connected = false\n this.setupComplete = false\n const error = new Error('Gemini realtime WebSocket connection error')\n this.onError(error)\n reject(error)\n }\n\n socket.onopen = () => {\n this.connected = true\n this.onOpen()\n resolve()\n }\n\n socket.onmessage = (event) => {\n void this.onReceiveMessage(event)\n }\n })\n }\n\n disconnect() {\n if (this.webSocket) {\n // Detach handlers first so a deliberate teardown (e.g. during a\n // reconnect) doesn't emit a spurious close/error to the client.\n this.webSocket.onclose = null\n this.webSocket.onerror = null\n this.webSocket.onopen = null\n this.webSocket.onmessage = null\n this.webSocket.close()\n this.webSocket = null\n }\n this.connected = false\n this.setupComplete = false\n }\n\n /**\n * Session management\n */\n sendInitialSetupMessage(resume = false) {\n const tools = this.functionDeclarations\n\n const setup: NonNullable<LiveClientMessage['setup']> = {\n model: `models/${this.model}`,\n generationConfig: {\n responseModalities: this.responseModalities,\n temperature: this.temperature,\n speechConfig: {\n languageCode: this.speechLanguageCode,\n voiceConfig: {\n prebuiltVoiceConfig: {\n voiceName: this.voiceName,\n },\n },\n },\n enableAffectiveDialog: this.enableAffectiveDialog,\n maxOutputTokens: this.maxOutputTokens,\n thinkingConfig: this.thinkingConfig,\n },\n sessionResumption: {\n transparent: true,\n handle: resume ? this.lastResumptionUpdate?.newHandle : undefined,\n },\n contextWindowCompression: this.contextWindowCompression,\n proactivity: {\n proactiveAudio: this.proactiveAudio,\n },\n systemInstruction: { parts: [{ text: this.systemInstructions }] },\n tools: [{ functionDeclarations: tools }],\n realtimeInputConfig: {\n automaticActivityDetection: {\n disabled: this.automaticActivityDetection.disabled,\n silenceDurationMs:\n this.automaticActivityDetection.silence_duration_ms,\n prefixPaddingMs: this.automaticActivityDetection.prefix_padding_ms,\n endOfSpeechSensitivity:\n this.automaticActivityDetection.end_of_speech_sensitivity,\n startOfSpeechSensitivity:\n this.automaticActivityDetection.start_of_speech_sensitivity,\n },\n activityHandling: this.activityHandling,\n turnCoverage: TurnCoverage.TURN_INCLUDES_ONLY_ACTIVITY,\n },\n }\n\n if (this.inputAudioTranscription) {\n setup.inputAudioTranscription = {}\n }\n\n if (this.outputAudioTranscription) {\n setup.outputAudioTranscription = {}\n }\n\n if (this.googleGrounding) {\n // Currently can't have both Google Search with custom tools.\n console.warn(\n 'Google Grounding enabled, removing custom function calls if any.',\n )\n setup.tools = [{ googleSearch: {} }]\n }\n\n this.sendMessage({ setup })\n }\n\n async restartSession(resume = false) {\n this.disconnect()\n await this.connect()\n this.sendInitialSetupMessage(resume)\n }\n\n updateToken(token: RealtimeToken) {\n this.token = token.token\n\n // Restart completely with the new model, or resume the existing session.\n const resume = !(token.config.model && this.model != token.config.model)\n if (!resume) {\n this.model = token.config.model as GeminiRealtimeModel\n }\n this.restartSession(resume).catch((err) =>\n this.onError(err instanceof Error ? err : new Error(String(err))),\n )\n }\n\n async updateSession(config: Partial<RealtimeSessionConfig>) {\n // model can only be set during initial setup\n if (config.model && !this.setupComplete) {\n this.model = config.model as GeminiRealtimeModel\n }\n\n if (config.instructions) {\n this.systemInstructions = config.instructions\n }\n\n if (config.tools) {\n this.functionDeclarations = config.tools.map(toolConfigToDeclaration)\n }\n\n if (config.maxOutputTokens) {\n // Gemini has no \"inf\" sentinel; treat it as \"no explicit limit\".\n this.maxOutputTokens =\n typeof config.maxOutputTokens === 'number'\n ? config.maxOutputTokens\n : undefined\n }\n\n if (config.temperature) {\n this.temperature = config.temperature\n }\n\n if (config.voice) {\n this.voiceName = config.voice as GeminiRealtimeVoice\n }\n\n const providerOptions = config.providerOptions as\n | GeminiRealtimeProviderOptions\n | undefined\n\n if (providerOptions?.googleGrounding) {\n this.googleGrounding = providerOptions.googleGrounding\n }\n\n if (providerOptions?.proactiveAudio) {\n this.proactiveAudio = providerOptions.proactiveAudio\n }\n\n if (providerOptions?.enableAffectiveDialog) {\n this.enableAffectiveDialog = providerOptions.enableAffectiveDialog\n }\n\n if (providerOptions?.contextWindowCompression) {\n this.contextWindowCompression = providerOptions.contextWindowCompression\n }\n\n if (providerOptions?.thinkingConfig) {\n this.thinkingConfig = providerOptions.thinkingConfig\n }\n\n if (providerOptions?.languageCode) {\n this.speechLanguageCode = providerOptions.languageCode\n }\n\n const includeTranscription =\n config.outputModalities?.includes('text') || false\n this.inputAudioTranscription = includeTranscription\n this.outputAudioTranscription = includeTranscription\n\n if (!this.setupComplete) {\n this.sendInitialSetupMessage()\n } else {\n return this.restartSession(true)\n }\n }\n\n /**\n * Message transmission & receiving\n */\n sendMessage(message: LiveClientMessage) {\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(JSON.stringify(message))\n } else {\n this.onError(\n new Error('Cannot send message: Gemini realtime socket is not open'),\n )\n }\n }\n\n async onReceiveMessage(messageEvent: MessageEvent) {\n let jsonData\n if (messageEvent.data instanceof Blob) {\n jsonData = await messageEvent.data.text()\n } else if (messageEvent.data instanceof ArrayBuffer) {\n jsonData = new TextDecoder().decode(messageEvent.data)\n } else {\n jsonData = messageEvent.data\n }\n\n try {\n const messageData = JSON.parse(jsonData)\n // Parse all response types from this message (audio + transcription can coexist)\n const responses = parseResponseMessages(messageData)\n for (const response of responses) {\n if (\n response.type === 'session_resumption_update' &&\n response.data.resumable\n ) {\n this.lastResumptionUpdate = response.data\n }\n if (response.type === 'setup_complete') {\n this.setupComplete = true\n }\n this.onReceiveResponse(response)\n }\n } catch (err) {\n this.onError(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n sendRealtimeInputMessage(data: string, mimeType: string) {\n const blob = { mimeType, data }\n\n if (mimeType.startsWith('audio/')) {\n this.sendMessage({ realtimeInput: { audio: blob } })\n } else if (mimeType.startsWith('image/') || mimeType.startsWith('video/')) {\n this.sendMessage({ realtimeInput: { video: blob } })\n }\n }\n\n sendAudioMessage(base64PCM: string) {\n this.sendRealtimeInputMessage(base64PCM, 'audio/pcm')\n }\n\n sendImageMessage(base64: string, mimeType = 'image/jpeg') {\n this.sendRealtimeInputMessage(base64, mimeType)\n }\n\n sendTextMessage(text: string) {\n const message: LiveClientMessage = {\n realtimeInput: {\n text,\n },\n }\n this.sendMessage(message)\n }\n\n sendToolResponse(functionResponses: Array<FunctionResponse>) {\n const message: LiveClientMessage = {\n toolResponse: {\n functionResponses,\n },\n }\n this.sendMessage(message)\n }\n}\n"],"mappings":";;;;AAiCA,SAAS,wBAAwB,MAA0C;CACzE,OAAO;EACL,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,sBAAsB,0BAA0B,KAAK,WAAW;EAChE,oBAAoB,0BAA0B,KAAK,YAAY;CACjE;AACF;;AAGA,SAAS,wBACP,MACqB;CACrB,OAAO;EACL,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,sBAAsB,KAAK;EAC3B,oBAAoB,KAAK;CAC3B;AACF;;;;;;;;;AAoCA,SAAgB,sBACd,MACqB;CACrB,MAAM,YAAiC,CAAC;CACxC,MAAM,gBAAgB,KAAK;CAC3B,MAAM,QAAQ,eAAe,WAAW;CAGxC,IAAI,KAAK,eAAe;EACtB,UAAU,KAAK;GAAE,MAAM;GAAkB,MAAM;GAAI,WAAW;EAAM,CAAC;EACrE,OAAO;CACT;CAGA,IAAI,KAAK,UAAU;EACjB,UAAU,KAAK;GACb,MAAM;GACN,MAAM,KAAK;GACX,WAAW;EACb,CAAC;EACD,OAAO;CACT;CAEA,IAAI,KAAK,yBACP,UAAU,KAAK;EACb,MAAM;EACN,MAAM,KAAK;EACX,WAAW;CACb,CAAC;CAGH,IAAI,KAAK,QACP,UAAU,KAAK;EAAE,MAAM;EAAW,MAAM,KAAK;EAAQ,WAAW;CAAM,CAAC;CAGzE,IAAI,KAAK,eACP,UAAU,KAAK;EACb,MAAM;EACN,MAAM,KAAK;EACX,WAAW;CACb,CAAC;CAIH,IAAI,OAAO,QACJ;OAAA,MAAM,QAAQ,OACjB,IAAI,KAAK,YAAY,MACnB,UAAU,KAAK;GACb,MAAM;GACN,MAAM;IACJ,WAAW,KAAK,WAAW;IAE3B,YAAY;GACd;GACA,WAAW;EACb,CAAC;OACI,IAAI,KAAK,MACd,UAAU,KAAK;GACb,MAAM,KAAK,UAAU,YAAY;GACjC,MAAM,KAAK;GACX,WAAW;EACb,CAAC;CAAA;CAMP,IAAI,eAAe,oBACjB,UAAU,KAAK;EACb,MAAM;EACN,MAAM;GACJ,MAAM,cAAc,mBAAmB,QAAQ;GAC/C,UAAU,cAAc,mBAAmB,YAAY;EACzD;EACA,WAAW;CACb,CAAC;CAGH,IAAI,eAAe,qBACjB,UAAU,KAAK;EACb,MAAM;EACN,MAAM;GACJ,MAAM,cAAc,oBAAoB,QAAQ;GAChD,UAAU,cAAc,oBAAoB,YAAY;EAC1D;EACA,WAAW;CACb,CAAC;CAIH,IAAI,eAAe,aACjB,UAAU,KAAK;EAAE,MAAM;EAAe,MAAM;EAAI,WAAW;CAAM,CAAC;CAIpE,IAAI,eAAe,cACjB,UAAU,KAAK;EAAE,MAAM;EAAiB,MAAM;EAAI,WAAW;CAAK,CAAC;CAGrE,OAAO;AACT;AAEA,IAAa,mBAAb,MAA8B;CAC5B,QAA+B;CAC/B,QAA4C;CAE5C,qBAAuD,CAAC,SAAS,KAAK;CACtE,qBAA6B;CAC7B,kBAA0B;CAC1B,YAAyC;CACzC,cAAsB;CACtB,0BAAkC;CAClC,2BAAmC;CACnC;CACA,iBAAyB;CACzB,wBAAgC;CAChC;CACA;CAEA;CACA,uBAA2D,CAAC;CAE5D,6BAA8C;EAC5C,UAAU;EACV,qBAAqB;EACrB,mBAAmB;EACnB,2BAA2B,eAAe;EAC1C,6BAA6B,iBAAiB;CAChD;CAEA,mBACE,iBAAiB;CAEnB,YAAsC;CACtC,uBAAyE;CACzE,gBAAwB;CACxB,YAAoB;CAEpB,0BAAmE,CAAC;CACpE,eAAkC,CAAC;CACnC,gBAAmC,CAAC;CACpC,gBAA+C,CAAC;CAEhD,YACE,OACA,OACA,OACA;EACA,KAAK,QAAQ;EACb,KAAK,QAAQ;EAEb,IAAI,OACF,KAAK,uBAAuB,MAAM,IAAI,uBAAuB;CAEjE;CAEA,IAAI,cAAc;EAChB,OAAO,KAAK;CACd;CAEA,IAAI,kBAAkB;EACpB,OAAO,KAAK;CACd;;;;CAKA,UAAyB;EACvB,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,SAAS,IAAI,UACjB,iJAAiJ,KAAK,OACxJ;GACA,KAAK,YAAY;GAKjB,IAAI,UAAU;GAEd,OAAO,gBAAgB;IACrB,KAAK,YAAY;IACjB,KAAK,gBAAgB;IACrB,IAAI,CAAC,SAAS,KAAK,QAAQ;IAC3B,uBAAO,IAAI,MAAM,yCAAyC,CAAC;GAC7D;GAEA,OAAO,gBAAgB;IACrB,UAAU;IACV,KAAK,YAAY;IACjB,KAAK,gBAAgB;IACrB,MAAM,wBAAQ,IAAI,MAAM,4CAA4C;IACpE,KAAK,QAAQ,KAAK;IAClB,OAAO,KAAK;GACd;GAEA,OAAO,eAAe;IACpB,KAAK,YAAY;IACjB,KAAK,OAAO;IACZ,QAAQ;GACV;GAEA,OAAO,aAAa,UAAU;IAC5B,KAAU,iBAAiB,KAAK;GAClC;EACF,CAAC;CACH;CAEA,aAAa;EACX,IAAI,KAAK,WAAW;GAGlB,KAAK,UAAU,UAAU;GACzB,KAAK,UAAU,UAAU;GACzB,KAAK,UAAU,SAAS;GACxB,KAAK,UAAU,YAAY;GAC3B,KAAK,UAAU,MAAM;GACrB,KAAK,YAAY;EACnB;EACA,KAAK,YAAY;EACjB,KAAK,gBAAgB;CACvB;;;;CAKA,wBAAwB,SAAS,OAAO;EACtC,MAAM,QAAQ,KAAK;EAEnB,MAAM,QAAiD;GACrD,OAAO,UAAU,KAAK;GACtB,kBAAkB;IAChB,oBAAoB,KAAK;IACzB,aAAa,KAAK;IAClB,cAAc;KACZ,cAAc,KAAK;KACnB,aAAa,EACX,qBAAqB,EACnB,WAAW,KAAK,UAClB,EACF;IACF;IACA,uBAAuB,KAAK;IAC5B,iBAAiB,KAAK;IACtB,gBAAgB,KAAK;GACvB;GACA,mBAAmB;IACjB,aAAa;IACb,QAAQ,SAAS,KAAK,sBAAsB,YAAY,KAAA;GAC1D;GACA,0BAA0B,KAAK;GAC/B,aAAa,EACX,gBAAgB,KAAK,eACvB;GACA,mBAAmB,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,mBAAmB,CAAC,EAAE;GAChE,OAAO,CAAC,EAAE,sBAAsB,MAAM,CAAC;GACvC,qBAAqB;IACnB,4BAA4B;KAC1B,UAAU,KAAK,2BAA2B;KAC1C,mBACE,KAAK,2BAA2B;KAClC,iBAAiB,KAAK,2BAA2B;KACjD,wBACE,KAAK,2BAA2B;KAClC,0BACE,KAAK,2BAA2B;IACpC;IACA,kBAAkB,KAAK;IACvB,cAAc,aAAa;GAC7B;EACF;EAEA,IAAI,KAAK,yBACP,MAAM,0BAA0B,CAAC;EAGnC,IAAI,KAAK,0BACP,MAAM,2BAA2B,CAAC;EAGpC,IAAI,KAAK,iBAAiB;GAExB,QAAQ,KACN,kEACF;GACA,MAAM,QAAQ,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC;EACrC;EAEA,KAAK,YAAY,EAAE,MAAM,CAAC;CAC5B;CAEA,MAAM,eAAe,SAAS,OAAO;EACnC,KAAK,WAAW;EAChB,MAAM,KAAK,QAAQ;EACnB,KAAK,wBAAwB,MAAM;CACrC;CAEA,YAAY,OAAsB;EAChC,KAAK,QAAQ,MAAM;EAGnB,MAAM,SAAS,EAAE,MAAM,OAAO,SAAS,KAAK,SAAS,MAAM,OAAO;EAClE,IAAI,CAAC,QACH,KAAK,QAAQ,MAAM,OAAO;EAE5B,KAAK,eAAe,MAAM,CAAC,CAAC,OAAO,QACjC,KAAK,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC,CAClE;CACF;CAEA,MAAM,cAAc,QAAwC;EAE1D,IAAI,OAAO,SAAS,CAAC,KAAK,eACxB,KAAK,QAAQ,OAAO;EAGtB,IAAI,OAAO,cACT,KAAK,qBAAqB,OAAO;EAGnC,IAAI,OAAO,OACT,KAAK,uBAAuB,OAAO,MAAM,IAAI,uBAAuB;EAGtE,IAAI,OAAO,iBAET,KAAK,kBACH,OAAO,OAAO,oBAAoB,WAC9B,OAAO,kBACP,KAAA;EAGR,IAAI,OAAO,aACT,KAAK,cAAc,OAAO;EAG5B,IAAI,OAAO,OACT,KAAK,YAAY,OAAO;EAG1B,MAAM,kBAAkB,OAAO;EAI/B,IAAI,iBAAiB,iBACnB,KAAK,kBAAkB,gBAAgB;EAGzC,IAAI,iBAAiB,gBACnB,KAAK,iBAAiB,gBAAgB;EAGxC,IAAI,iBAAiB,uBACnB,KAAK,wBAAwB,gBAAgB;EAG/C,IAAI,iBAAiB,0BACnB,KAAK,2BAA2B,gBAAgB;EAGlD,IAAI,iBAAiB,gBACnB,KAAK,iBAAiB,gBAAgB;EAGxC,IAAI,iBAAiB,cACnB,KAAK,qBAAqB,gBAAgB;EAG5C,MAAM,uBACJ,OAAO,kBAAkB,SAAS,MAAM,KAAK;EAC/C,KAAK,0BAA0B;EAC/B,KAAK,2BAA2B;EAEhC,IAAI,CAAC,KAAK,eACR,KAAK,wBAAwB;OAE7B,OAAO,KAAK,eAAe,IAAI;CAEnC;;;;CAKA,YAAY,SAA4B;EACtC,IAAI,KAAK,WAAW,eAAe,UAAU,MAC3C,KAAK,UAAU,KAAK,KAAK,UAAU,OAAO,CAAC;OAE3C,KAAK,wBACH,IAAI,MAAM,yDAAyD,CACrE;CAEJ;CAEA,MAAM,iBAAiB,cAA4B;EACjD,IAAI;EACJ,IAAI,aAAa,gBAAgB,MAC/B,WAAW,MAAM,aAAa,KAAK,KAAK;OACnC,IAAI,aAAa,gBAAgB,aACtC,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,aAAa,IAAI;OAErD,WAAW,aAAa;EAG1B,IAAI;GAGF,MAAM,YAAY,sBAFE,KAAK,MAAM,QAES,CAAW;GACnD,KAAK,MAAM,YAAY,WAAW;IAChC,IACE,SAAS,SAAS,+BAClB,SAAS,KAAK,WAEd,KAAK,uBAAuB,SAAS;IAEvC,IAAI,SAAS,SAAS,kBACpB,KAAK,gBAAgB;IAEvB,KAAK,kBAAkB,QAAQ;GACjC;EACF,SAAS,KAAK;GACZ,KAAK,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;EAClE;CACF;CAEA,yBAAyB,MAAc,UAAkB;EACvD,MAAM,OAAO;GAAE;GAAU;EAAK;EAE9B,IAAI,SAAS,WAAW,QAAQ,GAC9B,KAAK,YAAY,EAAE,eAAe,EAAE,OAAO,KAAK,EAAE,CAAC;OAC9C,IAAI,SAAS,WAAW,QAAQ,KAAK,SAAS,WAAW,QAAQ,GACtE,KAAK,YAAY,EAAE,eAAe,EAAE,OAAO,KAAK,EAAE,CAAC;CAEvD;CAEA,iBAAiB,WAAmB;EAClC,KAAK,yBAAyB,WAAW,WAAW;CACtD;CAEA,iBAAiB,QAAgB,WAAW,cAAc;EACxD,KAAK,yBAAyB,QAAQ,QAAQ;CAChD;CAEA,gBAAgB,MAAc;EAC5B,MAAM,UAA6B,EACjC,eAAe,EACb,KACF,EACF;EACA,KAAK,YAAY,OAAO;CAC1B;CAEA,iBAAiB,mBAA4C;EAC3D,MAAM,UAA6B,EACjC,cAAc,EACZ,kBACF,EACF;EACA,KAAK,YAAY,OAAO;CAC1B;AACF"}
@@ -26,11 +26,12 @@ import { GoogleGenAI } from "@google/genai";
26
26
  * ```
27
27
  */
28
28
  function geminiRealtimeToken(options = {}) {
29
- const client = new GoogleGenAI({ apiKey: getGeminiApiKeyFromEnv() });
29
+ const apiKey = getGeminiApiKeyFromEnv();
30
+ const client = new GoogleGenAI({ apiKey });
30
31
  return {
31
32
  provider: "gemini",
32
33
  async generateToken() {
33
- const expireTime = options.expiresAt ?? Date.now() + 1800 * 1e3;
34
+ const expireTime = options.expiresAt ?? Date.now() + 18e5;
34
35
  const token = await client.authTokens.create({ config: {
35
36
  uses: options.uses ?? 1,
36
37
  expireTime: new Date(expireTime).toISOString(),
@@ -1 +1 @@
1
- {"version":3,"file":"token.js","names":[],"sources":["../../../src/realtime/token.ts"],"sourcesContent":["import { GoogleGenAI } from '@google/genai'\nimport { getGeminiApiKeyFromEnv } from '../utils'\nimport type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai'\nimport type { GeminiRealtimeTokenOptions } from './types'\n\n/**\n * Creates a Google Gemini realtime token adapter.\n *\n * This adapter generates ephemeral tokens for client-side WebSocket connections.\n *\n * @param options - Configuration options for the realtime session\n * @returns A RealtimeTokenAdapter for use with realtimeToken()\n *\n * @example\n * ```typescript\n * import { realtimeToken } from '@tanstack/ai'\n * import { geminiRealtimeToken } from '@tanstack/ai-gemini'\n *\n * const token = await realtimeToken({\n * adapter: geminiRealtimeToken({\n * // Optional: constraint model config by token\n * liveConnectConstraints: {\n * model: 'gemini-3.1-flash-live-preview',\n * },\n * }),\n * })\n * ```\n */\nexport function geminiRealtimeToken(\n options: GeminiRealtimeTokenOptions = {},\n): RealtimeTokenAdapter {\n const apiKey = getGeminiApiKeyFromEnv()\n\n const client = new GoogleGenAI({\n apiKey,\n })\n\n return {\n provider: 'gemini',\n async generateToken(): Promise<RealtimeToken> {\n // Computed per call so a reused adapter doesn't mint tokens with a\n // fixed (and eventually past) expiry. Defaults to 30 minutes.\n const expireTime = options.expiresAt ?? Date.now() + 30 * 60 * 1000\n\n const token = await client.authTokens.create({\n config: {\n uses: options.uses ?? 1,\n expireTime: new Date(expireTime).toISOString(),\n liveConnectConstraints: options.liveConnectConstraints,\n httpOptions: {\n apiVersion: 'v1alpha',\n },\n },\n })\n\n if (!token.name) {\n throw new Error('Gemini realtime token creation failed')\n }\n\n return {\n provider: 'gemini',\n token: token.name,\n expiresAt: expireTime,\n config: {\n model: options.liveConnectConstraints?.model,\n },\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,oBACd,UAAsC,CAAC,GACjB;CAGtB,MAAM,SAAS,IAAI,YAAY,EAC7B,QAHa,uBAGb,EACF,CAAC;CAED,OAAO;EACL,UAAU;EACV,MAAM,gBAAwC;GAG5C,MAAM,aAAa,QAAQ,aAAa,KAAK,IAAI,IAAI,OAAU;GAE/D,MAAM,QAAQ,MAAM,OAAO,WAAW,OAAO,EAC3C,QAAQ;IACN,MAAM,QAAQ,QAAQ;IACtB,YAAY,IAAI,KAAK,UAAU,CAAC,CAAC,YAAY;IAC7C,wBAAwB,QAAQ;IAChC,aAAa,EACX,YAAY,UACd;GACF,EACF,CAAC;GAED,IAAI,CAAC,MAAM,MACT,MAAM,IAAI,MAAM,uCAAuC;GAGzD,OAAO;IACL,UAAU;IACV,OAAO,MAAM;IACb,WAAW;IACX,QAAQ,EACN,OAAO,QAAQ,wBAAwB,MACzC;GACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"token.js","names":[],"sources":["../../../src/realtime/token.ts"],"sourcesContent":["import { GoogleGenAI } from '@google/genai'\nimport { getGeminiApiKeyFromEnv } from '../utils'\nimport type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai'\nimport type { GeminiRealtimeTokenOptions } from './types'\n\n/**\n * Creates a Google Gemini realtime token adapter.\n *\n * This adapter generates ephemeral tokens for client-side WebSocket connections.\n *\n * @param options - Configuration options for the realtime session\n * @returns A RealtimeTokenAdapter for use with realtimeToken()\n *\n * @example\n * ```typescript\n * import { realtimeToken } from '@tanstack/ai'\n * import { geminiRealtimeToken } from '@tanstack/ai-gemini'\n *\n * const token = await realtimeToken({\n * adapter: geminiRealtimeToken({\n * // Optional: constraint model config by token\n * liveConnectConstraints: {\n * model: 'gemini-3.1-flash-live-preview',\n * },\n * }),\n * })\n * ```\n */\nexport function geminiRealtimeToken(\n options: GeminiRealtimeTokenOptions = {},\n): RealtimeTokenAdapter {\n const apiKey = getGeminiApiKeyFromEnv()\n\n const client = new GoogleGenAI({\n apiKey,\n })\n\n return {\n provider: 'gemini',\n async generateToken(): Promise<RealtimeToken> {\n // Computed per call so a reused adapter doesn't mint tokens with a\n // fixed (and eventually past) expiry. Defaults to 30 minutes.\n const expireTime = options.expiresAt ?? Date.now() + 30 * 60 * 1000\n\n const token = await client.authTokens.create({\n config: {\n uses: options.uses ?? 1,\n expireTime: new Date(expireTime).toISOString(),\n liveConnectConstraints: options.liveConnectConstraints,\n httpOptions: {\n apiVersion: 'v1alpha',\n },\n },\n })\n\n if (!token.name) {\n throw new Error('Gemini realtime token creation failed')\n }\n\n return {\n provider: 'gemini',\n token: token.name,\n expiresAt: expireTime,\n config: {\n model: options.liveConnectConstraints?.model,\n },\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,oBACd,UAAsC,CAAC,GACjB;CACtB,MAAM,SAAS,uBAAuB;CAEtC,MAAM,SAAS,IAAI,YAAY,EAC7B,OACF,CAAC;CAED,OAAO;EACL,UAAU;EACV,MAAM,gBAAwC;GAG5C,MAAM,aAAa,QAAQ,aAAa,KAAK,IAAI,IAAI;GAErD,MAAM,QAAQ,MAAM,OAAO,WAAW,OAAO,EAC3C,QAAQ;IACN,MAAM,QAAQ,QAAQ;IACtB,YAAY,IAAI,KAAK,UAAU,CAAC,CAAC,YAAY;IAC7C,wBAAwB,QAAQ;IAChC,aAAa,EACX,YAAY,UACd;GACF,EACF,CAAC;GAED,IAAI,CAAC,MAAM,MACT,MAAM,IAAI,MAAM,uCAAuC;GAGzD,OAAO;IACL,UAAU;IACV,OAAO,MAAM;IACb,WAAW;IACX,QAAQ,EACN,OAAO,QAAQ,wBAAwB,MACzC;GACF;EACF;CACF;AACF"}