mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-22 00:13:09 +08:00
fix: url context and web search capability (#11306)
* fix: enhance support for interleaved thinking and model compatibility * fix: type
This commit is contained in:
parent
7fd4837a47
commit
31eec403f7
13
src/renderer/src/aiCore/prepareParams/header.ts
Normal file
13
src/renderer/src/aiCore/prepareParams/header.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { isClaude45ReasoningModel } from '@renderer/config/models'
|
||||||
|
import type { Assistant, Model } from '@renderer/types'
|
||||||
|
import { isToolUseModeFunction } from '@renderer/utils/assistant'
|
||||||
|
|
||||||
|
const INTERLEAVED_THINKING_HEADER = 'interleaved-thinking-2025-05-14'
|
||||||
|
|
||||||
|
export function addAnthropicHeaders(assistant: Assistant, model: Model): string[] {
|
||||||
|
const anthropicHeaders: string[] = []
|
||||||
|
if (isClaude45ReasoningModel(model) && isToolUseModeFunction(assistant)) {
|
||||||
|
anthropicHeaders.push(INTERLEAVED_THINKING_HEADER)
|
||||||
|
}
|
||||||
|
return anthropicHeaders
|
||||||
|
}
|
||||||
@ -7,10 +7,12 @@ import { anthropic } from '@ai-sdk/anthropic'
|
|||||||
import { google } from '@ai-sdk/google'
|
import { google } from '@ai-sdk/google'
|
||||||
import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic/edge'
|
import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic/edge'
|
||||||
import { vertex } from '@ai-sdk/google-vertex/edge'
|
import { vertex } from '@ai-sdk/google-vertex/edge'
|
||||||
|
import { combineHeaders } from '@ai-sdk/provider-utils'
|
||||||
import type { WebSearchPluginConfig } from '@cherrystudio/ai-core/built-in/plugins'
|
import type { WebSearchPluginConfig } from '@cherrystudio/ai-core/built-in/plugins'
|
||||||
import { isBaseProvider } from '@cherrystudio/ai-core/core/providers/schemas'
|
import { isBaseProvider } from '@cherrystudio/ai-core/core/providers/schemas'
|
||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
import {
|
import {
|
||||||
|
isAnthropicModel,
|
||||||
isGenerateImageModel,
|
isGenerateImageModel,
|
||||||
isOpenRouterBuiltInWebSearchModel,
|
isOpenRouterBuiltInWebSearchModel,
|
||||||
isReasoningModel,
|
isReasoningModel,
|
||||||
@ -19,6 +21,8 @@ import {
|
|||||||
isSupportedThinkingTokenModel,
|
isSupportedThinkingTokenModel,
|
||||||
isWebSearchModel
|
isWebSearchModel
|
||||||
} from '@renderer/config/models'
|
} from '@renderer/config/models'
|
||||||
|
import { isAwsBedrockProvider } from '@renderer/config/providers'
|
||||||
|
import { isVertexProvider } from '@renderer/hooks/useVertexAI'
|
||||||
import { getAssistantSettings, getDefaultModel } from '@renderer/services/AssistantService'
|
import { getAssistantSettings, getDefaultModel } from '@renderer/services/AssistantService'
|
||||||
import store from '@renderer/store'
|
import store from '@renderer/store'
|
||||||
import type { CherryWebSearchConfig } from '@renderer/store/websearch'
|
import type { CherryWebSearchConfig } from '@renderer/store/websearch'
|
||||||
@ -34,6 +38,7 @@ import { setupToolsConfig } from '../utils/mcp'
|
|||||||
import { buildProviderOptions } from '../utils/options'
|
import { buildProviderOptions } from '../utils/options'
|
||||||
import { getAnthropicThinkingBudget } from '../utils/reasoning'
|
import { getAnthropicThinkingBudget } from '../utils/reasoning'
|
||||||
import { buildProviderBuiltinWebSearchConfig } from '../utils/websearch'
|
import { buildProviderBuiltinWebSearchConfig } from '../utils/websearch'
|
||||||
|
import { addAnthropicHeaders } from './header'
|
||||||
import { supportsTopP } from './modelCapabilities'
|
import { supportsTopP } from './modelCapabilities'
|
||||||
import { getTemperature, getTopP } from './modelParameters'
|
import { getTemperature, getTopP } from './modelParameters'
|
||||||
|
|
||||||
@ -172,13 +177,21 @@ export async function buildStreamTextParams(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let headers: Record<string, string | undefined> = options.requestOptions?.headers ?? {}
|
||||||
|
|
||||||
|
// https://docs.claude.com/en/docs/build-with-claude/extended-thinking#interleaved-thinking
|
||||||
|
if (!isVertexProvider(provider) && !isAwsBedrockProvider(provider) && isAnthropicModel(model)) {
|
||||||
|
const newBetaHeaders = { 'anthropic-beta': addAnthropicHeaders(assistant, model).join(',') }
|
||||||
|
headers = combineHeaders(headers, newBetaHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
// 构建基础参数
|
// 构建基础参数
|
||||||
const params: StreamTextParams = {
|
const params: StreamTextParams = {
|
||||||
messages: sdkMessages,
|
messages: sdkMessages,
|
||||||
maxOutputTokens: maxTokens,
|
maxOutputTokens: maxTokens,
|
||||||
temperature: getTemperature(assistant, model),
|
temperature: getTemperature(assistant, model),
|
||||||
abortSignal: options.requestOptions?.signal,
|
abortSignal: options.requestOptions?.signal,
|
||||||
headers: options.requestOptions?.headers,
|
headers,
|
||||||
providerOptions,
|
providerOptions,
|
||||||
stopWhen: stepCountIs(20),
|
stopWhen: stepCountIs(20),
|
||||||
maxRetries: 0
|
maxRetries: 0
|
||||||
|
|||||||
@ -70,7 +70,7 @@ export function isWebSearchModel(model: Model): boolean {
|
|||||||
// bedrock和vertex不支持
|
// bedrock和vertex不支持
|
||||||
if (
|
if (
|
||||||
isAnthropicModel(model) &&
|
isAnthropicModel(model) &&
|
||||||
(provider.id === SystemProviderIds['aws-bedrock'] || provider.id === SystemProviderIds.vertexai)
|
!(provider.id === SystemProviderIds['aws-bedrock'] || provider.id === SystemProviderIds.vertexai)
|
||||||
) {
|
) {
|
||||||
return CLAUDE_SUPPORTED_WEBSEARCH_REGEX.test(modelId)
|
return CLAUDE_SUPPORTED_WEBSEARCH_REGEX.test(modelId)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1573,6 +1573,10 @@ export function isAIGatewayProvider(provider: Provider): boolean {
|
|||||||
return provider.type === 'ai-gateway'
|
return provider.type === 'ai-gateway'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAwsBedrockProvider(provider: Provider): boolean {
|
||||||
|
return provider.type === 'aws-bedrock'
|
||||||
|
}
|
||||||
|
|
||||||
const NOT_SUPPORT_API_VERSION_PROVIDERS = ['github', 'copilot', 'perplexity'] as const satisfies SystemProviderId[]
|
const NOT_SUPPORT_API_VERSION_PROVIDERS = ['github', 'copilot', 'perplexity'] as const satisfies SystemProviderId[]
|
||||||
|
|
||||||
export const isSupportAPIVersionProvider = (provider: Provider) => {
|
export const isSupportAPIVersionProvider = (provider: Provider) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { isGeminiModel } from '@renderer/config/models'
|
import { isAnthropicModel, isGeminiModel } from '@renderer/config/models'
|
||||||
import { isSupportUrlContextProvider } from '@renderer/config/providers'
|
import { isSupportUrlContextProvider } from '@renderer/config/providers'
|
||||||
import { defineTool, registerTool, TopicType } from '@renderer/pages/home/Inputbar/types'
|
import { defineTool, registerTool, TopicType } from '@renderer/pages/home/Inputbar/types'
|
||||||
import { getProviderByModel } from '@renderer/services/AssistantService'
|
import { getProviderByModel } from '@renderer/services/AssistantService'
|
||||||
@ -10,9 +10,8 @@ const urlContextTool = defineTool({
|
|||||||
label: (t) => t('chat.input.url_context'),
|
label: (t) => t('chat.input.url_context'),
|
||||||
visibleInScopes: [TopicType.Chat],
|
visibleInScopes: [TopicType.Chat],
|
||||||
condition: ({ model }) => {
|
condition: ({ model }) => {
|
||||||
if (!isGeminiModel(model)) return false
|
|
||||||
const provider = getProviderByModel(model)
|
const provider = getProviderByModel(model)
|
||||||
return !!provider && isSupportUrlContextProvider(provider)
|
return !!provider && isSupportUrlContextProvider(provider) && (isGeminiModel(model) || isAnthropicModel(model))
|
||||||
},
|
},
|
||||||
render: ({ assistant }) => <UrlContextButton assistantId={assistant.id} />
|
render: ({ assistant }) => <UrlContextButton assistantId={assistant.id} />
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user