Claude: add web search tool, adjust prefill voiding Closes #3968
| @@ -1963,7 +1963,7 @@ | |||
| 1963 | </span> | 1963 | </span> |
| 1964 | </div> | 1964 | </div> |
| 1965 | </div> | 1965 | </div> |
| 1966 | <div class="range-block" data-source="makersuite,openrouter"> | 1966 | <div class="range-block" data-source="makersuite,openrouter,claude"> |
| 1967 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> | 1967 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> |
| 1968 | <input id="openai_enable_web_search" type="checkbox" /> | 1968 | <input id="openai_enable_web_search" type="checkbox" /> |
| 1969 | <span data-i18n="Enable web search">Enable web search</span> | 1969 | <span data-i18n="Enable web search">Enable web search</span> |
| @@ -148,7 +148,8 @@ async function sendClaudeRequest(request, response) { | |||
| 148 | const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt; | 148 | const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt; |
| 149 | const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, getPromptNames(request)); | 149 | const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, getPromptNames(request)); |
| 150 | const useThinking = request.body.model.startsWith('claude-3-7') && Boolean(request.body.include_reasoning); | 150 | const useThinking = request.body.model.startsWith('claude-3-7') && Boolean(request.body.include_reasoning); |
| 151 | let voidPrefill = false; | 151 | const useWebSearch = /^claude-3-(5|7)/.test(request.body.model) && Boolean(request.body.enable_web_search); |
| 152 | let fixThinkingPrefill = false; | ||
| 152 | // Add custom stop sequences | 153 | // Add custom stop sequences |
| 153 | const stopSequences = []; | 154 | const stopSequences = []; |
| 154 | if (Array.isArray(request.body.stop)) { | 155 | if (Array.isArray(request.body.stop)) { |
| @@ -183,15 +184,19 @@ async function sendClaudeRequest(request, response) { | |||
| 183 | .map(tool => tool.function) | 184 | .map(tool => tool.function) |
| 184 | .map(fn => ({ name: fn.name, description: fn.description, input_schema: fn.parameters })); | 185 | .map(fn => ({ name: fn.name, description: fn.description, input_schema: fn.parameters })); |
| 185 | 186 | ||
| 186 | if (requestBody.tools.length) { | ||
| 187 | // No prefill when using tools | ||
| 188 | voidPrefill = true; | ||
| 189 | } | ||
| 190 | if (enableSystemPromptCache && requestBody.tools.length) { | 187 | if (enableSystemPromptCache && requestBody.tools.length) { |
| 191 | requestBody.tools[requestBody.tools.length - 1]['cache_control'] = { type: 'ephemeral' }; | 188 | requestBody.tools[requestBody.tools.length - 1]['cache_control'] = { type: 'ephemeral' }; |
| 192 | } | 189 | } |
| 193 | } | 190 | } |
| 194 | 191 | ||
| 192 | if (useWebSearch) { | ||
| 193 | const webSearchTool = [{ | ||
| 194 | 'type': 'web_search_20250305', | ||
| 195 | 'name': 'web_search', | ||
| 196 | }]; | ||
| 197 | requestBody.tools = [...(requestBody.tools || []), ...webSearchTool]; | ||
| 198 | } | ||
| 199 | |||
| 195 | if (cachingAtDepth !== -1) { | 200 | if (cachingAtDepth !== -1) { |
| 196 | cachingAtDepthForClaude(convertedPrompt.messages, cachingAtDepth); | 201 | cachingAtDepthForClaude(convertedPrompt.messages, cachingAtDepth); |
| 197 | } | 202 | } |
| @@ -205,7 +210,7 @@ async function sendClaudeRequest(request, response) { | |||
| 205 | 210 | ||
| 206 | if (useThinking && Number.isInteger(budgetTokens)) { | 211 | if (useThinking && Number.isInteger(budgetTokens)) { |
| 207 | // No prefill when thinking | 212 | // No prefill when thinking |
| 208 | voidPrefill = true; | 213 | fixThinkingPrefill = true; |
| 209 | const minThinkTokens = 1024; | 214 | const minThinkTokens = 1024; |
| 210 | if (requestBody.max_tokens <= minThinkTokens) { | 215 | if (requestBody.max_tokens <= minThinkTokens) { |
| 211 | const newValue = requestBody.max_tokens + minThinkTokens; | 216 | const newValue = requestBody.max_tokens + minThinkTokens; |
| @@ -224,8 +229,8 @@ async function sendClaudeRequest(request, response) { | |||
| 224 | delete requestBody.top_k; | 229 | delete requestBody.top_k; |
| 225 | } | 230 | } |
| 226 | 231 | ||
| 227 | if (voidPrefill && convertedPrompt.messages.length && convertedPrompt.messages[convertedPrompt.messages.length - 1].role === 'assistant') { | 232 | if (fixThinkingPrefill && convertedPrompt.messages.length && convertedPrompt.messages[convertedPrompt.messages.length - 1].role === 'assistant') { |
| 228 | convertedPrompt.messages.push({ role: 'user', content: [{ type: 'text', text: '\u200b' }] }); | 233 | convertedPrompt.messages[convertedPrompt.messages.length - 1].role = 'user'; |
| 229 | } | 234 | } |
| 230 | 235 | ||
| 231 | if (betaHeaders.length) { | 236 | if (betaHeaders.length) { |