mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-09 06:49:02 +08:00
fix: convert 'developer' role to 'system' for unsupported providers (#12325)
AI SDK v5 uses 'developer' role for reasoning models, but some providers like Azure DeepSeek R1 only support 'system', 'user', 'assistant', 'tool' roles, causing HTTP 422 errors. This fix adds a custom fetch wrapper that converts 'developer' role back to 'system' for providers that don't support it. Fixes #12321 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
116ee6f94b
commit
6b0bb64795
@ -1,5 +1,5 @@
|
|||||||
import { formatPrivateKey, hasProviderConfig, ProviderConfigFactory } from '@cherrystudio/ai-core/provider'
|
import { formatPrivateKey, hasProviderConfig, ProviderConfigFactory } from '@cherrystudio/ai-core/provider'
|
||||||
import { isOpenAIChatCompletionOnlyModel } from '@renderer/config/models'
|
import { isOpenAIChatCompletionOnlyModel, isOpenAIReasoningModel } from '@renderer/config/models'
|
||||||
import {
|
import {
|
||||||
getAwsBedrockAccessKeyId,
|
getAwsBedrockAccessKeyId,
|
||||||
getAwsBedrockApiKey,
|
getAwsBedrockApiKey,
|
||||||
@ -29,6 +29,7 @@ import {
|
|||||||
isNewApiProvider,
|
isNewApiProvider,
|
||||||
isOllamaProvider,
|
isOllamaProvider,
|
||||||
isPerplexityProvider,
|
isPerplexityProvider,
|
||||||
|
isSupportDeveloperRoleProvider,
|
||||||
isSupportStreamOptionsProvider,
|
isSupportStreamOptionsProvider,
|
||||||
isVertexProvider
|
isVertexProvider
|
||||||
} from '@renderer/utils/provider'
|
} from '@renderer/utils/provider'
|
||||||
@ -264,6 +265,14 @@ export function providerToAiSdkConfig(actualProvider: Provider, model: Model): A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply developer-to-system role conversion for providers that don't support developer role
|
||||||
|
// bug: https://github.com/vercel/ai/issues/10982
|
||||||
|
// fixPR: https://github.com/vercel/ai/pull/11127
|
||||||
|
// TODO: but the PR don't backport to v5, the code will be removed when upgrading to v6
|
||||||
|
if (!isSupportDeveloperRoleProvider(actualProvider) || !isOpenAIReasoningModel(model)) {
|
||||||
|
extraOptions.fetch = createDeveloperToSystemFetch(extraOptions.fetch)
|
||||||
|
}
|
||||||
|
|
||||||
if (hasProviderConfig(aiSdkProviderId) && aiSdkProviderId !== 'openai-compatible') {
|
if (hasProviderConfig(aiSdkProviderId) && aiSdkProviderId !== 'openai-compatible') {
|
||||||
const options = ProviderConfigFactory.fromProvider(aiSdkProviderId, baseConfig, extraOptions)
|
const options = ProviderConfigFactory.fromProvider(aiSdkProviderId, baseConfig, extraOptions)
|
||||||
return {
|
return {
|
||||||
@ -302,6 +311,44 @@ export function isModernSdkSupported(provider: Provider): boolean {
|
|||||||
return hasProviderConfig(aiSdkProviderId)
|
return hasProviderConfig(aiSdkProviderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a custom fetch wrapper that converts 'developer' role to 'system' role in request body.
|
||||||
|
* This is needed for providers that don't support the 'developer' role (e.g., Azure DeepSeek R1).
|
||||||
|
*
|
||||||
|
* @param originalFetch - Optional original fetch function to wrap
|
||||||
|
* @returns A fetch function that transforms the request body
|
||||||
|
*/
|
||||||
|
function createDeveloperToSystemFetch(originalFetch?: typeof fetch): typeof fetch {
|
||||||
|
const baseFetch = originalFetch ?? fetch
|
||||||
|
return async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||||
|
let options = init
|
||||||
|
if (options?.body && typeof options.body === 'string') {
|
||||||
|
try {
|
||||||
|
const body = JSON.parse(options.body)
|
||||||
|
if (body.messages && Array.isArray(body.messages)) {
|
||||||
|
let hasChanges = false
|
||||||
|
body.messages = body.messages.map((msg: { role: string }) => {
|
||||||
|
if (msg.role === 'developer') {
|
||||||
|
hasChanges = true
|
||||||
|
return { ...msg, role: 'system' }
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
})
|
||||||
|
if (hasChanges) {
|
||||||
|
options = {
|
||||||
|
...options,
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// If parsing fails, just use original body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return baseFetch(input, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 准备特殊provider的配置,主要用于异步处理的配置
|
* 准备特殊provider的配置,主要用于异步处理的配置
|
||||||
*/
|
*/
|
||||||
@ -360,5 +407,6 @@ export async function prepareSpecialProviderConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user