mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Show an error when all tools fail
This commit is contained in:
@@ -4420,10 +4420,18 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
const lastMessage = chat[chat.length - 1];
|
||||
const shouldDeleteMessage = ['', '...'].includes(lastMessage?.mes) && ['', '...'].includes(streamingProcessor.result);
|
||||
shouldDeleteMessage && await deleteLastMessage();
|
||||
const invocations = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls);
|
||||
if (Array.isArray(invocations) && invocations.length) {
|
||||
const invocationResult = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls);
|
||||
if (invocationResult.hadToolCalls) {
|
||||
if (!invocationResult.invocations.length && shouldDeleteMessage) {
|
||||
ToolManager.showToolCallError(invocationResult.errors);
|
||||
unblockGeneration(type);
|
||||
generatedPromptCache = '';
|
||||
streamingProcessor = null;
|
||||
ToolManager.saveFunctionToolInvocations(invocations);
|
||||
return;
|
||||
}
|
||||
|
||||
streamingProcessor = null;
|
||||
ToolManager.saveFunctionToolInvocations(invocationResult.invocations);
|
||||
return Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName }, dryRun);
|
||||
}
|
||||
}
|
||||
@@ -4505,9 +4513,16 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
if (canPerformToolCalls) {
|
||||
const shouldDeleteMessage = ['', '...'].includes(getMessage);
|
||||
shouldDeleteMessage && await deleteLastMessage();
|
||||
const invocations = await ToolManager.invokeFunctionTools(data);
|
||||
if (Array.isArray(invocations) && invocations.length) {
|
||||
ToolManager.saveFunctionToolInvocations(invocations);
|
||||
const invocationResult = await ToolManager.invokeFunctionTools(data);
|
||||
if (invocationResult.hadToolCalls) {
|
||||
if (!invocationResult.invocations.length && shouldDeleteMessage) {
|
||||
ToolManager.showToolCallError(invocationResult.errors);
|
||||
unblockGeneration(type);
|
||||
generatedPromptCache = '';
|
||||
return;
|
||||
}
|
||||
|
||||
ToolManager.saveFunctionToolInvocations(invocationResult.invocations);
|
||||
return Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName }, dryRun);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { addOneMessage, chat, main_api, system_avatar, systemUserName } from '../script.js';
|
||||
import { chat_completion_sources, oai_settings } from './openai.js';
|
||||
import { Popup } from './popup.js';
|
||||
|
||||
/**
|
||||
* @typedef {object} ToolInvocation
|
||||
@@ -9,6 +10,13 @@ import { chat_completion_sources, oai_settings } from './openai.js';
|
||||
* @property {string} result - The result of the tool invocation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} ToolInvocationResult
|
||||
* @property {ToolInvocation[]} invocations Successful tool invocations
|
||||
* @property {boolean} hadToolCalls Whether any tool calls were found
|
||||
* @property {Error[]} errors Errors that occurred during tool invocation
|
||||
*/
|
||||
|
||||
/**
|
||||
* A class that represents a tool definition.
|
||||
*/
|
||||
@@ -129,7 +137,7 @@ export class ToolManager {
|
||||
* Invokes a tool by name. Returns the result of the tool's action function.
|
||||
* @param {string} name The name of the tool to invoke.
|
||||
* @param {object} parameters Function parameters. For example, if the tool requires a "name" parameter, you would pass {name: "value"}.
|
||||
* @returns {Promise<string|null>} The result of the tool's action function. If an error occurs, null is returned. Non-string results are JSON-stringified.
|
||||
* @returns {Promise<string|Error>} The result of the tool's action function. If an error occurs, null is returned. Non-string results are JSON-stringified.
|
||||
*/
|
||||
static async invokeFunctionTool(name, parameters) {
|
||||
try {
|
||||
@@ -143,7 +151,13 @@ export class ToolManager {
|
||||
return typeof result === 'string' ? result : JSON.stringify(result);
|
||||
} catch (error) {
|
||||
console.error(`An error occurred while invoking the tool "${name}":`, error);
|
||||
return null;
|
||||
|
||||
if (error instanceof Error) {
|
||||
error.cause = name;
|
||||
return error;
|
||||
}
|
||||
|
||||
return new Error('Unknown error occurred while invoking the tool.', { cause: name });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,11 +320,15 @@ export class ToolManager {
|
||||
/**
|
||||
* Check for function tool calls in the response data and invoke them.
|
||||
* @param {any} data Reply data
|
||||
* @returns {Promise<ToolInvocation[]>} Successful tool invocations
|
||||
* @returns {Promise<ToolInvocationResult>} Successful tool invocations
|
||||
*/
|
||||
static async invokeFunctionTools(data) {
|
||||
/** @type {ToolInvocation[]} */
|
||||
const invocations = [];
|
||||
/** @type {ToolInvocationResult} */
|
||||
const result = {
|
||||
invocations: [],
|
||||
hadToolCalls: false,
|
||||
errors: [],
|
||||
};
|
||||
const toolCalls = ToolManager.#getToolCallsFromData(data);
|
||||
const oaiCompatibleSources = [
|
||||
chat_completion_sources.OPENAI,
|
||||
@@ -322,7 +340,7 @@ export class ToolManager {
|
||||
|
||||
if (oaiCompatibleSources.includes(oai_settings.chat_completion_source)) {
|
||||
if (!Array.isArray(toolCalls)) {
|
||||
return [];
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const toolCall of toolCalls) {
|
||||
@@ -334,16 +352,20 @@ export class ToolManager {
|
||||
const id = toolCall.id;
|
||||
const parameters = toolCall.function.arguments;
|
||||
const name = toolCall.function.name;
|
||||
result.hadToolCalls = true;
|
||||
|
||||
const toast = toastr.info(`Invoking function tool: ${name}`);
|
||||
const result = await ToolManager.invokeFunctionTool(name, parameters);
|
||||
const toolResult = await ToolManager.invokeFunctionTool(name, parameters);
|
||||
toastr.clear(toast);
|
||||
console.log('Function tool result:', result);
|
||||
|
||||
// Save a successful invocation
|
||||
if (result) {
|
||||
invocations.push({ id, name, parameters, result });
|
||||
if (toolResult instanceof Error) {
|
||||
result.errors.push(toolResult);
|
||||
continue;
|
||||
}
|
||||
|
||||
result.invocations.push({ id, name, parameters, result: toolResult });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +396,7 @@ export class ToolManager {
|
||||
}
|
||||
*/
|
||||
|
||||
return invocations;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,4 +440,16 @@ export class ToolManager {
|
||||
chat.push(message);
|
||||
addOneMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an error message for tool calls.
|
||||
* @param {Error[]} errors Errors that occurred during tool invocation
|
||||
* @returns {void}
|
||||
*/
|
||||
static showToolCallError(errors) {
|
||||
toastr.error('An error occurred while invoking function tools. Click here for more details.', 'Tool Calling', {
|
||||
onclick: () => Popup.show.text('Tool Calling Errors', DOMPurify.sanitize(errors.map(e => `${e.cause}: ${e.message}`).join('<br>'))),
|
||||
timeOut: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -421,6 +421,7 @@ small {
|
||||
.mes.smallSysMes pre {
|
||||
text-align: initial;
|
||||
word-break: break-all;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.mes.smallSysMes summary {
|
||||
|
Reference in New Issue
Block a user