hotfix: Custom params not passed to Gemini API when using NewAPI/AiHubMix (#14352)

### What this PR does

Before this PR: Custom `generationConfig` parameters set in model
settings were silently ignored when using Gemini models via
`NewAPI`/`AiHubMix`. The outgoing request always contained an empty
`generationConfig: {}`

After this PR: Custom `generationConfig` fields are correctly applied to
the API request

Fixes #14301 

### Why we need it and why it was done in this way

`NewAPI`/`AiHubMix` providers fell through to the generic `default`
branch in `buildProviderOptions`, producing `{ newapi: {...} }` instead
of `{ google: {...} }` for Gemini models. Fix: route these providers to
`buildProxyProviderOptions` which dispatches by model type

The following tradeoffs were made: `buildCherryInProviderOptions` (which
used `provider.type` to dispatch) was replaced by
`buildProxyProviderOptions` (which uses model ID). This is more robust
for proxy providers that don't set `type: 'gemini'`

### Release note

```release-note
fix: Custom parameters were not being passed to `Gemini` API when using `NewAPI` or `AiHubMix` providers
```
This commit is contained in:
菠蘿包
2026-04-18 17:32:21 +08:00
committed by GitHub
parent 7afabbdf20
commit fbda0d213d
3 changed files with 45 additions and 3 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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-]+)?',