Save tool calls to visible chats.
| @@ -3571,7 +3571,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3571 | } | 3571 | } |
| 3572 | 3572 | ||
| 3573 | // Collect messages with usable content | 3573 | // Collect messages with usable content |
| 3574 | let coreChat = chat.filter(x => !x.is_system); | 3574 | const canUseTools = ToolManager.isToolCallingSupported(); |
| 3575 | const canPerformToolCalls = !dryRun && ToolManager.canPerformToolCalls(type); | ||
| 3576 | let coreChat = chat.filter(x => !x.is_system || (canUseTools && Array.isArray(x.extra?.tool_invocations))); | ||
| 3575 | if (type === 'swipe') { | 3577 | if (type === 'swipe') { |
| 3576 | coreChat.pop(); | 3578 | coreChat.pop(); |
| 3577 | } | 3579 | } |
| @@ -4406,8 +4408,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4406 | getMessage = continue_mag + getMessage; | 4408 | getMessage = continue_mag + getMessage; |
| 4407 | } | 4409 | } |
| 4408 | 4410 | ||
| 4409 | if (ToolManager.isFunctionCallingSupported() && Array.isArray(streamingProcessor.toolCalls) && streamingProcessor.toolCalls.length) { | 4411 | if (canPerformToolCalls && Array.isArray(streamingProcessor.toolCalls) && streamingProcessor.toolCalls.length) { |
| 4410 | const invocations = await ToolManager.checkFunctionToolCalls(streamingProcessor.toolCalls); | 4412 | const invocations = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls); |
| 4411 | if (Array.isArray(invocations) && invocations.length) { | 4413 | if (Array.isArray(invocations) && invocations.length) { |
| 4412 | const lastMessage = chat[chat.length - 1]; | 4414 | const lastMessage = chat[chat.length - 1]; |
| 4413 | const shouldDeleteMessage = ['', '...'].includes(lastMessage?.mes) && ['', '...'].includes(streamingProcessor.result); | 4415 | const shouldDeleteMessage = ['', '...'].includes(lastMessage?.mes) && ['', '...'].includes(streamingProcessor.result); |
| @@ -4455,14 +4457,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4455 | throw new Error(data?.response); | 4457 | throw new Error(data?.response); |
| 4456 | } | 4458 | } |
| 4457 | 4459 | ||
| 4458 | if (ToolManager.isFunctionCallingSupported()) { | ||
| 4459 | const invocations = await ToolManager.checkFunctionToolCalls(data); | ||
| 4460 | if (Array.isArray(invocations) && invocations.length) { | ||
| 4461 | ToolManager.saveFunctionToolInvocations(invocations); | ||
| 4462 | return Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName }, dryRun); | ||
| 4463 | } | ||
| 4464 | } | ||
| 4465 | |||
| 4466 | //const getData = await response.json(); | 4460 | //const getData = await response.json(); |
| 4467 | let getMessage = extractMessageFromData(data); | 4461 | let getMessage = extractMessageFromData(data); |
| 4468 | let title = extractTitleFromData(data); | 4462 | let title = extractTitleFromData(data); |
| @@ -4502,6 +4496,16 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4502 | parseAndSaveLogprobs(data, continue_mag); | 4496 | parseAndSaveLogprobs(data, continue_mag); |
| 4503 | } | 4497 | } |
| 4504 | 4498 | ||
| 4499 | if (canPerformToolCalls) { | ||
| 4500 | const invocations = await ToolManager.invokeFunctionTools(data); | ||
| 4501 | if (Array.isArray(invocations) && invocations.length) { | ||
| 4502 | const shouldDeleteMessage = ['', '...'].includes(getMessage); | ||
| 4503 | shouldDeleteMessage && await deleteLastMessage(); | ||
| 4504 | ToolManager.saveFunctionToolInvocations(invocations); | ||
| 4505 | return Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName }, dryRun); | ||
| 4506 | } | ||
| 4507 | } | ||
| 4508 | |||
| 4505 | if (type !== 'quiet') { | 4509 | if (type !== 'quiet') { |
| 4506 | playMessageSound(); | 4510 | playMessageSound(); |
| 4507 | } | 4511 | } |
| @@ -703,7 +703,7 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 703 | } | 703 | } |
| 704 | 704 | ||
| 705 | const imageInlining = isImageInliningSupported(); | 705 | const imageInlining = isImageInliningSupported(); |
| 706 | const toolCalling = ToolManager.isFunctionCallingSupported(); | 706 | const canUseTools = ToolManager.isToolCallingSupported(); |
| 707 | 707 | ||
| 708 | // Insert chat messages as long as there is budget available | 708 | // Insert chat messages as long as there is budget available |
| 709 | const chatPool = [...messages].reverse(); | 709 | const chatPool = [...messages].reverse(); |
| @@ -725,10 +725,10 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 725 | await chatMessage.addImage(chatPrompt.image); | 725 | await chatMessage.addImage(chatPrompt.image); |
| 726 | } | 726 | } |
| 727 | 727 | ||
| 728 | if (toolCalling && Array.isArray(chatPrompt.invocations)) { | 728 | if (canUseTools && Array.isArray(chatPrompt.invocations)) { |
| 729 | /** @type {import('./tool-calling.js').ToolInvocation[]} */ | 729 | /** @type {import('./tool-calling.js').ToolInvocation[]} */ |
| 730 | const invocations = chatPrompt.invocations; | 730 | const invocations = chatPrompt.invocations; |
| 731 | const toolCallMessage = new Message('assistant', undefined, 'toolCall-' + chatMessage.identifier); | 731 | const toolCallMessage = new Message(chatMessage.role, undefined, 'toolCall-' + chatMessage.identifier); |
| 732 | toolCallMessage.setToolCalls(invocations); | 732 | toolCallMessage.setToolCalls(invocations); |
| 733 | if (chatCompletion.canAfford(toolCallMessage)) { | 733 | if (chatCompletion.canAfford(toolCallMessage)) { |
| 734 | chatCompletion.reserveBudget(toolCallMessage); | 734 | chatCompletion.reserveBudget(toolCallMessage); |
| @@ -1285,7 +1285,7 @@ export async function prepareOpenAIMessages({ | |||
| 1285 | const eventData = { chat, dryRun }; | 1285 | const eventData = { chat, dryRun }; |
| 1286 | await eventSource.emit(event_types.CHAT_COMPLETION_PROMPT_READY, eventData); | 1286 | await eventSource.emit(event_types.CHAT_COMPLETION_PROMPT_READY, eventData); |
| 1287 | 1287 | ||
| 1288 | openai_messages_count = chat.filter(x => x?.role === 'user' || x?.role === 'assistant')?.length || 0; | 1288 | openai_messages_count = chat.filter(x => !x?.tool_calls && (x?.role === 'user' || x?.role === 'assistant'))?.length || 0; |
| 1289 | 1289 | ||
| 1290 | return [chat, promptManager.tokenHandler.counts]; | 1290 | return [chat, promptManager.tokenHandler.counts]; |
| 1291 | } | 1291 | } |
| @@ -1886,7 +1886,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1886 | generate_data['seed'] = oai_settings.seed; | 1886 | generate_data['seed'] = oai_settings.seed; |
| 1887 | } | 1887 | } |
| 1888 | 1888 | ||
| 1889 | if (!canMultiSwipe && ToolManager.isFunctionCallingSupported()) { | 1889 | if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) { |
| 1890 | await ToolManager.registerFunctionToolsOpenAI(generate_data); | 1890 | await ToolManager.registerFunctionToolsOpenAI(generate_data); |
| 1891 | } | 1891 | } |
| 1892 | 1892 | ||
| @@ -2393,13 +2393,20 @@ class MessageCollection { | |||
| 2393 | } | 2393 | } |
| 2394 | 2394 | ||
| 2395 | /** | 2395 | /** |
| 2396 | * Get chat in the format of {role, name, content}. | 2396 | * Get chat in the format of {role, name, content, tool_calls}. |
| 2397 | * @returns {Array} Array of objects with role, name, and content properties. | 2397 | * @returns {Array} Array of objects with role, name, and content properties. |
| 2398 | */ | 2398 | */ |
| 2399 | getChat() { | 2399 | getChat() { |
| 2400 | return this.collection.reduce((acc, message) => { | 2400 | return this.collection.reduce((acc, message) => { |
| 2401 | const name = message.name; | 2401 | if (message.content || message.tool_calls) { |
| 2402 | if (message.content) acc.push({ role: message.role, ...(name && { name }), content: message.content }); | 2402 | acc.push({ |
| 2403 | role: message.role, | ||
| 2404 | content: message.content, | ||
| 2405 | ...(message.name && { name: message.name }), | ||
| 2406 | ...(message.tool_calls && { tool_calls: message.tool_calls }), | ||
| 2407 | ...(message.role === 'tool' && { tool_call_id: message.identifier }), | ||
| 2408 | }); | ||
| 2409 | } | ||
| 2403 | return acc; | 2410 | return acc; |
| 2404 | }, []); | 2411 | }, []); |
| 2405 | } | 2412 | } |
| @@ -1,4 +1,4 @@ | |||
| 1 | import { chat, main_api } from '../script.js'; | 1 | import { addOneMessage, chat, main_api, system_avatar, systemUserName } from '../script.js'; |
| 2 | import { chat_completion_sources, oai_settings } from './openai.js'; | 2 | import { chat_completion_sources, oai_settings } from './openai.js'; |
| 3 | 3 | ||
| 4 | /** | 4 | /** |
| @@ -243,12 +243,12 @@ export class ToolManager { | |||
| 243 | } | 243 | } |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | static isFunctionCallingSupported() { | 246 | /** |
| 247 | if (main_api !== 'openai') { | 247 | * Checks if tool calling is supported for the current settings and generation type. |
| 248 | return false; | 248 | * @returns {boolean} Whether tool calling is supported for the given type |
| 249 | } | 249 | */ |
| 250 | 250 | static isToolCallingSupported() { | |
| 251 | if (!oai_settings.function_calling) { | 251 | if (main_api !== 'openai' || !oai_settings.function_calling) { |
| 252 | return false; | 252 | return false; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| @@ -264,6 +264,22 @@ export class ToolManager { | |||
| 264 | return supportedSources.includes(oai_settings.chat_completion_source); | 264 | return supportedSources.includes(oai_settings.chat_completion_source); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | /** | ||
| 268 | * Checks if tool calls can be performed for the current settings and generation type. | ||
| 269 | * @param {string} type Generation type | ||
| 270 | * @returns {boolean} Whether tool calls can be performed for the given type | ||
| 271 | */ | ||
| 272 | static canPerformToolCalls(type) { | ||
| 273 | const noToolCallTypes = ['swipe', 'impersonate', 'quiet', 'continue']; | ||
| 274 | const isSupported = ToolManager.isToolCallingSupported(); | ||
| 275 | return isSupported && !noToolCallTypes.includes(type); | ||
| 276 | } | ||
| 277 | |||
| 278 | /** | ||
| 279 | * Utility function to get tool calls from the response data. | ||
| 280 | * @param {any} data Response data | ||
| 281 | * @returns {any[]} Tool calls from the response data | ||
| 282 | */ | ||
| 267 | static #getToolCallsFromData(data) { | 283 | static #getToolCallsFromData(data) { |
| 268 | // Parsed tool calls from streaming data | 284 | // Parsed tool calls from streaming data |
| 269 | if (Array.isArray(data) && data.length > 0) { | 285 | if (Array.isArray(data) && data.length > 0) { |
| @@ -290,15 +306,11 @@ export class ToolManager { | |||
| 290 | * @param {any} data Reply data | 306 | * @param {any} data Reply data |
| 291 | * @returns {Promise<ToolInvocation[]>} Successful tool invocations | 307 | * @returns {Promise<ToolInvocation[]>} Successful tool invocations |
| 292 | */ | 308 | */ |
| 293 | static async checkFunctionToolCalls(data) { | 309 | static async invokeFunctionTools(data) { |
| 294 | if (!ToolManager.isFunctionCallingSupported()) { | ||
| 295 | return []; | ||
| 296 | } | ||
| 297 | |||
| 298 | /** @type {ToolInvocation[]} */ | 310 | /** @type {ToolInvocation[]} */ |
| 299 | const invocations = []; | 311 | const invocations = []; |
| 300 | const toolCalls = ToolManager.#getToolCallsFromData(data); | 312 | const toolCalls = ToolManager.#getToolCallsFromData(data); |
| 301 | const oaiCompat = [ | 313 | const oaiCompatibleSources = [ |
| 302 | chat_completion_sources.OPENAI, | 314 | chat_completion_sources.OPENAI, |
| 303 | chat_completion_sources.CUSTOM, | 315 | chat_completion_sources.CUSTOM, |
| 304 | chat_completion_sources.MISTRALAI, | 316 | chat_completion_sources.MISTRALAI, |
| @@ -306,7 +318,7 @@ export class ToolManager { | |||
| 306 | chat_completion_sources.GROQ, | 318 | chat_completion_sources.GROQ, |
| 307 | ]; | 319 | ]; |
| 308 | 320 | ||
| 309 | if (oaiCompat.includes(oai_settings.chat_completion_source)) { | 321 | if (oaiCompatibleSources.includes(oai_settings.chat_completion_source)) { |
| 310 | if (!Array.isArray(toolCalls)) { | 322 | if (!Array.isArray(toolCalls)) { |
| 311 | return []; | 323 | return []; |
| 312 | } | 324 | } |
| @@ -323,7 +335,7 @@ export class ToolManager { | |||
| 323 | 335 | ||
| 324 | toastr.info('Invoking function tool: ' + name); | 336 | toastr.info('Invoking function tool: ' + name); |
| 325 | const result = await ToolManager.invokeFunctionTool(name, parameters); | 337 | const result = await ToolManager.invokeFunctionTool(name, parameters); |
| 326 | toastr.info('Function tool result: ' + result); | 338 | console.log('Function tool result:', result); |
| 327 | 339 | ||
| 328 | // Save a successful invocation | 340 | // Save a successful invocation |
| 329 | if (result) { | 341 | if (result) { |
| @@ -367,15 +379,19 @@ export class ToolManager { | |||
| 367 | * @param {ToolInvocation[]} invocations Successful tool invocations | 379 | * @param {ToolInvocation[]} invocations Successful tool invocations |
| 368 | */ | 380 | */ |
| 369 | static saveFunctionToolInvocations(invocations) { | 381 | static saveFunctionToolInvocations(invocations) { |
| 370 | for (let index = chat.length - 1; index >= 0; index--) { | 382 | const toolNames = invocations.map(i => i.name).join(', '); |
| 371 | const message = chat[index]; | 383 | const message = { |
| 372 | if (message.is_user) { | 384 | name: systemUserName, |
| 373 | if (!message.extra || typeof message.extra !== 'object') { | 385 | force_avatar: system_avatar, |
| 374 | message.extra = {}; | 386 | is_system: true, |
| 375 | } | 387 | is_user: false, |
| 376 | message.extra.tool_invocations = invocations; | 388 | mes: `Performed tool calls: ${toolNames}`, |
| 377 | break; | 389 | extra: { |
| 378 | } | 390 | isSmallSys: true, |
| 379 | } | 391 | tool_invocations: invocations, |
| 392 | }, | ||
| 393 | }; | ||
| 394 | chat.push(message); | ||
| 395 | addOneMessage(message); | ||
| 380 | } | 396 | } |
| 381 | } | 397 | } |