Claude: Use multi-part system prompt, cache tools
| @@ -87,7 +87,7 @@ async function sendClaudeRequest(request, response) { | ||
| 87 | 87 | const apiUrl = new URL(request.body.reverse_proxy || API_CLAUDE).toString(); |
| 88 | 88 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE); |
| 89 | 89 | const divider = '-'.repeat(process.stdout.columns); |
| 90 | 90 | const enableSystemPromptCache = getConfigValue('claude.enableSystemPromptCache', false) && request.body.model.startsWith('claude-3'); |
| 91 | 91 | |
| 92 | 92 | if (!apiKey) { |
| 93 | 93 | console.log(color.red(`Claude API key is missing.\n${divider}`)); |
| @@ -110,7 +110,7 @@ async function sendClaudeRequest(request, response) { | ||
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | const requestBody = { |
| 113 | 113 | /** @type {any} */ system: ''[], |
| 114 | 114 | messages: convertedPrompt.messages, |
| 115 | 115 | model: request.body.model, |
| 116 | 116 | max_tokens: request.body.max_tokens, |
| @@ -121,9 +121,11 @@ async function sendClaudeRequest(request, response) { | ||
| 121 | 121 | stream: request.body.stream, |
| 122 | 122 | }; |
| 123 | 123 | if (useSystemPrompt) { |
| 124 | - requestBody.system = enableSystemPromptCache | |
| 124 | + if (enableSystemPromptCache && Array.isArray(convertedPrompt.systemPrompt) && convertedPrompt.systemPrompt.length) { | |
| 125 | 125 | ? convertedPrompt.systemPrompt[{ type: 'text', text: convertedPrompt.systemPrompt,.length - 1]['cache_control:'] = { type: 'ephemeral' } }]; |
| 126 | - : convertedPrompt.systemPrompt; | |
| 126 | + } | |
| 127 | + | |
| 128 | + requestBody.system = convertedPrompt.systemPrompt; | |
| 127 | 129 | } else { |
| 128 | 130 | delete requestBody.system; |
| 129 | 131 | } |
| @@ -138,6 +140,10 @@ async function sendClaudeRequest(request, response) { | ||
| 138 | 140 | .filter(tool => tool.type === 'function') |
| 139 | 141 | .map(tool => tool.function) |
| 140 | 142 | .map(fn => ({ name: fn.name, description: fn.description, input_schema: fn.parameters })); |
| 143 | + | |
| 144 | + if (enableSystemPromptCache && requestBody.tools.length) { | |
| 145 | + requestBody.tools[requestBody.tools.length - 1]['cache_control'] = { type: 'ephemeral' }; | |
| 146 | + } | |
| 141 | 147 | } |
| 142 | 148 | if (enableSystemPromptCache) { |
| 143 | 149 | additionalHeaders['anthropic-beta'] = 'prompt-caching-2024-07-31'; |
| @@ -95,7 +95,7 @@ function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, | ||
| 95 | 95 | * @param {string} userName User name |
| 96 | 96 | */ |
| 97 | 97 | function convertClaudeMessages(messages, prefillString, useSysPrompt, humanMsgFix, charName = '', userName = '') { |
| 98 | 98 | let systemPrompt = ''[]; |
| 99 | 99 | if (useSysPrompt) { |
| 100 | 100 | // Collect all the system messages up until the first instance of a non-system message, and then remove them from the messages array. |
| 101 | 101 | let i; |
| @@ -114,7 +114,7 @@ function convertClaudeMessages(messages, prefillString, useSysPrompt, humanMsgFi | ||
| 114 | 114 | messages[i].content = `${charName}: ${messages[i].content}`; |
| 115 | 115 | } |
| 116 | 116 | } |
| 117 | - systemPrompt += `${messages[i].content}\n\n`; | |
| 117 | + systemPrompt.push({ type: 'text', text: messages[i].content }); | |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | 120 | messages.splice(0, i); |
| @@ -246,7 +246,7 @@ function convertClaudeMessages(messages, prefillString, useSysPrompt, humanMsgFi | ||
| 246 | 246 | } |
| 247 | 247 | }); |
| 248 | 248 | |
| 249 | 249 | return { messages: mergedMessages, systemPrompt: systemPrompt.trim() }; |
| 250 | 250 | } |
| 251 | 251 | |
| 252 | 252 | /** |