mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-10 07:19:02 +08:00
feat: enhance web search tool switching logic to support provider-specific context (#11769)
* feat: enhance web search tool switching logic to support provider-specific context * Update packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: consolidate control flow in switchWebSearchTool (#11771) * Initial plan * refactor: make control flow consistent in switchWebSearchTool Replace early returns with break statements in all switch cases to ensure consistent control flow. Move fallback logic into default case for clarity. Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com> * Update packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: format * fix: ensure switchWebSearchTool is always called for cherryin providers - Add missing else branch to prevent silent failure when provider extraction fails - Add empty string check for extracted providerId from split operation - Ensures web search functionality is preserved in all edge cases Addresses PR review feedback from #11769 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * refactor: simplify repetitive switchWebSearchTool calls - Extract providerId determination logic before calling switchWebSearchTool - Call switchWebSearchTool only once at the end with updated providerId - Reduce code duplication while maintaining all edge case handling Addresses review feedback from @kangfenmao 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * refactor: eliminate code duplication in switchWebSearchTool - Extract helper functions: ensureToolsObject, applyToolBasedSearch, applyProviderOptionsSearch - Replace switch statement and fallback if-else chain with providerHandlers map - Use array-based priority order for fallback logic - Reduce code from 73 lines to 80 lines but with much better maintainability - Eliminates 12 instances of "if (!params.tools) params.tools = {}" - Single source of truth for each provider's configuration logic 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c4fd48376d
commit
9ac7e2c78d
@ -6,6 +6,7 @@ import { type Tool } from 'ai'
|
|||||||
|
|
||||||
import { createOpenRouterOptions, createXaiOptions, mergeProviderOptions } from '../../../options'
|
import { createOpenRouterOptions, createXaiOptions, mergeProviderOptions } from '../../../options'
|
||||||
import type { ProviderOptionsMap } from '../../../options/types'
|
import type { ProviderOptionsMap } from '../../../options/types'
|
||||||
|
import type { AiRequestContext } from '../../'
|
||||||
import type { OpenRouterSearchConfig } from './openrouter'
|
import type { OpenRouterSearchConfig } from './openrouter'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,28 +96,84 @@ export type WebSearchToolInputSchema = {
|
|||||||
'openai-chat': InferToolInput<OpenAIChatWebSearchTool>
|
'openai-chat': InferToolInput<OpenAIChatWebSearchTool>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const switchWebSearchTool = (config: WebSearchPluginConfig, params: any) => {
|
/**
|
||||||
if (config.openai) {
|
* Helper function to ensure params.tools object exists
|
||||||
if (!params.tools) params.tools = {}
|
*/
|
||||||
params.tools.web_search = openai.tools.webSearch(config.openai)
|
const ensureToolsObject = (params: any) => {
|
||||||
} else if (config['openai-chat']) {
|
if (!params.tools) params.tools = {}
|
||||||
if (!params.tools) params.tools = {}
|
}
|
||||||
params.tools.web_search_preview = openai.tools.webSearchPreview(config['openai-chat'])
|
|
||||||
} else if (config.anthropic) {
|
/**
|
||||||
if (!params.tools) params.tools = {}
|
* Helper function to apply tool-based web search configuration
|
||||||
params.tools.web_search = anthropic.tools.webSearch_20250305(config.anthropic)
|
*/
|
||||||
} else if (config.google) {
|
const applyToolBasedSearch = (params: any, toolName: string, toolInstance: any) => {
|
||||||
// case 'google-vertex':
|
ensureToolsObject(params)
|
||||||
if (!params.tools) params.tools = {}
|
params.tools[toolName] = toolInstance
|
||||||
params.tools.web_search = google.tools.googleSearch(config.google || {})
|
}
|
||||||
} else if (config.xai) {
|
|
||||||
const searchOptions = createXaiOptions({
|
/**
|
||||||
searchParameters: { ...config.xai, mode: 'on' }
|
* Helper function to apply provider options-based web search configuration
|
||||||
})
|
*/
|
||||||
params.providerOptions = mergeProviderOptions(params.providerOptions, searchOptions)
|
const applyProviderOptionsSearch = (params: any, searchOptions: any) => {
|
||||||
} else if (config.openrouter) {
|
params.providerOptions = mergeProviderOptions(params.providerOptions, searchOptions)
|
||||||
const searchOptions = createOpenRouterOptions(config.openrouter)
|
}
|
||||||
params.providerOptions = mergeProviderOptions(params.providerOptions, searchOptions)
|
|
||||||
|
export const switchWebSearchTool = (config: WebSearchPluginConfig, params: any, context?: AiRequestContext) => {
|
||||||
|
const providerId = context?.providerId
|
||||||
|
|
||||||
|
// Provider-specific configuration map
|
||||||
|
const providerHandlers: Record<string, () => void> = {
|
||||||
|
openai: () => {
|
||||||
|
const cfg = config.openai ?? DEFAULT_WEB_SEARCH_CONFIG.openai
|
||||||
|
applyToolBasedSearch(params, 'web_search', openai.tools.webSearch(cfg))
|
||||||
|
},
|
||||||
|
'openai-chat': () => {
|
||||||
|
const cfg = (config['openai-chat'] ?? DEFAULT_WEB_SEARCH_CONFIG['openai-chat']) as OpenAISearchPreviewConfig
|
||||||
|
applyToolBasedSearch(params, 'web_search_preview', openai.tools.webSearchPreview(cfg))
|
||||||
|
},
|
||||||
|
anthropic: () => {
|
||||||
|
const cfg = config.anthropic ?? DEFAULT_WEB_SEARCH_CONFIG.anthropic
|
||||||
|
applyToolBasedSearch(params, 'web_search', anthropic.tools.webSearch_20250305(cfg))
|
||||||
|
},
|
||||||
|
google: () => {
|
||||||
|
const cfg = (config.google ?? DEFAULT_WEB_SEARCH_CONFIG.google) as GoogleSearchConfig
|
||||||
|
applyToolBasedSearch(params, 'web_search', google.tools.googleSearch(cfg))
|
||||||
|
},
|
||||||
|
xai: () => {
|
||||||
|
const cfg = config.xai ?? DEFAULT_WEB_SEARCH_CONFIG.xai
|
||||||
|
const searchOptions = createXaiOptions({ searchParameters: { ...cfg, mode: 'on' } })
|
||||||
|
applyProviderOptionsSearch(params, searchOptions)
|
||||||
|
},
|
||||||
|
openrouter: () => {
|
||||||
|
const cfg = (config.openrouter ?? DEFAULT_WEB_SEARCH_CONFIG.openrouter) as OpenRouterSearchConfig
|
||||||
|
const searchOptions = createOpenRouterOptions(cfg)
|
||||||
|
applyProviderOptionsSearch(params, searchOptions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try provider-specific handler first
|
||||||
|
const handler = providerId && providerHandlers[providerId]
|
||||||
|
if (handler) {
|
||||||
|
handler()
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: apply based on available config keys (prioritized order)
|
||||||
|
const fallbackOrder: Array<keyof WebSearchPluginConfig> = [
|
||||||
|
'openai',
|
||||||
|
'openai-chat',
|
||||||
|
'anthropic',
|
||||||
|
'google',
|
||||||
|
'xai',
|
||||||
|
'openrouter'
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const key of fallbackOrder) {
|
||||||
|
if (config[key]) {
|
||||||
|
providerHandlers[key]()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,8 +17,22 @@ export const webSearchPlugin = (config: WebSearchPluginConfig = DEFAULT_WEB_SEAR
|
|||||||
name: 'webSearch',
|
name: 'webSearch',
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
|
|
||||||
transformParams: async (params: any) => {
|
transformParams: async (params: any, context) => {
|
||||||
switchWebSearchTool(config, params)
|
let { providerId } = context
|
||||||
|
|
||||||
|
// For cherryin providers, extract the actual provider from the model's provider string
|
||||||
|
// Expected format: "cherryin.{actualProvider}" (e.g., "cherryin.gemini")
|
||||||
|
if (providerId === 'cherryin' || providerId === 'cherryin-chat') {
|
||||||
|
const provider = params.model?.provider
|
||||||
|
if (provider && typeof provider === 'string' && provider.includes('.')) {
|
||||||
|
const extractedProviderId = provider.split('.')[1]
|
||||||
|
if (extractedProviderId) {
|
||||||
|
providerId = extractedProviderId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switchWebSearchTool(config, params, { ...context, providerId })
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user