Merge pull request #3971 from SillyTavern/ccllaauuddee Assorted Claude adjustments

104d4ccebcbf593b5dc6b31ca09632004d5987d3

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
3 files changed, +21 -14Ignore whitespace
public/index.html+1 -1
@@ -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>
src/endpoints/backends/chat-completions.js+17 -11
@@ -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 sequences153 // 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 }));
185186
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 }
194191
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 }
@@ -200,11 +205,12 @@ async function sendClaudeRequest(request, response) {
200 betaHeaders.push('prompt-caching-2024-07-31');205 betaHeaders.push('prompt-caching-2024-07-31');
201 }206 }
202207
203 if (useThinking) {208 const reasoningEffort = request.body.reasoning_effort;
209 const budgetTokens = calculateClaudeBudgetTokens(requestBody.max_tokens, reasoningEffort, requestBody.stream);
210
211 if (useThinking && Number.isInteger(budgetTokens)) {
204 // No prefill when thinking212 // No prefill when thinking
205 voidPrefill = true;213 fixThinkingPrefill = true;
206 const reasoningEffort = request.body.reasoning_effort;
207 const budgetTokens = calculateClaudeBudgetTokens(requestBody.max_tokens, reasoningEffort, requestBody.stream);
208 const minThinkTokens = 1024;214 const minThinkTokens = 1024;
209 if (requestBody.max_tokens <= minThinkTokens) {215 if (requestBody.max_tokens <= minThinkTokens) {
210 const newValue = requestBody.max_tokens + minThinkTokens;216 const newValue = requestBody.max_tokens + minThinkTokens;
@@ -223,8 +229,8 @@ async function sendClaudeRequest(request, response) {
223 delete requestBody.top_k;229 delete requestBody.top_k;
224 }230 }
225231
226 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') {
227 convertedPrompt.messages.push({ role: 'user', content: [{ type: 'text', text: '\u200b' }] });233 convertedPrompt.messages[convertedPrompt.messages.length - 1].role = 'user';
228 }234 }
229235
230 if (betaHeaders.length) {236 if (betaHeaders.length) {
src/prompt-converters.js+3 -2
@@ -917,19 +917,20 @@ export function cachingAtDepthForOpenRouterClaude(messages, cachingAtDepth) {
917 * @param {number} maxTokens Maximum tokens917 * @param {number} maxTokens Maximum tokens
918 * @param {string} reasoningEffort Reasoning effort918 * @param {string} reasoningEffort Reasoning effort
919 * @param {boolean} stream If streaming is enabled919 * @param {boolean} stream If streaming is enabled
920 * @returns {number} Budget tokens920 * @returns {number?} Budget tokens
921 */921 */
922export function calculateClaudeBudgetTokens(maxTokens, reasoningEffort, stream) {922export function calculateClaudeBudgetTokens(maxTokens, reasoningEffort, stream) {
923 let budgetTokens = 0;923 let budgetTokens = 0;
924924
925 switch (reasoningEffort) {925 switch (reasoningEffort) {
926 case REASONING_EFFORT.auto:
927 return null;
926 case REASONING_EFFORT.min:928 case REASONING_EFFORT.min:
927 budgetTokens = 1024;929 budgetTokens = 1024;
928 break;930 break;
929 case REASONING_EFFORT.low:931 case REASONING_EFFORT.low:
930 budgetTokens = Math.floor(maxTokens * 0.1);932 budgetTokens = Math.floor(maxTokens * 0.1);
931 break;933 break;
932 case REASONING_EFFORT.auto:
933 case REASONING_EFFORT.medium:934 case REASONING_EFFORT.medium:
934 budgetTokens = Math.floor(maxTokens * 0.25);935 budgetTokens = Math.floor(maxTokens * 0.25);
935 break;936 break;