diff --git a/.changeset/gemini-model-meta-refresh.md b/.changeset/gemini-model-meta-refresh.md new file mode 100644 index 000000000..4512dfefd --- /dev/null +++ b/.changeset/gemini-model-meta-refresh.md @@ -0,0 +1,23 @@ +--- +'@tanstack/ai-gemini': minor +--- + +Sync Gemini model metadata with Google's current published model list (#620, #621). + +**Added** + +- `gemini-3.1-flash-lite` (stable GA) — joins the existing `gemini-3.1-flash-lite-preview` entry and qualifies for the native combined tools + `responseSchema` streaming path (`GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS`). + +**Removed (retired by Google — these ids now 404 against the Gemini API or are no longer published)** + +- `gemini-3-pro-preview` (verified 404; superseded by `gemini-3.1-pro-preview`) +- `gemini-2.5-flash-preview-09-2025` (superseded by stable `gemini-2.5-flash`) +- `gemini-2.5-flash-lite-preview-09-2025` (superseded by stable `gemini-2.5-flash-lite`) +- `gemini-2.0-flash` and `gemini-2.0-flash-lite` (2.0 line retired from Google's published list) +- `gemini-2.0-flash-preview-image-generation` (image; superseded by `gemini-2.5-flash-image`) + +**Fixed** + +- `gemini-3.5-flash` was missing from `GeminiChatModelToolCapabilitiesByName`, leaving its provider-tool typing broken. + +If you were passing a removed id to `geminiText()` / `geminiSummarize()`, switch to the listed successor (e.g. `gemini-2.0-flash` → `gemini-2.5-flash`). diff --git a/docs/adapters/gemini.md b/docs/adapters/gemini.md index 4014a8810..42b766553 100644 --- a/docs/adapters/gemini.md +++ b/docs/adapters/gemini.md @@ -506,7 +506,6 @@ These models use the `generateContent` API and support resolution tiers (1K, 2K, | `gemini-3.1-flash-image-preview` | Latest and fastest Gemini native image generation | | `gemini-3-pro-image-preview` | Higher quality Gemini native image generation | | `gemini-2.5-flash-image` | Gemini 2.5 Flash with image generation | -| `gemini-2.0-flash-preview-image-generation` | Gemini 2.0 Flash image generation | ### Imagen Models diff --git a/docs/adapters/openrouter.md b/docs/adapters/openrouter.md index 3b86fc328..cd8984511 100644 --- a/docs/adapters/openrouter.md +++ b/docs/adapters/openrouter.md @@ -55,7 +55,7 @@ OpenRouter provides access to 300+ models from various providers. Models use the ```typescript model: "openai/gpt-5.1" model: "anthropic/claude-sonnet-4.5" -model: "google/gemini-3-pro-preview" +model: "google/gemini-3.1-pro-preview" model: "meta-llama/llama-4-maverick" model: "deepseek/deepseek-v3.2" ``` diff --git a/docs/advanced/multimodal-content.md b/docs/advanced/multimodal-content.md index eb68ebc7f..e42067a05 100644 --- a/docs/advanced/multimodal-content.md +++ b/docs/advanced/multimodal-content.md @@ -181,7 +181,7 @@ const message = { ``` **Supported modalities:** -- `gemini-2.0-flash`: text, image, audio, video +- `gemini-2.5-flash`: text, image, audio, video ### Ollama diff --git a/docs/media/image-generation.md b/docs/media/image-generation.md index d8af2e816..acebe00eb 100644 --- a/docs/media/image-generation.md +++ b/docs/media/image-generation.md @@ -233,7 +233,6 @@ interface GeneratedImage { | `gemini-3.1-flash-image-preview` | Latest and fastest Gemini native image generation | | `gemini-3-pro-image-preview` | Higher quality Gemini native image generation | | `gemini-2.5-flash-image` | Gemini 2.5 Flash with image generation | -| `gemini-2.0-flash-preview-image-generation` | Gemini 2.0 Flash image generation | ### Gemini Imagen Models diff --git a/examples/ts-react-chat/src/lib/model-selection.ts b/examples/ts-react-chat/src/lib/model-selection.ts index fdc9a8e1a..f3c66c32e 100644 --- a/examples/ts-react-chat/src/lib/model-selection.ts +++ b/examples/ts-react-chat/src/lib/model-selection.ts @@ -71,8 +71,8 @@ export const MODEL_OPTIONS: Array = [ }, { provider: 'gemini', - model: 'gemini-2.0-flash', - label: 'Gemini - 2.0 Flash', + model: 'gemini-2.5-flash', + label: 'Gemini - 2.5 Flash', }, // Gemini Interactions (stateful, experimental — `@tanstack/ai-gemini/experimental`) diff --git a/examples/ts-react-chat/src/routes/api.structured-output.ts b/examples/ts-react-chat/src/routes/api.structured-output.ts index dc3558a3f..501653a0b 100644 --- a/examples/ts-react-chat/src/routes/api.structured-output.ts +++ b/examples/ts-react-chat/src/routes/api.structured-output.ts @@ -159,8 +159,12 @@ function adapterFor(provider: Provider, model?: string): AnyTextAdapter { // `generateContentStream` call. Gemini 2.x is documented as brittle // for the combination and falls back to the engine's legacy // finalization path. + // + // Default is `gemini-3.5-flash`: the newest *stable* (non-preview) + // 3.x id, matching the dropdown's first entry. The previous default + // (`gemini-3-pro-preview`) was retired by Google and now 404s. return geminiText( - (baseModel || 'gemini-3-pro-preview') as 'gemini-3-pro-preview', + (baseModel || 'gemini-3.5-flash') as 'gemini-3.5-flash', ) case 'grok': return grokText( diff --git a/examples/ts-react-chat/src/routes/generations.structured-output.tsx b/examples/ts-react-chat/src/routes/generations.structured-output.tsx index 7a1d89245..478e5bb5b 100644 --- a/examples/ts-react-chat/src/routes/generations.structured-output.tsx +++ b/examples/ts-react-chat/src/routes/generations.structured-output.tsx @@ -77,16 +77,16 @@ const PROVIDER_MODELS: Record< // hit the engine's legacy finalization path instead. // // Naming gotcha: Google uses a dash separator for the major version - // (`gemini-3-pro-preview`) but a dot separator for the minor version + // (`gemini-3-flash-preview`) but a dot separator for the minor version // (`gemini-3.1-pro-preview`). The dropdown values mirror the canonical // ids from `ai-gemini/model-meta` — `GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS` // keys on the exact string, so any drift here silently breaks // combined-mode routing. gemini: [ { value: 'gemini-3.5-flash', label: 'Gemini 3.5 Flash' }, - { value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro (Preview)' }, { value: 'gemini-3-flash-preview', label: 'Gemini 3 Flash (Preview)' }, { value: 'gemini-3.1-pro-preview', label: 'Gemini 3.1 Pro (Preview)' }, + { value: 'gemini-3.1-flash-lite', label: 'Gemini 3.1 Flash Lite' }, { value: 'gemini-3.1-flash-lite-preview', label: 'Gemini 3.1 Flash Lite (Preview)', diff --git a/examples/ts-svelte-chat/src/lib/model-selection.ts b/examples/ts-svelte-chat/src/lib/model-selection.ts index 0f66fb3fc..e7558d30c 100644 --- a/examples/ts-svelte-chat/src/lib/model-selection.ts +++ b/examples/ts-svelte-chat/src/lib/model-selection.ts @@ -30,11 +30,6 @@ export const MODEL_OPTIONS: Array = [ }, // Gemini - { - provider: 'gemini', - model: 'gemini-2.0-flash', - label: 'Gemini - 2.0 Flash', - }, { provider: 'gemini', model: 'gemini-2.5-flash', diff --git a/examples/ts-svelte-chat/src/routes/api/chat/+server.ts b/examples/ts-svelte-chat/src/routes/api/chat/+server.ts index 523add1fc..ef57f8738 100644 --- a/examples/ts-svelte-chat/src/routes/api/chat/+server.ts +++ b/examples/ts-svelte-chat/src/routes/api/chat/+server.ts @@ -39,7 +39,7 @@ const adapterConfig = { }), gemini: () => createChatOptions({ - adapter: geminiText('gemini-2.0-flash'), + adapter: geminiText('gemini-2.5-flash'), }), ollama: () => createChatOptions({ diff --git a/examples/ts-vue-chat/src/lib/model-selection.ts b/examples/ts-vue-chat/src/lib/model-selection.ts index 0f66fb3fc..e7558d30c 100644 --- a/examples/ts-vue-chat/src/lib/model-selection.ts +++ b/examples/ts-vue-chat/src/lib/model-selection.ts @@ -30,11 +30,6 @@ export const MODEL_OPTIONS: Array = [ }, // Gemini - { - provider: 'gemini', - model: 'gemini-2.0-flash', - label: 'Gemini - 2.0 Flash', - }, { provider: 'gemini', model: 'gemini-2.5-flash', diff --git a/examples/ts-vue-chat/vite.config.ts b/examples/ts-vue-chat/vite.config.ts index 42140d0a2..f4ed32581 100644 --- a/examples/ts-vue-chat/vite.config.ts +++ b/examples/ts-vue-chat/vite.config.ts @@ -230,7 +230,7 @@ export default defineConfig({ adapter = anthropicText(selectedModel) break case 'gemini': - selectedModel = model || 'gemini-2.0-flash' + selectedModel = model || 'gemini-2.5-flash' adapter = geminiText(selectedModel) break case 'ollama': diff --git a/packages/ai-code-mode-skills/test-cli/adapters.ts b/packages/ai-code-mode-skills/test-cli/adapters.ts index f24c06a02..5fe4936df 100644 --- a/packages/ai-code-mode-skills/test-cli/adapters.ts +++ b/packages/ai-code-mode-skills/test-cli/adapters.ts @@ -32,7 +32,7 @@ export interface AdapterDefinition { const OPENAI_MODEL = process.env.OPENAI_MODEL || 'gpt-4o' const ANTHROPIC_MODEL = process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-20250514' -const GEMINI_MODEL = process.env.GEMINI_MODEL || 'gemini-2.0-flash' +const GEMINI_MODEL = process.env.GEMINI_MODEL || 'gemini-2.5-flash' /** * Create OpenAI adapter diff --git a/packages/ai-code-mode-skills/test-cli/cli.ts b/packages/ai-code-mode-skills/test-cli/cli.ts index f4275dc87..44fef8407 100644 --- a/packages/ai-code-mode-skills/test-cli/cli.ts +++ b/packages/ai-code-mode-skills/test-cli/cli.ts @@ -606,7 +606,7 @@ program try { const { geminiText } = await import('@tanstack/ai-gemini') - const modelName = model || 'gemini-2.0-flash' + const modelName = model || 'gemini-2.5-flash' adapter = geminiText(modelName, { apiKey }) logInfo(`Using Gemini adapter with model: ${modelName}`) } catch (error) { @@ -721,7 +721,7 @@ program try { const { geminiText } = await import('@tanstack/ai-gemini') - const modelName = model || 'gemini-2.0-flash' + const modelName = model || 'gemini-2.5-flash' adapter = geminiText(modelName, { apiKey }) logInfo(`Using Gemini adapter with model: ${modelName}`) } catch (error) { diff --git a/packages/ai-gemini/src/adapters/summarize.ts b/packages/ai-gemini/src/adapters/summarize.ts index 74c653a93..f94d26e08 100644 --- a/packages/ai-gemini/src/adapters/summarize.ts +++ b/packages/ai-gemini/src/adapters/summarize.ts @@ -20,7 +20,7 @@ export type GeminiSummarizeModel = (typeof GEMINI_MODELS)[number] * * @example * ```typescript - * const adapter = createGeminiSummarize('AIza...', 'gemini-2.0-flash'); + * const adapter = createGeminiSummarize('AIza...', 'gemini-2.5-flash'); * ``` */ export function createGeminiSummarize( @@ -44,7 +44,7 @@ export function createGeminiSummarize( * * @example * ```typescript - * const adapter = geminiSummarize('gemini-2.0-flash'); + * const adapter = geminiSummarize('gemini-2.5-flash'); * await summarize({ adapter, text: 'Long article text...' }); * ``` */ diff --git a/packages/ai-gemini/src/image/image-provider-options.ts b/packages/ai-gemini/src/image/image-provider-options.ts index a94f414f7..62a933445 100644 --- a/packages/ai-gemini/src/image/image-provider-options.ts +++ b/packages/ai-gemini/src/image/image-provider-options.ts @@ -178,7 +178,6 @@ export type GeminiNativeImageModels = | 'gemini-3.1-flash-image-preview' | 'gemini-3-pro-image-preview' | 'gemini-2.5-flash-image' - | 'gemini-2.0-flash-preview-image-generation' /** * Model-specific size options mapping. diff --git a/packages/ai-gemini/src/model-meta.ts b/packages/ai-gemini/src/model-meta.ts index 886959d95..610bd2ef6 100644 --- a/packages/ai-gemini/src/model-meta.ts +++ b/packages/ai-gemini/src/model-meta.ts @@ -83,8 +83,8 @@ const GEMINI_3_1_PRO = { GeminiThinkingOptions > -const GEMINI_3_PRO = { - name: 'gemini-3-pro-preview', +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', @@ -102,10 +102,10 @@ const GEMINI_3_PRO = { }, pricing: { input: { - normal: 2.5, + normal: 0.5, }, output: { - normal: 15, + normal: 3, }, }, } as const satisfies ModelMeta< @@ -117,29 +117,23 @@ 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, +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', 'audio', 'video', 'document'], - output: ['text'], - capabilities: [ - 'batch_api', - 'caching', - 'function_calling', - 'structured_output', - 'thinking', - ], - tools: ['code_execution', 'file_search', 'google_search', 'url_context'], + input: ['text', 'image'], + output: ['text', 'image'], + capabilities: ['batch_api', 'structured_output', 'thinking'], + tools: ['google_search'], }, pricing: { input: { - normal: 0.5, + normal: 2, }, output: { - normal: 3, + normal: 0.134, }, }, } as const satisfies ModelMeta< @@ -151,10 +145,10 @@ const GEMINI_3_FLASH = { GeminiThinkingOptions > -const GEMINI_3_PRO_IMAGE = { - name: 'gemini-3-pro-image-preview', +const GEMINI_3_1_FLASH_IMAGE = { + name: 'gemini-3.1-flash-image-preview', max_input_tokens: 65_536, - max_output_tokens: 32_768, + max_output_tokens: 65_536, knowledge_cutoff: '2025-01-01', supports: { input: ['text', 'image'], @@ -164,10 +158,10 @@ const GEMINI_3_PRO_IMAGE = { }, pricing: { input: { - normal: 2, + normal: 0.25, }, output: { - normal: 0.134, + normal: 1.5, }, }, } as const satisfies ModelMeta< @@ -179,16 +173,22 @@ const GEMINI_3_PRO_IMAGE = { GeminiThinkingOptions > -const GEMINI_3_1_FLASH_IMAGE = { - name: 'gemini-3.1-flash-image-preview', - max_input_tokens: 65_536, +const GEMINI_3_1_FLASH_LITE = { + name: 'gemini-3.1-flash-lite', + max_input_tokens: 1_048_576, max_output_tokens: 65_536, knowledge_cutoff: '2025-01-01', supports: { - input: ['text', 'image'], - output: ['text', 'image'], - capabilities: ['batch_api', 'structured_output', 'thinking'], - tools: ['google_search'], + input: ['text', 'image', 'audio', 'video', 'document'], + output: ['text'], + capabilities: [ + 'batch_api', + 'caching', + 'function_calling', + 'structured_output', + 'thinking', + ], + tools: ['code_execution', 'file_search', 'google_search', 'url_context'], }, pricing: { input: { @@ -207,7 +207,7 @@ const GEMINI_3_1_FLASH_IMAGE = { GeminiThinkingOptions > -const GEMINI_3_1_FLASH_LITE = { +const GEMINI_3_1_FLASH_LITE_PREVIEW = { name: 'gemini-3.1-flash-lite-preview', max_input_tokens: 1_048_576, max_output_tokens: 65_536, @@ -346,40 +346,6 @@ const GEMINI_2_5_FLASH = { GeminiThinkingOptions > -const GEMINI_2_5_FLASH_PREVIEW = { - name: 'gemini-2.5-flash-preview-09-2025', - max_input_tokens: 1_048_576, - max_output_tokens: 65_536, - knowledge_cutoff: '2025-01-01', - supports: { - input: ['text', 'image', 'audio', 'video'], - output: ['text'], - capabilities: [ - 'batch_api', - 'caching', - 'function_calling', - 'structured_output', - 'thinking', - ], - tools: ['code_execution', 'file_search', 'google_search', 'url_context'], - }, - pricing: { - input: { - normal: 1, - }, - output: { - normal: 2.5, - }, - }, -} as const satisfies ModelMeta< - GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions & - GeminiThinkingOptions -> - const GEMINI_2_5_FLASH_IMAGE = { name: 'gemini-2.5-flash-image', max_input_tokens: 1_048_576, @@ -575,165 +541,6 @@ const GEMINI_2_5_FLASH_LITE = { GeminiThinkingOptions > -const GEMINI_2_5_FLASH_LITE_PREVIEW = { - name: 'gemini-2.5-flash-lite-preview-09-2025', - 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', - 'function_calling', - 'structured_output', - 'thinking', - ], - tools: ['code_execution', 'google_search', 'url_context'], - }, - pricing: { - input: { - normal: 0.1, - }, - output: { - normal: 0.4, - }, - }, -} as const satisfies ModelMeta< - GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions & - GeminiThinkingOptions -> - -const GEMINI_2_FLASH = { - name: 'gemini-2.0-flash', - max_input_tokens: 1_048_576, - max_output_tokens: 8_192, - knowledge_cutoff: '2024-08-01', - supports: { - input: ['text', 'image', 'audio', 'video'], - output: ['text'], - capabilities: [ - 'batch_api', - 'caching', - 'function_calling', - 'live_api', - 'structured_output', - ], - tools: ['code_execution', 'google_maps', 'google_search'], - }, - pricing: { - input: { - normal: 0.1, - }, - output: { - normal: 0.4, - }, - }, -} as const satisfies ModelMeta< - GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions -> - -const GEMINI_2_FLASH_IMAGE = { - name: 'gemini-2.0-flash-preview-image-generation', - max_input_tokens: 32_768, - max_output_tokens: 8_192, - knowledge_cutoff: '2024-08-01', - supports: { - input: ['text', 'image', 'audio', 'video'], - output: ['text', 'image'], - capabilities: ['batch_api', 'caching', 'structured_output'], - tools: [], - }, - pricing: { - input: { - normal: 0.1, - }, - output: { - normal: 0.039, - }, - }, -} as const satisfies ModelMeta< - GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions -> -/* -const GEMINI_2_FLASH_LIVE = { - name: 'gemini-2.0-flash-live-001', - max_input_tokens: 1_048_576, - max_output_tokens: 8_192, - knowledge_cutoff: '2024-08-01', - supports: { - input: ['text', 'audio', 'video'], - output: ['text', 'audio'], - capabilities: [ - 'audio_generation', - 'code_execution', - 'function_calling', - 'live_api', - 'search_grounding', - 'structured_output', - 'url_context', - ], - }, - pricing: { - // todo find this info - input: { - normal: 0, - }, - output: { - normal: 0, - }, - }, -} as const satisfies ModelMeta< - GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiGenerationConfigOptions & - GeminiCachedContentOptions -> */ - -const GEMINI_2_FLASH_LITE = { - name: 'gemini-2.0-flash-lite', - max_input_tokens: 1_048_576, - max_output_tokens: 8_192, - knowledge_cutoff: '2024-08-01', - supports: { - input: ['text', 'audio', 'video', 'image'], - output: ['text'], - capabilities: [ - 'batch_api', - 'caching', - 'function_calling', - 'structured_output', - ], - tools: [], - }, - pricing: { - input: { - normal: 0.075, - }, - output: { - normal: 0.3, - }, - }, -} as const satisfies ModelMeta< - GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions -> - const IMAGEN_4_GENERATE = { name: 'imagen-4.0-generate-001', max_input_tokens: 480, @@ -939,32 +746,6 @@ const VEO_2 = { GeminiCachedContentOptions > */ -/* const GEMINI_MODEL_META = { - [GEMINI_3_PRO.name]: GEMINI_3_PRO, - [GEMINI_2_5_PRO.name]: GEMINI_2_5_PRO, - [GEMINI_2_5_PRO_TTS.name]: GEMINI_2_5_PRO_TTS, - [GEMINI_2_5_FLASH.name]: GEMINI_2_5_FLASH, - [GEMINI_2_5_FLASH_PREVIEW.name]: GEMINI_2_5_FLASH_PREVIEW, - [GEMINI_2_5_FLASH_IMAGE.name]: GEMINI_2_5_FLASH_IMAGE, - [GEMINI_2_5_FLASH_LIVE.name]: GEMINI_2_5_FLASH_LIVE, - [GEMINI_2_5_FLASH_TTS.name]: GEMINI_2_5_FLASH_TTS, - [GEMINI_2_5_FLASH_LITE.name]: GEMINI_2_5_FLASH_LITE, - [GEMINI_2_5_FLASH_LITE_PREVIEW.name]: GEMINI_2_5_FLASH_LITE_PREVIEW, - [GEMINI_2_FLASH.name]: GEMINI_2_FLASH, - [GEMINI_2_FLASH_IMAGE.name]: GEMINI_2_FLASH_IMAGE, - [GEMINI_2_FLASH_LIVE.name]: GEMINI_2_FLASH_LIVE, - [GEMINI_2_FLASH_LITE.name]: GEMINI_2_FLASH_LITE, - [IMAGEN_4_GENERATE.name]: IMAGEN_4_GENERATE, - [IMAGEN_4_GENERATE_ULTRA.name]: IMAGEN_4_GENERATE_ULTRA, - [IMAGEN_4_GENERATE_FAST.name]: IMAGEN_4_GENERATE_FAST, - [IMAGEN_3.name]: IMAGEN_3, - [VEO_3_1_PREVIEW.name]: VEO_3_1_PREVIEW, - [VEO_3_1_FAST_PREVIEW.name]: VEO_3_1_FAST_PREVIEW, - [VEO_3.name]: VEO_3, - [VEO_3_FAST.name]: VEO_3_FAST, - [VEO_2.name]: VEO_2, -} as const */ - const GEMINI_3_5_FLASH = { name: 'gemini-3.5-flash', max_input_tokens: 1_048_576, @@ -1000,19 +781,14 @@ const GEMINI_3_5_FLASH = { > export const GEMINI_MODELS = [ + GEMINI_3_5_FLASH.name, GEMINI_3_1_PRO.name, - GEMINI_3_PRO.name, GEMINI_3_FLASH.name, GEMINI_3_1_FLASH_LITE.name, + GEMINI_3_1_FLASH_LITE_PREVIEW.name, GEMINI_2_5_PRO.name, GEMINI_2_5_FLASH.name, - GEMINI_2_5_FLASH_PREVIEW.name, GEMINI_2_5_FLASH_LITE.name, - GEMINI_2_5_FLASH_LITE_PREVIEW.name, - GEMINI_2_FLASH.name, - GEMINI_2_FLASH_LITE.name, - - GEMINI_3_5_FLASH.name, ] as const /** @@ -1024,9 +800,9 @@ export const GEMINI_MODELS = [ */ export const GEMINI_COMBINED_TOOLS_AND_SCHEMA_MODELS = new Set([ GEMINI_3_1_PRO.name, - GEMINI_3_PRO.name, GEMINI_3_FLASH.name, GEMINI_3_1_FLASH_LITE.name, + GEMINI_3_1_FLASH_LITE_PREVIEW.name, GEMINI_3_5_FLASH.name, ]) @@ -1038,7 +814,6 @@ export const GEMINI_IMAGE_MODELS = [ GEMINI_3_1_FLASH_IMAGE.name, GEMINI_3_PRO_IMAGE.name, GEMINI_2_5_FLASH_IMAGE.name, - GEMINI_2_FLASH_IMAGE.name, IMAGEN_3.name, IMAGEN_4_GENERATE.name, IMAGEN_4_GENERATE_FAST.name, @@ -1127,12 +902,6 @@ export type GeminiChatModelProviderOptionsByName = { GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions - [GEMINI_3_PRO.name]: GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions & - GeminiThinkingOptions [GEMINI_3_FLASH.name]: GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & @@ -1145,19 +914,19 @@ export type GeminiChatModelProviderOptionsByName = { GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions - [GEMINI_2_5_PRO.name]: GeminiToolConfigOptions & + [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions - [GEMINI_2_5_FLASH.name]: GeminiToolConfigOptions & + [GEMINI_2_5_PRO.name]: GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions - [GEMINI_2_5_FLASH_PREVIEW.name]: GeminiToolConfigOptions & + [GEMINI_2_5_FLASH.name]: GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & @@ -1169,23 +938,6 @@ export type GeminiChatModelProviderOptionsByName = { GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions - [GEMINI_2_5_FLASH_LITE_PREVIEW.name]: GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions & - GeminiThinkingOptions - // Models with structured output but no thinking support - [GEMINI_2_FLASH.name]: GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions - [GEMINI_2_FLASH_LITE.name]: GeminiToolConfigOptions & - GeminiSafetyOptions & - GeminiCommonConfigOptions & - GeminiCachedContentOptions & - GeminiStructuredOutputOptions [GEMINI_3_5_FLASH.name]: GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & @@ -1200,16 +952,13 @@ export type GeminiChatModelProviderOptionsByName = { */ export type GeminiChatModelToolCapabilitiesByName = { [GEMINI_3_1_PRO.name]: typeof GEMINI_3_1_PRO.supports.tools - [GEMINI_3_PRO.name]: typeof GEMINI_3_PRO.supports.tools [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.tools [GEMINI_3_1_FLASH_LITE.name]: typeof GEMINI_3_1_FLASH_LITE.supports.tools + [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: typeof GEMINI_3_1_FLASH_LITE_PREVIEW.supports.tools [GEMINI_2_5_PRO.name]: typeof GEMINI_2_5_PRO.supports.tools [GEMINI_2_5_FLASH.name]: typeof GEMINI_2_5_FLASH.supports.tools - [GEMINI_2_5_FLASH_PREVIEW.name]: typeof GEMINI_2_5_FLASH_PREVIEW.supports.tools [GEMINI_2_5_FLASH_LITE.name]: typeof GEMINI_2_5_FLASH_LITE.supports.tools - [GEMINI_2_5_FLASH_LITE_PREVIEW.name]: typeof GEMINI_2_5_FLASH_LITE_PREVIEW.supports.tools - [GEMINI_2_FLASH.name]: typeof GEMINI_2_FLASH.supports.tools - [GEMINI_2_FLASH_LITE.name]: typeof GEMINI_2_FLASH_LITE.supports.tools + [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.tools } /** @@ -1228,17 +977,13 @@ export type GeminiChatModelToolCapabilitiesByName = { export type GeminiModelInputModalitiesByName = { // Models with full multimodal support (text, image, audio, video, document) [GEMINI_3_1_PRO.name]: typeof GEMINI_3_1_PRO.supports.input - [GEMINI_3_PRO.name]: typeof GEMINI_3_PRO.supports.input [GEMINI_3_FLASH.name]: typeof GEMINI_3_FLASH.supports.input [GEMINI_3_1_FLASH_LITE.name]: typeof GEMINI_3_1_FLASH_LITE.supports.input + [GEMINI_3_1_FLASH_LITE_PREVIEW.name]: typeof GEMINI_3_1_FLASH_LITE_PREVIEW.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 + [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.input // Models with text, image, audio, video (no document) [GEMINI_2_5_FLASH.name]: typeof GEMINI_2_5_FLASH.supports.input - [GEMINI_2_5_FLASH_PREVIEW.name]: typeof GEMINI_2_5_FLASH_PREVIEW.supports.input - [GEMINI_2_FLASH.name]: typeof GEMINI_2_FLASH.supports.input - [GEMINI_2_FLASH_LITE.name]: typeof GEMINI_2_FLASH_LITE.supports.input - [GEMINI_3_5_FLASH.name]: typeof GEMINI_3_5_FLASH.supports.input } diff --git a/packages/ai-gemini/tests/chat-per-model-type-safety.test.ts b/packages/ai-gemini/tests/chat-per-model-type-safety.test.ts index 40e80e903..4ec94085a 100644 --- a/packages/ai-gemini/tests/chat-per-model-type-safety.test.ts +++ b/packages/ai-gemini/tests/chat-per-model-type-safety.test.ts @@ -79,40 +79,20 @@ describe('Gemini per-model chat modelOptions gating', () => { }) }) - describe('gemini-2.0-flash — structured output, NO thinking at all', () => { - it('accepts base + structured-output options', () => { + describe('gemini-3.1-flash-lite — stable id, thinking + structured output', () => { + it('accepts base + thinking + structured-output options', () => { chat({ - adapter: geminiText('gemini-2.0-flash'), + adapter: geminiText('gemini-3.1-flash-lite'), messages: [{ role: 'user', content: 'hi' }], modelOptions: { stopSequences: ['STOP'], topK: 5, cachedContent: 'cachedContents/abc', responseMimeType: 'application/json', - }, - }) - }) - - it('rejects thinkingConfig option', () => { - chat({ - adapter: geminiText('gemini-2.0-flash'), - messages: [{ role: 'user', content: 'hi' }], - modelOptions: { - // @ts-expect-error - 'thinkingConfig' is not available on gemini-2.0-flash - thinkingConfig: { includeThoughts: true }, - }, - }) - }) - }) - - describe('gemini-2.0-flash-lite — structured output, NO thinking at all', () => { - it('rejects thinkingConfig option', () => { - chat({ - adapter: geminiText('gemini-2.0-flash-lite'), - messages: [{ role: 'user', content: 'hi' }], - modelOptions: { - // @ts-expect-error - 'thinkingConfig' is not available on gemini-2.0-flash-lite - thinkingConfig: { includeThoughts: true }, + thinkingConfig: { + includeThoughts: true, + thinkingBudget: 512, + }, }, }) }) @@ -136,6 +116,15 @@ describe('Gemini per-model chat modelOptions gating', () => { // @ts-expect-error - 'gemini-fake-9000' is not a valid Gemini chat model geminiText('gemini-fake-9000') }) + + it('rejects retired model ids at the factory', () => { + // @ts-expect-error - 'gemini-3-pro-preview' was retired by Google + geminiText('gemini-3-pro-preview') + // @ts-expect-error - 'gemini-2.0-flash' was retired by Google + geminiText('gemini-2.0-flash') + // @ts-expect-error - 'gemini-2.0-flash-lite' was retired by Google + geminiText('gemini-2.0-flash-lite') + }) }) }) @@ -176,11 +165,11 @@ describe('Gemini provider options shape assertions', () => { }) }) - describe('gemini-2.0-flash — no thinking', () => { - type Options = GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] + describe('gemini-3.1-flash-lite — stable id mirrors the preview feature set', () => { + type Options = GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite'] - it('does NOT have thinkingConfig', () => { - expectTypeOf().not.toHaveProperty('thinkingConfig') + it('has thinkingConfig', () => { + expectTypeOf().toHaveProperty('thinkingConfig') }) it('has responseMimeType (structured output)', () => { expectTypeOf().toHaveProperty('responseMimeType') @@ -192,15 +181,4 @@ describe('Gemini provider options shape assertions', () => { expectTypeOf().toHaveProperty('cachedContent') }) }) - - describe('gemini-2.0-flash-lite — no thinking', () => { - type Options = GeminiChatModelProviderOptionsByName['gemini-2.0-flash-lite'] - - it('does NOT have thinkingConfig', () => { - expectTypeOf().not.toHaveProperty('thinkingConfig') - }) - it('has responseMimeType', () => { - expectTypeOf().toHaveProperty('responseMimeType') - }) - }) }) diff --git a/packages/ai-gemini/tests/gemini-adapter.test.ts b/packages/ai-gemini/tests/gemini-adapter.test.ts index 3e85bf982..63ac9d6cc 100644 --- a/packages/ai-gemini/tests/gemini-adapter.test.ts +++ b/packages/ai-gemini/tests/gemini-adapter.test.ts @@ -54,7 +54,7 @@ vi.mock('@google/genai', async () => { const createTextAdapter = () => new GeminiTextAdapter({ apiKey: 'test-key' }, 'gemini-2.5-pro') const createSummarizeAdapter = () => - createGeminiSummarize('test-key', 'gemini-2.0-flash') + createGeminiSummarize('test-key', 'gemini-2.5-flash') const weatherTool: Tool = { name: 'lookup_weather', @@ -859,7 +859,7 @@ describe('GeminiAdapter through AI', () => { const adapter = new GeminiTextAdapter( { apiKey: 'test-key' }, - 'gemini-3-pro-preview', + 'gemini-3.1-pro-preview', ) expect(adapter.supportsCombinedToolsAndSchema()).toBe(true) @@ -879,7 +879,7 @@ describe('GeminiAdapter through AI', () => { expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1) const [payload] = mocks.generateContentStreamSpy.mock.calls[0]! - expect(payload.model).toBe('gemini-3-pro-preview') + expect(payload.model).toBe('gemini-3.1-pro-preview') expect(payload.config).toMatchObject({ responseMimeType: 'application/json', responseSchema: expect.objectContaining({ type: 'object' }), @@ -933,7 +933,7 @@ describe('GeminiAdapter through AI', () => { expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1) const [payload] = mocks.generateContentStreamSpy.mock.calls[0]! - expect(payload.model).toBe('gemini-2.0-flash') + expect(payload.model).toBe('gemini-2.5-flash') expect(payload.config.systemInstruction).toContain( 'professional summarizer', ) diff --git a/packages/ai-gemini/tests/model-meta.test.ts b/packages/ai-gemini/tests/model-meta.test.ts index 1741568e6..6ae0fbf6f 100644 --- a/packages/ai-gemini/tests/model-meta.test.ts +++ b/packages/ai-gemini/tests/model-meta.test.ts @@ -36,9 +36,12 @@ type MakeInputModalitiesTypes> = { * * These tests verify that: * 1. Models with thinking support have GeminiThinkingOptions in their provider options - * 2. Models without thinking support do NOT have GeminiThinkingOptions - * 3. Models with structured output support have GeminiStructuredOutputOptions - * 4. All models have base options (tool config, safety, generation config, cached content) + * 2. Models with structured output support have GeminiStructuredOutputOptions + * 3. All models have base options (tool config, safety, generation config, cached content) + * + * Note: every current chat model (Gemini 2.5+ / 3.x) supports thinking, so + * there is no longer a "without thinking" category — the retired 2.0 line + * was the last one without it. */ // Base options that ALL chat models should have @@ -49,8 +52,8 @@ type BaseOptions = GeminiToolConfigOptions & describe('Gemini Model Provider Options Type Assertions', () => { describe('Models WITH thinking support', () => { - it('gemini-3-pro-preview should support thinking options', () => { - type Model = 'gemini-3-pro-preview' + it('gemini-3.1-pro-preview should support thinking options', () => { + type Model = 'gemini-3.1-pro-preview' type Options = GeminiChatModelProviderOptionsByName[Model] // Should have thinking options @@ -121,20 +124,6 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf().toExtend() }) - it('gemini-2.5-flash-preview-09-2025 should support thinking options', () => { - type Model = 'gemini-2.5-flash-preview-09-2025' - type Options = GeminiChatModelProviderOptionsByName[Model] - - // Should have thinking options - expectTypeOf().toExtend() - - // Should have structured output options - expectTypeOf().toExtend() - - // Should have base options - expectTypeOf().toExtend() - }) - it('gemini-2.5-flash-lite should support thinking options', () => { type Model = 'gemini-2.5-flash-lite' type Options = GeminiChatModelProviderOptionsByName[Model] @@ -149,8 +138,8 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf().toExtend() }) - it('gemini-2.5-flash-lite-preview-09-2025 should support thinking options', () => { - type Model = 'gemini-2.5-flash-lite-preview-09-2025' + it('gemini-3.1-flash-lite should support thinking options', () => { + type Model = 'gemini-3.1-flash-lite' type Options = GeminiChatModelProviderOptionsByName[Model] // Should have thinking options @@ -161,6 +150,14 @@ describe('Gemini Model Provider Options Type Assertions', () => { // Should have base options expectTypeOf().toExtend() + + // Verify specific properties exist + expectTypeOf().toHaveProperty('stopSequences') + expectTypeOf().toHaveProperty('safetySettings') + expectTypeOf().toHaveProperty('toolConfig') + expectTypeOf().toHaveProperty('cachedContent') + expectTypeOf().toHaveProperty('responseMimeType') + expectTypeOf().toHaveProperty('responseSchema') }) it('gemini-3.1-flash-lite-preview should support thinking options', () => { @@ -184,34 +181,13 @@ describe('Gemini Model Provider Options Type Assertions', () => { expectTypeOf().toHaveProperty('responseMimeType') expectTypeOf().toHaveProperty('responseSchema') }) - }) - - describe('Models WITHOUT thinking support', () => { - it('gemini-2.0-flash should NOT have thinking options in type definition', () => { - type Model = 'gemini-2.0-flash' - type Options = GeminiChatModelProviderOptionsByName[Model] - - // Should NOT have thinking options - verify it's not assignable - // GeminiThinkingOptions has generationConfig.thinkingConfig which should not exist - expectTypeOf().not.toExtend() - - // Should have structured output options - expectTypeOf().toExtend() - - // Should have base options - expectTypeOf().toExtend() - - // Verify specific properties exist for structured output - expectTypeOf().toHaveProperty('responseMimeType') - expectTypeOf().toHaveProperty('responseSchema') - }) - it('gemini-2.0-flash-lite should NOT have thinking options in type definition', () => { - type Model = 'gemini-2.0-flash-lite' + it('gemini-3.5-flash should support thinking options', () => { + type Model = 'gemini-3.5-flash' type Options = GeminiChatModelProviderOptionsByName[Model] - // Should NOT have thinking options - expectTypeOf().not.toExtend() + // Should have thinking options + expectTypeOf().toExtend() // Should have structured output options expectTypeOf().toExtend() @@ -226,16 +202,24 @@ describe('Gemini Model Provider Options Type Assertions', () => { // Verify the type map has all expected model keys type Keys = keyof GeminiChatModelProviderOptionsByName - expectTypeOf<'gemini-3-pro-preview'>().toExtend() + expectTypeOf<'gemini-3.1-pro-preview'>().toExtend() expectTypeOf<'gemini-3-flash-preview'>().toExtend() + expectTypeOf<'gemini-3.1-flash-lite'>().toExtend() expectTypeOf<'gemini-3.1-flash-lite-preview'>().toExtend() expectTypeOf<'gemini-2.5-pro'>().toExtend() expectTypeOf<'gemini-2.5-flash'>().toExtend() - expectTypeOf<'gemini-2.5-flash-preview-09-2025'>().toExtend() expectTypeOf<'gemini-2.5-flash-lite'>().toExtend() - expectTypeOf<'gemini-2.5-flash-lite-preview-09-2025'>().toExtend() - expectTypeOf<'gemini-2.0-flash'>().toExtend() - expectTypeOf<'gemini-2.0-flash-lite'>().toExtend() + expectTypeOf<'gemini-3.5-flash'>().toExtend() + }) + + it('GeminiChatModelProviderOptionsByName should NOT have entries for retired models', () => { + type Keys = keyof GeminiChatModelProviderOptionsByName + + expectTypeOf<'gemini-3-pro-preview'>().not.toExtend() + expectTypeOf<'gemini-2.5-flash-preview-09-2025'>().not.toExtend() + expectTypeOf<'gemini-2.5-flash-lite-preview-09-2025'>().not.toExtend() + expectTypeOf<'gemini-2.0-flash'>().not.toExtend() + expectTypeOf<'gemini-2.0-flash-lite'>().not.toExtend() }) }) @@ -249,7 +233,7 @@ describe('Gemini Model Provider Options Type Assertions', () => { }) it('structured output options should have responseMimeType and responseSchema', () => { - type Options = GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] + type Options = GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] expectTypeOf().toHaveProperty('responseMimeType') expectTypeOf().toHaveProperty('responseSchema') @@ -258,100 +242,82 @@ describe('Gemini Model Provider Options Type Assertions', () => { it('all models should have safety settings', () => { expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] + GeminiChatModelProviderOptionsByName['gemini-3.1-pro-preview'] >().toHaveProperty('safetySettings') expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] >().toHaveProperty('safetySettings') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] - >().toHaveProperty('safetySettings') - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] - >().toHaveProperty('safetySettings') - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite'] >().toHaveProperty('safetySettings') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] >().toHaveProperty('safetySettings') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toHaveProperty('safetySettings') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] >().toHaveProperty('safetySettings') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] >().toHaveProperty('safetySettings') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.5-flash'] >().toHaveProperty('safetySettings') }) it('all models should have tool config', () => { expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] + GeminiChatModelProviderOptionsByName['gemini-3.1-pro-preview'] >().toHaveProperty('toolConfig') expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] >().toHaveProperty('toolConfig') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] - >().toHaveProperty('toolConfig') - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite'] >().toHaveProperty('toolConfig') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-preview-09-2025'] - >().toHaveProperty('toolConfig') - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] >().toHaveProperty('toolConfig') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toHaveProperty('toolConfig') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] >().toHaveProperty('toolConfig') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] >().toHaveProperty('toolConfig') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.5-flash'] >().toHaveProperty('toolConfig') }) it('all models should have cached content option', () => { expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] + GeminiChatModelProviderOptionsByName['gemini-3.1-pro-preview'] >().toHaveProperty('cachedContent') expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] >().toHaveProperty('cachedContent') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] - >().toHaveProperty('cachedContent') - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] - >().toHaveProperty('cachedContent') - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite'] >().toHaveProperty('cachedContent') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] >().toHaveProperty('cachedContent') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toHaveProperty('cachedContent') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] >().toHaveProperty('cachedContent') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] >().toHaveProperty('cachedContent') expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.5-flash'] >().toHaveProperty('cachedContent') }) }) @@ -359,70 +325,55 @@ describe('Gemini Model Provider Options Type Assertions', () => { describe('Type discrimination between model categories', () => { it('models with thinking should extend GeminiThinkingOptions', () => { expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] + GeminiChatModelProviderOptionsByName['gemini-3.1-pro-preview'] >().toExtend() expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] + GeminiChatModelProviderOptionsByName['gemini-3.5-flash'] >().toExtend() }) - it('models without thinking should NOT extend GeminiThinkingOptions', () => { - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] - >().not.toExtend() - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash-lite'] - >().not.toExtend() - }) - it('all models should extend GeminiStructuredOutputOptions', () => { expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3-pro-preview'] + GeminiChatModelProviderOptionsByName['gemini-3.1-pro-preview'] >().toExtend() expectTypeOf< GeminiChatModelProviderOptionsByName['gemini-3-flash-preview'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] - >().toExtend() - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] - >().toExtend() - expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite-preview-09-2025'] + GeminiChatModelProviderOptionsByName['gemini-2.5-pro'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-3.1-flash-lite-preview'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash'] + GeminiChatModelProviderOptionsByName['gemini-2.5-flash-lite'] >().toExtend() expectTypeOf< - GeminiChatModelProviderOptionsByName['gemini-2.0-flash-lite'] + GeminiChatModelProviderOptionsByName['gemini-3.5-flash'] >().toExtend() }) }) @@ -435,15 +386,15 @@ describe('Gemini Model Provider Options Type Assertions', () => { * content parts based on each Gemini model's supported input modalities. * * Models with full multimodal (text + image + audio + video + document): - * - gemini-3-pro-preview + * - gemini-3.1-pro-preview * - gemini-3-flash-preview + * - gemini-3.1-flash-lite (and preview) * - gemini-2.5-pro - * - gemini-3.1-flash-lite-preview - * - gemini-2.5-flash-lite (and preview) + * - gemini-2.5-flash-lite + * - gemini-3.5-flash * * Models with limited multimodal (text + image + audio + video, NO document): - * - gemini-2.5-flash (and preview) - * - gemini-2.0-flash (and lite) + * - gemini-2.5-flash */ describe('Gemini Model Input Modality Type Assertions', () => { // Helper types using provider-specific metadata. @@ -458,8 +409,8 @@ describe('Gemini Model Input Modality Type Assertions', () => { // ===== Full Multimodal Models (text + image + audio + video + document) ===== - describe('gemini-3-pro-preview (full multimodal)', () => { - type Modalities = GeminiModelInputModalitiesByName['gemini-3-pro-preview'] + describe('gemini-3.1-pro-preview (full multimodal)', () => { + type Modalities = GeminiModelInputModalitiesByName['gemini-3.1-pro-preview'] type Message = ConstrainedModelMessage> it('should allow all content part types', () => { @@ -497,9 +448,8 @@ describe('Gemini Model Input Modality Type Assertions', () => { }) }) - describe('gemini-3.1-flash-lite-preview (full multimodal)', () => { - type Modalities = - GeminiModelInputModalitiesByName['gemini-3.1-flash-lite-preview'] + describe('gemini-3.1-flash-lite (full multimodal)', () => { + type Modalities = GeminiModelInputModalitiesByName['gemini-3.1-flash-lite'] type Message = ConstrainedModelMessage> it('should allow all content part types', () => { @@ -511,8 +461,9 @@ describe('Gemini Model Input Modality Type Assertions', () => { }) }) - describe('gemini-2.5-flash-lite (full multimodal)', () => { - type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-flash-lite'] + describe('gemini-3.1-flash-lite-preview (full multimodal)', () => { + type Modalities = + GeminiModelInputModalitiesByName['gemini-3.1-flash-lite-preview'] type Message = ConstrainedModelMessage> it('should allow all content part types', () => { @@ -524,9 +475,8 @@ describe('Gemini Model Input Modality Type Assertions', () => { }) }) - describe('gemini-2.5-flash-lite-preview-09-2025 (full multimodal)', () => { - type Modalities = - GeminiModelInputModalitiesByName['gemini-2.5-flash-lite-preview-09-2025'] + describe('gemini-2.5-flash-lite (full multimodal)', () => { + type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-flash-lite'] type Message = ConstrainedModelMessage> it('should allow all content part types', () => { @@ -538,65 +488,23 @@ describe('Gemini Model Input Modality Type Assertions', () => { }) }) - // ===== Limited Multimodal Models (text + image + audio + video, NO document) ===== - - describe('gemini-2.5-flash (no document)', () => { - type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-flash'] - type Message = ConstrainedModelMessage> - - it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => { - expectTypeOf>().toExtend() - expectTypeOf>().toExtend() - expectTypeOf>().toExtend() - expectTypeOf>().toExtend() - }) - - it('should NOT allow DocumentPart', () => { - expectTypeOf< - MessageWithContent - >().not.toExtend() - }) - }) - - describe('gemini-2.5-flash-preview-09-2025 (no document)', () => { - type Modalities = - GeminiModelInputModalitiesByName['gemini-2.5-flash-preview-09-2025'] + describe('gemini-3.5-flash (full multimodal)', () => { + type Modalities = GeminiModelInputModalitiesByName['gemini-3.5-flash'] type Message = ConstrainedModelMessage> - it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => { + it('should allow all content part types', () => { expectTypeOf>().toExtend() expectTypeOf>().toExtend() expectTypeOf>().toExtend() expectTypeOf>().toExtend() - }) - - it('should NOT allow DocumentPart', () => { - expectTypeOf< - MessageWithContent - >().not.toExtend() + expectTypeOf>().toExtend() }) }) - describe('gemini-2.0-flash (no document)', () => { - type Modalities = GeminiModelInputModalitiesByName['gemini-2.0-flash'] - type Message = ConstrainedModelMessage> - - it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => { - expectTypeOf>().toExtend() - expectTypeOf>().toExtend() - expectTypeOf>().toExtend() - expectTypeOf>().toExtend() - }) - - it('should NOT allow DocumentPart', () => { - expectTypeOf< - MessageWithContent - >().not.toExtend() - }) - }) + // ===== Limited Multimodal Models (text + image + audio + video, NO document) ===== - describe('gemini-2.0-flash-lite (no document)', () => { - type Modalities = GeminiModelInputModalitiesByName['gemini-2.0-flash-lite'] + describe('gemini-2.5-flash (no document)', () => { + type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-flash'] type Message = ConstrainedModelMessage> it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => { diff --git a/packages/ai-gemini/tests/tools-per-model-type-safety.test.ts b/packages/ai-gemini/tests/tools-per-model-type-safety.test.ts index e32d28c2e..2da3c271c 100644 --- a/packages/ai-gemini/tests/tools-per-model-type-safety.test.ts +++ b/packages/ai-gemini/tests/tools-per-model-type-safety.test.ts @@ -65,24 +65,38 @@ describe('Gemini per-model tool gating', () => { ]) }) - it('gemini-2.0-flash-lite rejects all provider tools', () => { - const adapter = geminiText('gemini-2.0-flash-lite') + it('gemini-2.5-flash-lite accepts code_execution, google_maps, google_search, url_context but rejects file_search', () => { + const adapter = geminiText('gemini-2.5-flash-lite') typedTools(adapter, [ userTool, - // @ts-expect-error - gemini-2.0-flash-lite does not support code_execution codeExecutionTool(), - // @ts-expect-error - gemini-2.0-flash-lite does not support computer_use - computerUseTool({}), - // @ts-expect-error - gemini-2.0-flash-lite does not support file_search - fileSearchTool({ fileSearchStoreNames: [] }), - // @ts-expect-error - gemini-2.0-flash-lite does not support google_maps googleMapsTool(), - // @ts-expect-error - gemini-2.0-flash-lite does not support google_search googleSearchTool(), - // @ts-expect-error - gemini-2.0-flash-lite does not support google_search_retrieval + urlContextTool(), + // @ts-expect-error - gemini-2.5-flash-lite does not support file_search + fileSearchTool({ fileSearchStoreNames: [] }), + // @ts-expect-error - gemini-2.5-flash-lite does not support computer_use + computerUseTool({ + environment: Environment.ENVIRONMENT_BROWSER, + excludedPredefinedFunctions: [], + }), + // @ts-expect-error - gemini-2.5-flash-lite does not support google_search_retrieval googleSearchRetrievalTool(), - // @ts-expect-error - gemini-2.0-flash-lite does not support url_context + ]) + }) + + it('gemini-3.1-flash-lite (stable) accepts the same tool set as the preview id', () => { + const adapter = geminiText('gemini-3.1-flash-lite') + typedTools(adapter, [ + userTool, + codeExecutionTool(), + fileSearchTool({ fileSearchStoreNames: [] }), + googleSearchTool(), urlContextTool(), + // @ts-expect-error - gemini-3.1-flash-lite does not support google_maps + googleMapsTool(), + // @ts-expect-error - gemini-3.1-flash-lite does not support google_search_retrieval + googleSearchRetrievalTool(), ]) }) }) diff --git a/packages/ai/skills/ai-core/adapter-configuration/references/gemini-adapter.md b/packages/ai/skills/ai-core/adapter-configuration/references/gemini-adapter.md index 0cd038f10..a8d67c2db 100644 --- a/packages/ai/skills/ai-core/adapter-configuration/references/gemini-adapter.md +++ b/packages/ai/skills/ai-core/adapter-configuration/references/gemini-adapter.md @@ -27,7 +27,6 @@ import { geminiImage } from '@tanstack/ai-gemini' | Model | Max Input | Max Output | Notes | | ------------------------------- | --------- | ---------- | ---------------------------- | | `gemini-3.1-pro-preview` | 1M | 65K | Latest flagship, thinking | -| `gemini-3-pro-preview` | 1M | 65K | Previous flagship | | `gemini-3-flash-preview` | 1M | 65K | Fast, thinking, multimodal | | `gemini-3.1-flash-lite-preview` | 1M | 65K | Budget, still capable | | `gemini-2.5-pro` | 1M | 65K | Stable release, all features | diff --git a/testing/e2e/src/lib/media-providers.ts b/testing/e2e/src/lib/media-providers.ts index 2fb534291..bc31f2c3b 100644 --- a/testing/e2e/src/lib/media-providers.ts +++ b/testing/e2e/src/lib/media-providers.ts @@ -47,7 +47,7 @@ export function createImageAdapter( }), gemini: () => createGeminiImage( - 'gemini-2.0-flash-preview-image-generation', + 'gemini-2.5-flash-image', DUMMY_KEY, { httpOptions: { baseUrl: llmockBase(aimockPort), headers }, diff --git a/testing/e2e/src/lib/providers.ts b/testing/e2e/src/lib/providers.ts index 4edbd5219..7c1a75ed4 100644 --- a/testing/e2e/src/lib/providers.ts +++ b/testing/e2e/src/lib/providers.ts @@ -21,7 +21,7 @@ const DUMMY_KEY = 'sk-e2e-test-dummy-key' const defaultModels: Record = { openai: 'gpt-4o', anthropic: 'claude-sonnet-4-5', - gemini: 'gemini-2.0-flash', + gemini: 'gemini-2.5-flash', ollama: 'mistral', groq: 'llama-3.3-70b-versatile', grok: 'grok-3', @@ -57,7 +57,7 @@ export function createTextAdapter( if (provider === 'gemini' && feature === 'stateful-interactions') { return createChatOptions({ adapter: createGeminiTextInteractions( - model as 'gemini-2.0-flash', + model as 'gemini-2.5-flash', DUMMY_KEY, { httpOptions: { @@ -86,7 +86,7 @@ export function createTextAdapter( }), gemini: () => createChatOptions({ - adapter: createGeminiChat(model as 'gemini-2.0-flash', DUMMY_KEY, { + adapter: createGeminiChat(model as 'gemini-2.5-flash', DUMMY_KEY, { httpOptions: { baseUrl: base, headers: testHeaders, diff --git a/testing/e2e/src/routes/api.summarize.ts b/testing/e2e/src/routes/api.summarize.ts index 46c69e3ce..4180c5e4d 100644 --- a/testing/e2e/src/routes/api.summarize.ts +++ b/testing/e2e/src/routes/api.summarize.ts @@ -42,7 +42,7 @@ function createSummarizeAdapter( defaultHeaders: headers, }), gemini: () => - createGeminiSummarize(DUMMY_KEY, 'gemini-2.0-flash', { + createGeminiSummarize(DUMMY_KEY, 'gemini-2.5-flash', { httpOptions: { baseUrl: llmockBase(aimockPort), headers }, }), ollama: () => createOllamaSummarize('mistral', llmockBase(aimockPort)), diff --git a/testing/panel/src/lib/model-selection.ts b/testing/panel/src/lib/model-selection.ts index 470c6a52d..69731dc77 100644 --- a/testing/panel/src/lib/model-selection.ts +++ b/testing/panel/src/lib/model-selection.ts @@ -36,11 +36,6 @@ export const MODEL_OPTIONS: Array = [ }, // Gemini - { - provider: 'gemini', - model: 'gemini-2.0-flash', - label: 'Gemini - 2.0 Flash', - }, { provider: 'gemini', model: 'gemini-2.5-flash', @@ -114,8 +109,8 @@ export const MODEL_OPTIONS: Array = [ }, { provider: 'openrouter', - model: 'google/gemini-2.0-flash-001', - label: 'OpenRouter - Gemini 2.0 Flash', + model: 'google/gemini-2.5-flash', + label: 'OpenRouter - Gemini 2.5 Flash', }, { provider: 'openrouter', diff --git a/testing/panel/src/routes/api.chat.ts b/testing/panel/src/routes/api.chat.ts index 11ee577cb..094d999aa 100644 --- a/testing/panel/src/routes/api.chat.ts +++ b/testing/panel/src/routes/api.chat.ts @@ -178,7 +178,7 @@ export const Route = createFileRoute('/api/chat')({ }), gemini: () => createChatOptions({ - adapter: geminiText((model || 'gemini-2.0-flash') as any), + adapter: geminiText((model || 'gemini-2.5-flash') as any), }), grok: () => createChatOptions({ diff --git a/testing/panel/src/routes/api.image.ts b/testing/panel/src/routes/api.image.ts index 8c388089a..efb3c7022 100644 --- a/testing/panel/src/routes/api.image.ts +++ b/testing/panel/src/routes/api.image.ts @@ -17,7 +17,7 @@ export const Route = createFileRoute('/api/image')({ const defaultModels: Record = { openai: 'gpt-image-1', - gemini: 'gemini-2.0-flash-preview-image-generation', + gemini: 'gemini-2.5-flash-image', openrouter: 'google/gemini-3.1-flash-image-preview', } const model: string = diff --git a/testing/panel/src/routes/api.structured.ts b/testing/panel/src/routes/api.structured.ts index 3b692aa17..d6b65f433 100644 --- a/testing/panel/src/routes/api.structured.ts +++ b/testing/panel/src/routes/api.structured.ts @@ -65,7 +65,7 @@ export const Route = createFileRoute('/api/structured')({ // Default models per provider const defaultModels: Record = { anthropic: 'claude-sonnet-4-5', - gemini: 'gemini-2.0-flash', + gemini: 'gemini-2.5-flash', grok: 'grok-3-mini', ollama: 'mistral:7b', openai: 'gpt-4o', diff --git a/testing/panel/src/routes/api.summarize.ts b/testing/panel/src/routes/api.summarize.ts index ee3ce70f0..3d23faaec 100644 --- a/testing/panel/src/routes/api.summarize.ts +++ b/testing/panel/src/routes/api.summarize.ts @@ -35,7 +35,7 @@ export const Route = createFileRoute('/api/summarize')({ // Default models per provider const defaultModels: Record = { anthropic: 'claude-sonnet-4-5', - gemini: 'gemini-2.0-flash', + gemini: 'gemini-2.5-flash', grok: 'grok-3-mini', ollama: 'mistral:7b', openai: 'gpt-4o-mini', diff --git a/testing/panel/src/routes/structured.tsx b/testing/panel/src/routes/structured.tsx index b79ed20ec..28238addd 100644 --- a/testing/panel/src/routes/structured.tsx +++ b/testing/panel/src/routes/structured.tsx @@ -23,7 +23,7 @@ interface StructuredProvider { const PROVIDERS: Array = [ { id: 'openai', name: 'OpenAI (GPT-4o)' }, { id: 'anthropic', name: 'Anthropic (Claude Sonnet)' }, - { id: 'gemini', name: 'Gemini (2.0 Flash)' }, + { id: 'gemini', name: 'Gemini (2.5 Flash)' }, { id: 'grok', name: 'Grok (Grok 3 Mini)' }, { id: 'ollama', name: 'Ollama (Mistral 7B)' }, { id: 'openrouter', name: 'OpenRouter (GPT-4o)' }, diff --git a/testing/panel/src/routes/summarize.tsx b/testing/panel/src/routes/summarize.tsx index 790731079..90c432cd4 100644 --- a/testing/panel/src/routes/summarize.tsx +++ b/testing/panel/src/routes/summarize.tsx @@ -18,7 +18,7 @@ interface SummarizeProvider { const PROVIDERS: Array = [ { id: 'openai', name: 'OpenAI (GPT-4o Mini)' }, { id: 'anthropic', name: 'Anthropic (Claude Sonnet)' }, - { id: 'gemini', name: 'Gemini (2.0 Flash)' }, + { id: 'gemini', name: 'Gemini (2.5 Flash)' }, { id: 'grok', name: 'Grok (Grok 3 Mini)' }, { id: 'ollama', name: 'Ollama (Mistral 7B)' }, { id: 'openrouter', name: 'OpenRouter (GPT-4o Mini)' }, diff --git a/testing/panel/tests/vendor-config.ts b/testing/panel/tests/vendor-config.ts index 5373d6fba..d684e245d 100644 --- a/testing/panel/tests/vendor-config.ts +++ b/testing/panel/tests/vendor-config.ts @@ -59,7 +59,7 @@ export const PROVIDERS: ProviderConfig[] = [ id: 'gemini', name: 'Gemini', envKey: 'GEMINI_API_KEY', - defaultModel: 'gemini-2.0-flash', + defaultModel: 'gemini-2.5-flash', supportsBasicInference: true, supportsTools: true, supportsSummarization: true,