diff --git a/src/renderer/src/aiCore/utils/__tests__/options.test.ts b/src/renderer/src/aiCore/utils/__tests__/options.test.ts index 616269a054..d3622e8696 100644 --- a/src/renderer/src/aiCore/utils/__tests__/options.test.ts +++ b/src/renderer/src/aiCore/utils/__tests__/options.test.ts @@ -1123,6 +1123,46 @@ describe('options utils', () => { }) }) + it.each([ + { providerId: 'newapi', providerName: 'NewAPI' }, + { providerId: 'aihubmix', providerName: 'AiHubMix' } + ])( + 'should route Gemini models to google providerOptions through $providerName', + async ({ providerId, providerName }) => { + const { getCustomParameters } = await import('../reasoning') + vi.mocked(getCustomParameters).mockReturnValue({ + generationConfig: { responseModalities: ['IMAGE', 'TEXT'] }, + imageConfig: { aspectRatio: '3:4', imageSize: '4K' } + }) + + const provider: Provider = { + id: providerId, + name: providerName, + type: 'openai', + models: [] as Model[] + } as Provider + + const geminiModel: Model = { + id: 'gemini-3.1-flash-image-preview', + name: 'Gemini 3.1 Flash Image Preview', + provider: providerId + } as Model + + const result = buildProviderOptions(mockAssistant, geminiModel, provider, { + enableReasoning: false, + enableWebSearch: false, + enableGenerateImage: true + }) + + expect(result.providerOptions).toHaveProperty('google') + expect(result.providerOptions).not.toHaveProperty(providerId) + expect(result.providerOptions.google).toMatchObject({ + generationConfig: { responseModalities: ['IMAGE', 'TEXT'] }, + imageConfig: { aspectRatio: '3:4', imageSize: '4K' } + }) + } + ) + // Note: For proxy providers like aihubmix/newapi, users should write AI SDK provider ID (google/anthropic) // instead of the Cherry Studio provider ID for custom parameters to work correctly diff --git a/src/renderer/src/aiCore/utils/options.ts b/src/renderer/src/aiCore/utils/options.ts index 1f2ace67db..0bee602478 100644 --- a/src/renderer/src/aiCore/utils/options.ts +++ b/src/renderer/src/aiCore/utils/options.ts @@ -205,6 +205,8 @@ export function buildProviderOptions( case SystemProviderIds.ollama: providerSpecificOptions = buildOllamaProviderOptions(assistant, model, capabilities) break + case 'newapi': + case 'aihubmix': case SystemProviderIds.gateway: providerSpecificOptions = buildAIGatewayOptions(assistant, model, capabilities, serviceTier, textVerbosity) break diff --git a/src/renderer/src/config/models/vision.ts b/src/renderer/src/config/models/vision.ts index 0faf8ba5ab..10c832cfee 100644 --- a/src/renderer/src/config/models/vision.ts +++ b/src/renderer/src/config/models/vision.ts @@ -119,7 +119,7 @@ const IMAGE_ENHANCEMENT_MODELS = [ 'gpt-image-1', 'gemini-2.5-flash-image(?:-[\\w-]+)?', 'gemini-2.0-flash-preview-image-generation', - 'gemini-3(?:\\.\\d+)?-pro-image(?:-[\\w-]+)?' + 'gemini-3(?:\\.\\d+)?-(?:flash|pro)-image(?:-[\\w-]+)?' ] const IMAGE_ENHANCEMENT_MODELS_REGEX = new RegExp(IMAGE_ENHANCEMENT_MODELS.join('|'), 'i') @@ -129,7 +129,7 @@ const DEDICATED_IMAGE_MODEL_REGEX = new RegExp(DEDICATED_IMAGE_MODELS.join('|'), // Models that should auto-enable image generation button when selected const AUTO_ENABLE_IMAGE_MODELS = [ 'gemini-2.5-flash-image(?:-[\\w-]+)?', - 'gemini-3(?:\\.\\d+)?-pro-image(?:-[\\w-]+)?', + 'gemini-3(?:\\.\\d+)?-(?:flash|pro)-image(?:-[\\w-]+)?', ...DEDICATED_IMAGE_MODELS ] @@ -147,7 +147,7 @@ const OPENAI_TOOL_USE_IMAGE_GENERATION_MODELS = [ const OPENAI_IMAGE_GENERATION_MODELS = [...OPENAI_TOOL_USE_IMAGE_GENERATION_MODELS, 'gpt-image-1'] -const MODERN_IMAGE_MODELS = ['gemini-3(?:\\.\\d+)?-pro-image(?:-[\\w-]+)?'] +const MODERN_IMAGE_MODELS = ['gemini-3(?:\\.\\d+)?-(?:flash|pro)-image(?:-[\\w-]+)?'] const GENERATE_IMAGE_MODELS = [ 'gemini-2.0-flash-exp(?:-[\\w-]+)?',