diff --git a/.changeset/gemini-3-models.md b/.changeset/gemini-3-models.md new file mode 100644 index 00000000..91befe6c --- /dev/null +++ b/.changeset/gemini-3-models.md @@ -0,0 +1,5 @@ +--- +'@tanstack/ai-gemini': minor +--- + +Add Gemini 3 Flash and Pro Image models for text and image generation diff --git a/packages/typescript/ai-gemini/src/model-meta.ts b/packages/typescript/ai-gemini/src/model-meta.ts index 5fca6c16..9110c74e 100644 --- a/packages/typescript/ai-gemini/src/model-meta.ts +++ b/packages/typescript/ai-gemini/src/model-meta.ts @@ -83,6 +83,76 @@ const GEMINI_3_PRO = { GeminiThinkingOptions > +const GEMINI_3_FLASH = { + name: 'gemini-3-flash-preview', + max_input_tokens: 1_048_576, + max_output_tokens: 65_536, + knowledge_cutoff: '2025-01-01', + supports: { + input: ['text', 'image', 'audio', 'video', 'document'], + output: ['text'], + capabilities: [ + 'batch_api', + 'caching', + 'code_execution', + 'file_search', + 'function_calling', + 'search_grounding', + 'structured_output', + 'thinking', + 'url_context', + ], + }, + pricing: { + input: { + normal: 0.5, + }, + output: { + normal: 3, + }, + }, +} as const satisfies ModelMeta< + GeminiToolConfigOptions & + GeminiSafetyOptions & + GeminiGenerationConfigOptions & + GeminiCachedContentOptions & + GeminiStructuredOutputOptions & + GeminiThinkingOptions +> + +const GEMINI_3_PRO_IMAGE = { + name: 'gemini-3-pro-image-preview', + max_input_tokens: 65_536, + max_output_tokens: 32_768, + knowledge_cutoff: '2025-01-01', + supports: { + input: ['text', 'image'], + output: ['text', 'image'], + capabilities: [ + 'batch_api', + 'image_generation', + 'search_grounding', + 'structured_output', + 'thinking', + ], + }, + pricing: { + input: { + normal: 2, + }, + output: { + normal: 0.134, + }, + }, +} as const satisfies ModelMeta< + GeminiToolConfigOptions & + GeminiSafetyOptions & + GeminiGenerationConfigOptions & + GeminiCachedContentOptions & + GeminiStructuredOutputOptions & + GeminiThinkingOptions +> + const GEMINI_2_5_PRO = { name: 'gemini-2.5-pro', max_input_tokens: 1_048_576, @@ -747,6 +817,7 @@ const VEO_2 = { export const GEMINI_MODELS = [ GEMINI_3_PRO.name, + GEMINI_3_FLASH.name, GEMINI_2_5_PRO.name, GEMINI_2_5_FLASH.name, GEMINI_2_5_FLASH_PREVIEW.name, @@ -761,6 +832,7 @@ export type GeminiModels = (typeof GEMINI_MODELS)[number] export type GeminiImageModels = (typeof GEMINI_IMAGE_MODELS)[number] export const GEMINI_IMAGE_MODELS = [ + GEMINI_3_PRO_IMAGE.name, GEMINI_2_5_FLASH_IMAGE.name, GEMINI_2_FLASH_IMAGE.name, IMAGEN_3.name, @@ -841,6 +913,12 @@ export type GeminiChatModelProviderOptionsByName = { GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions + [GEMINI_3_FLASH.name]: GeminiToolConfigOptions & + GeminiSafetyOptions & + GeminiGenerationConfigOptions & + GeminiCachedContentOptions & + GeminiStructuredOutputOptions & + GeminiThinkingOptions [GEMINI_2_5_PRO.name]: GeminiToolConfigOptions & GeminiSafetyOptions & GeminiGenerationConfigOptions & @@ -900,6 +978,7 @@ export type GeminiChatModelProviderOptionsByName = { export type GeminiModelInputModalitiesByName = { // Models with full multimodal support (text, image, audio, video, document) [GEMINI_3_PRO.name]: typeof GEMINI_3_PRO.supports.input + [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.input [GEMINI_2_5_PRO.name]: typeof GEMINI_2_5_PRO.supports.input [GEMINI_2_5_FLASH_LITE.name]: typeof GEMINI_2_5_FLASH_LITE.supports.input [GEMINI_2_5_FLASH_LITE_PREVIEW.name]: typeof GEMINI_2_5_FLASH_LITE_PREVIEW.supports.input diff --git a/packages/typescript/ai-gemini/tests/model-meta.test.ts b/packages/typescript/ai-gemini/tests/model-meta.test.ts index dfe0750b..05a59ba4 100644 --- a/packages/typescript/ai-gemini/tests/model-meta.test.ts +++ b/packages/typescript/ai-gemini/tests/model-meta.test.ts @@ -60,6 +60,28 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf().toHaveProperty('responseSchema') }) + it('gemini-3-flash-preview should support thinking options', () => { + type Model = 'gemini-3-flash-preview' + type Options = GeminiChatModelProviderOptionsByName[Model] + + // Should have thinking options + expectTypeOf().toExtend() + + // Should have structured output options + expectTypeOf().toExtend() + + // Should have base options + expectTypeOf().toExtend() + + // Verify specific properties exist + expectTypeOf().toHaveProperty('generationConfig') + expectTypeOf().toHaveProperty('safetySettings') + expectTypeOf().toHaveProperty('toolConfig') + expectTypeOf().toHaveProperty('cachedContent') + expectTypeOf().toHaveProperty('responseMimeType') + expectTypeOf().toHaveProperty('responseSchema') + }) + it('gemini-2.5-pro should support thinking options', () => { type Model = 'gemini-2.5-pro' type Options = GeminiChatModelProviderOptionsByName[Model] @@ -172,6 +194,7 @@ describe('Gemini Model Provider Options Type Assertions', () => { type Keys = keyof GeminiChatModelProviderOptionsByName expectTypeOf<'gemini-3-pro-preview'>().toExtend() + expectTypeOf<'gemini-3-flash-preview'>().toExtend() expectTypeOf<'gemini-2.5-pro'>().toExtend() expectTypeOf<'gemini-2.5-flash'>().toExtend() expectTypeOf<'gemini-2.5-flash-preview-09-2025'>().toExtend() @@ -203,6 +226,9 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] >().toHaveProperty('safetySettings') + expectTypeOf< + GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] + >().toHaveProperty('safetySettings') expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toHaveProperty('safetySettings') @@ -230,6 +256,9 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] >().toHaveProperty('toolConfig') + expectTypeOf< + GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] + >().toHaveProperty('toolConfig') expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toHaveProperty('toolConfig') @@ -257,6 +286,9 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] >().toHaveProperty('cachedContent') + expectTypeOf< + GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] + >().toHaveProperty('cachedContent') expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toHaveProperty('cachedContent') @@ -286,6 +318,9 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] >().toExtend() + expectTypeOf< + GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] + >().toExtend() expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toExtend() @@ -316,6 +351,9 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] >().toExtend() + expectTypeOf< + GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] + >().toExtend() expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toExtend() @@ -375,6 +413,19 @@ describe('Gemini Model Input Modality Type Assertions', () => { }) }) + describe('gemini-3-flash-preview (full multimodal)', () => { + type Modalities = GeminiModelInputModalitiesByName['gemini-3-flash-preview'] + type Message = ConstrainedModelMessage + + it('should allow all content part types', () => { + expectTypeOf>().toExtend() + expectTypeOf>().toExtend() + expectTypeOf>().toExtend() + expectTypeOf>().toExtend() + expectTypeOf>().toExtend() + }) + }) + describe('gemini-2.5-pro (full multimodal)', () => { type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-pro'] type Message = ConstrainedModelMessage