From ffe901e1ffc8d3b29e5c58b0b873eeb5257b3405 Mon Sep 17 00:00:00 2001 From: Sven Olderaan Date: Fri, 14 Mar 2025 21:49:09 +0100 Subject: [PATCH] Fix tool registration using SillyTavern's native API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Refactored registerFunctionTool to follow Dice extension's pattern - Now uses context.registerFunctionTool with proper JSON schema format - Simplified initialization with cleaner retry logic - Removed redundant registration methods - Added proper schema definition with Object.freeze pattern 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- index.js | 182 +++++++++++++++---------------------------------------- 1 file changed, 50 insertions(+), 132 deletions(-) diff --git a/index.js b/index.js index db93b76..8a02899 100644 --- a/index.js +++ b/index.js @@ -95,106 +95,51 @@ function onTestButtonClick() { // Register function tool function registerFunctionTool() { try { - // Register the function in the most direct way to the window - window.generateChatBubbleImage = generateChatBubbleImage; - console.log(`[${extensionName}] Registered function to window object`); - - // Method 1: Try through window.SillyTavern API if it exists - if (window.SillyTavern?.getContext) { - try { - const api = window.SillyTavern; - const context = api.getContext(); - - // Add to context directly - context.generateChatBubbleImage = generateChatBubbleImage; - console.log(`[${extensionName}] Function added to SillyTavern context API`); - - // If registerCustomFunction exists, use it - if (typeof api.registerCustomFunction === 'function') { - api.registerCustomFunction('generateChatBubbleImage', generateChatBubbleImage); - console.log(`[${extensionName}] Function registered via SillyTavern API`); - } - } catch (error) { - console.warn(`[${extensionName}] Error registering with SillyTavern API:`, error); - } - } - - // Method 2: Try through extensions_functions if it exists - if (window.extensions_functions) { - window.extensions_functions['generateChatBubbleImage'] = generateChatBubbleImage; - console.log(`[${extensionName}] Added to extensions_functions`); - } - - // Method 3: Try with ToolManager if it exists - if (window.ToolManager) { - try { - // Check if tool calling is supported - if (typeof window.ToolManager.isToolCallingSupported === 'function' && - window.ToolManager.isToolCallingSupported()) { - - // Define the function parameters schema - const parameters = { - "type": "object", - "properties": { - "text": { - "type": "string", - "description": "The text to display in the chat bubble" - }, - "style": { - "type": "string", - "description": "The visual style of the chat bubble (default, modern, retro, minimal)" - } + // Add function directly to context + const context = getContext(); + if (context) { + context.generateChatBubbleImage = generateChatBubbleImage; + console.log(`[${extensionName}] Function added to context: generateChatBubbleImage`); + + // Check if registerFunctionTool exists in context + if (typeof context.registerFunctionTool === 'function') { + // Define parameter schema following JSON schema format + const bubbleSchema = Object.freeze({ + $schema: 'http://json-schema.org/draft-04/schema#', + type: 'object', + properties: { + text: { + type: 'string', + description: 'The text to display in the chat bubble' }, - "required": ["text"] - }; - - // Register the tool - window.ToolManager.registerFunctionTool({ - name: 'generateChatBubbleImage', - displayName: 'Generate Chat Bubble', - description: 'Creates a markdown image link with the text displayed as a chat bubble', - parameters: parameters, - action: async (params) => { - return generateChatBubbleImage(params.text, params.style); + style: { + type: 'string', + description: 'The visual style of the chat bubble (default, modern, retro, minimal)' }, - formatMessage: async (params) => { - return `Generating chat bubble with text: "${params.text?.substring(0, 30)}${params.text?.length > 30 ? '...' : ''}"`; - } - }); - - console.log(`[${extensionName}] Function tool registered via ToolManager`); - } else { - console.warn(`[${extensionName}] Tool calling is not supported in the current configuration`); - } - } catch (error) { - console.error(`[${extensionName}] Error registering with ToolManager:`, error); - } - } - - // Method 4: Try to register globally as a function call format - // This creates a special object that some AI models might recognize - window.AI_FUNCTION_generateChatBubbleImage = { - name: 'generateChatBubbleImage', - description: 'Creates a markdown image link with the text displayed as a chat bubble', - parameters: { - type: 'object', - properties: { - text: { - type: 'string', - description: 'The text to display in the chat bubble' }, - style: { - type: 'string', - description: 'The visual style of the chat bubble (optional)' - } - }, - required: ['text'] - }, - function: generateChatBubbleImage - }; - - console.log(`[${extensionName}] Created special AI function format object`); - + required: ['text'] + }); + + // Register the function tool using SillyTavern's own API + context.registerFunctionTool({ + name: 'generateChatBubbleImage', + displayName: 'Chat Bubble Image', + description: 'Creates a markdown image link with the text displayed as a styled chat bubble. Use when you want to visually style messages or display text in a speech bubble.', + parameters: bubbleSchema, + action: async (args) => { + if (!args?.text) return ''; + return generateChatBubbleImage(args.text, args.style); + }, + formatMessage: () => '', + }); + + console.log(`[${extensionName}] Function tool registered via context.registerFunctionTool`); + } else { + console.warn(`[${extensionName}] registerFunctionTool not available in context`); + } + } else { + console.warn(`[${extensionName}] Unable to get context for function registration`); + } } catch (error) { console.error(`[${extensionName}] Error registering function tool:`, error); } @@ -216,46 +161,19 @@ jQuery(async () => { $("#sillybubble_default_style").on("input", onDefaultStyleInput); $("#sillybubble_test_button").on("click", onTestButtonClick); - // First registration attempt immediately + // Initial attempt to register the function tool registerFunctionTool(); - // Try to add to context immediately - try { - const context = getContext(); - if (context) { - // Make the function available to the AI - context.generateChatBubbleImage = generateChatBubbleImage; - console.log(`[${extensionName}] Function added to context: generateChatBubbleImage`); - } - } catch (error) { - console.error(`[${extensionName}] Error adding function to context:`, error); - } + // Make function globally accessible as fallback + window.generateChatBubbleImage = generateChatBubbleImage; - // Wait for the document to fully load before trying again + // Wait for SillyTavern to fully initialize, then register again $(document).ready(() => { - // Try registration again after a short delay - setTimeout(() => { - registerFunctionTool(); - - // Add function to global window for direct accessibility - window.generateChatBubbleImage = generateChatBubbleImage; - - // Also add explicit API function definition for direct calling - window.SILLYBUBBLE_FUNCTION = { - name: 'generateChatBubbleImage', - call: function(text, style) { - return generateChatBubbleImage(text, style); - } - }; - - console.log(`[${extensionName}] Function registration and context setup completed`); - }, 2000); // Wait 2 seconds for SillyTavern to initialize + // Try again after a short delay + setTimeout(() => registerFunctionTool(), 2000); - // One final attempt after 10 seconds - setTimeout(() => { - registerFunctionTool(); - console.log(`[${extensionName}] Final function registration attempt completed`); - }, 10000); + // Final attempt after SillyTavern is fully loaded + setTimeout(() => registerFunctionTool(), 10000); }); // Load settings