🎚️ feat: Add Thinking Level Parameter for Gemini 3+ Models (#11994)

* 🧠 feat: Add Thinking Level Config for Gemini 3 Models

- Introduced a new setting for 'thinking level' in the Google configuration, allowing users to control the depth of reasoning for Gemini 3 models.
- Updated translation files to include the new 'thinking level' label and description.
- Enhanced the Google LLM configuration to support the new 'thinking level' parameter, ensuring compatibility with both Google and Vertex AI providers.
- Added necessary schema and type definitions to accommodate the new setting across the data provider and API layers.

* test: Google LLM Configuration for Gemini 3 Models

- Added tests to validate default thinking configuration for Gemini 3 models, ensuring `thinkingConfig` is set correctly without `thinkingLevel`.
- Implemented logic to ignore `thinkingBudget` for Gemini 3+ models, confirming that it does not affect the configuration.
- Included a test to verify that `gemini-2.9-flash` is not classified as a Gemini 3+ model, maintaining expected behavior for earlier versions.
- Updated existing tests to ensure comprehensive coverage of the new configurations and behaviors.

* fix: Update translation for Google LLM thinking settings

- Revised descriptions for 'thinking budget' and 'thinking level' in the English translation file to clarify their applicability to different Gemini model versions.
- Ensured that the new descriptions accurately reflect the functionality and usage of the settings for Gemini 2.5 and 3 models.

* docs: Update comments for Gemini 3+ thinking configuration

- Added detailed comments in the Google LLM configuration to clarify the differences between `thinkingLevel` and `thinkingBudget` for Gemini 3+ models.
- Explained the necessity of `includeThoughts` in Vertex AI requests and how it interacts with `thinkingConfig` for improved understanding of the configuration logic.

* fix: Update comment for Gemini 3 model versioning

- Corrected comment in the configuration file to reflect the proper versioning for Gemini models, changing "Gemini 3.0 Models" to "Gemini 3 Models" for clarity and consistency.

* fix: Update thinkingLevel schema for Gemini 3 Models

- Removed nullable option from the thinkingLevel field in the tConversationSchema to ensure it is always defined when present, aligning with the intended configuration for Gemini 3 models.
This commit is contained in:
Danny Avila 2026-02-28 16:56:10 -05:00 committed by GitHub
parent 826b494578
commit 723acd830c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 283 additions and 14 deletions

View file

@ -1,5 +1,5 @@
import { Providers } from '@librechat/agents';
import { AuthKeys } from 'librechat-data-provider';
import { AuthKeys, ThinkingLevel } from 'librechat-data-provider';
import type * as t from '~/types';
import { getGoogleConfig, getSafetySettings, knownGoogleParams } from './llm';
@ -367,6 +367,191 @@ describe('getGoogleConfig', () => {
});
});
describe('Gemini 3 Thinking Level', () => {
it('should use thinkingLevel for Gemini 3 models with Google provider', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3-pro-preview',
thinking: true,
thinkingLevel: ThinkingLevel.high,
},
});
expect(result.llmConfig).toHaveProperty('thinkingConfig');
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
includeThoughts: true,
thinkingLevel: ThinkingLevel.high,
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).not.toHaveProperty(
'thinkingBudget',
);
});
it('should use thinkingLevel for Gemini 3.1 models', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3.1-pro-preview',
thinking: true,
thinkingLevel: ThinkingLevel.medium,
},
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
includeThoughts: true,
thinkingLevel: ThinkingLevel.medium,
});
});
it('should omit thinkingLevel when unset (empty string) for Gemini 3', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3-flash-preview',
thinking: true,
thinkingLevel: ThinkingLevel.unset,
},
});
expect(result.llmConfig).toHaveProperty('thinkingConfig');
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
includeThoughts: true,
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).not.toHaveProperty(
'thinkingLevel',
);
});
it('should not set thinkingConfig when thinking is false for Gemini 3', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3-pro-preview',
thinking: false,
thinkingLevel: ThinkingLevel.high,
},
});
expect(result.llmConfig).not.toHaveProperty('thinkingConfig');
});
it('should use thinkingLevel for Gemini 3 with Vertex AI provider', () => {
const credentials = {
[AuthKeys.GOOGLE_SERVICE_KEY]: {
project_id: 'test-project',
},
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3-pro-preview',
thinking: true,
thinkingLevel: ThinkingLevel.low,
},
});
expect(result.provider).toBe(Providers.VERTEXAI);
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
includeThoughts: true,
thinkingLevel: ThinkingLevel.low,
});
expect(result.llmConfig).toHaveProperty('includeThoughts', true);
});
it('should send thinkingConfig by default for Gemini 3 (no thinking options set)', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3-pro-preview',
},
});
expect(result.llmConfig).toHaveProperty('thinkingConfig');
const config = (result.llmConfig as Record<string, unknown>).thinkingConfig;
expect(config).toMatchObject({ includeThoughts: true });
expect(config).not.toHaveProperty('thinkingLevel');
});
it('should ignore thinkingBudget for Gemini 3+ models', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-3-pro-preview',
thinking: true,
thinkingBudget: 5000,
},
});
const config = (result.llmConfig as Record<string, unknown>).thinkingConfig;
expect(config).not.toHaveProperty('thinkingBudget');
expect(config).toMatchObject({ includeThoughts: true });
});
it('should NOT classify gemini-2.9-flash as Gemini 3+', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-2.9-flash',
thinking: true,
thinkingBudget: 5000,
},
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
thinkingBudget: 5000,
includeThoughts: true,
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).not.toHaveProperty(
'thinkingLevel',
);
});
it('should use thinkingBudget (not thinkingLevel) for Gemini 2.5 models', () => {
const credentials = {
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
};
const result = getGoogleConfig(credentials, {
modelOptions: {
model: 'gemini-2.5-flash',
thinking: true,
thinkingBudget: 5000,
thinkingLevel: ThinkingLevel.high,
},
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
thinkingBudget: 5000,
includeThoughts: true,
});
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).not.toHaveProperty(
'thinkingLevel',
);
});
});
describe('Web Search Functionality', () => {
it('should enable web search when web_search is true', () => {
const credentials = {