Improve function registration for SillyBubble extension
- Use the proper ToolManager API when available - Add fallback mechanisms when ToolManager is not available - Fix extension settings handling to use the standard pattern - Implement proper JSON schema for function parameters - Add delayed initialization to ensure SillyTavern is fully loaded - Add better error handling and logging 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5ccb1d3984
commit
247abbe91a
196
index.js
196
index.js
@ -1,31 +1,42 @@
|
||||
// SillyBubble - Dynamic Chat Bubble Image Generation Extension
|
||||
import { extension_settings, getContext, loadExtensionSettings, registerCustomFunction } from "../../../extensions.js";
|
||||
import { saveSettingsDebounced, callPopup, substituteParams } from "../../../../script.js";
|
||||
import { extension_settings, getContext } from "../../../extensions.js";
|
||||
import { saveSettingsDebounced, callPopup } from "../../../../script.js";
|
||||
|
||||
// Extension configuration
|
||||
const extensionName = "SillyBubble";
|
||||
const extensionFolderPath = `scripts/extensions/third-party/${extensionName}`;
|
||||
const extensionSettings = extension_settings[extensionName];
|
||||
|
||||
// Default settings
|
||||
const defaultSettings = {
|
||||
image_service_url: "image.php",
|
||||
default_style: "default",
|
||||
enabled: true
|
||||
};
|
||||
|
||||
// Make sure settings exist
|
||||
if (!extension_settings[extensionName]) {
|
||||
extension_settings[extensionName] = {};
|
||||
}
|
||||
|
||||
// Apply defaults for any missing settings
|
||||
if (Object.keys(extension_settings[extensionName]).length === 0) {
|
||||
Object.assign(extension_settings[extensionName], defaultSettings);
|
||||
}
|
||||
|
||||
// Function for AI to call - generates markdown image with URL-encoded text
|
||||
function generateChatBubbleImage(text, style) {
|
||||
if (!extensionSettings.enabled) {
|
||||
if (!extension_settings[extensionName].enabled) {
|
||||
return text;
|
||||
}
|
||||
|
||||
// Use default style if not specified
|
||||
const bubbleStyle = style || extensionSettings.default_style;
|
||||
const bubbleStyle = style || extension_settings[extensionName].default_style;
|
||||
|
||||
// URL encode the text parameter
|
||||
const encodedText = encodeURIComponent(text);
|
||||
|
||||
// Construct the URL with the encoded text
|
||||
const imageUrl = `${extensionSettings.image_service_url}?q=${encodedText}`;
|
||||
const imageUrl = `${extension_settings[extensionName].image_service_url}?q=${encodedText}`;
|
||||
|
||||
// Add style parameter if specified
|
||||
const fullUrl = bubbleStyle !== "default"
|
||||
@ -36,37 +47,32 @@ function generateChatBubbleImage(text, style) {
|
||||
return ``;
|
||||
}
|
||||
|
||||
// Load extension settings
|
||||
async function loadSettings() {
|
||||
extension_settings[extensionName] = extension_settings[extensionName] || {};
|
||||
if (Object.keys(extension_settings[extensionName]).length === 0) {
|
||||
Object.assign(extension_settings[extensionName], defaultSettings);
|
||||
}
|
||||
|
||||
// Load extension settings into UI
|
||||
function loadSettings() {
|
||||
// Update UI with current settings
|
||||
$("#sillybubble_enabled").prop("checked", extensionSettings.enabled).trigger("input");
|
||||
$("#sillybubble_image_url").val(extensionSettings.image_service_url).trigger("input");
|
||||
$("#sillybubble_default_style").val(extensionSettings.default_style).trigger("input");
|
||||
$("#sillybubble_enabled").prop("checked", extension_settings[extensionName].enabled).trigger("input");
|
||||
$("#sillybubble_image_url").val(extension_settings[extensionName].image_service_url).trigger("input");
|
||||
$("#sillybubble_default_style").val(extension_settings[extensionName].default_style).trigger("input");
|
||||
}
|
||||
|
||||
// Handle enable/disable toggle
|
||||
function onEnabledInput(event) {
|
||||
const value = Boolean($(event.target).prop("checked"));
|
||||
extensionSettings.enabled = value;
|
||||
extension_settings[extensionName].enabled = value;
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
// Handle image service URL changes
|
||||
function onImageUrlInput(event) {
|
||||
const value = $(event.target).val();
|
||||
extensionSettings.image_service_url = value;
|
||||
extension_settings[extensionName].image_service_url = value;
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
// Handle default style changes
|
||||
function onDefaultStyleInput(event) {
|
||||
const value = $(event.target).val();
|
||||
extensionSettings.default_style = value;
|
||||
extension_settings[extensionName].default_style = value;
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
@ -82,63 +88,113 @@ function onTestButtonClick() {
|
||||
<div>${markdown}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
callPopup(testPopup, 'text');
|
||||
}
|
||||
|
||||
// Register function tool
|
||||
function registerFunctionTool() {
|
||||
try {
|
||||
// Check if ToolManager exists in global scope
|
||||
if (!window.ToolManager) {
|
||||
console.warn(`[${extensionName}] ToolManager not found. Will try alternative registration methods.`);
|
||||
|
||||
// Method 1: Register directly to window
|
||||
window.generateChatBubbleImage = generateChatBubbleImage;
|
||||
console.log(`[${extensionName}] Registered function to window object`);
|
||||
|
||||
// Method 2: Add to extensions_functions if it exists
|
||||
if (window.extensions_functions) {
|
||||
window.extensions_functions['generateChatBubbleImage'] = generateChatBubbleImage;
|
||||
console.log(`[${extensionName}] Added to extensions_functions`);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if tool calling is supported
|
||||
if (typeof window.ToolManager.isToolCallingSupported !== 'function' || !window.ToolManager.isToolCallingSupported()) {
|
||||
console.warn(`[${extensionName}] Tool calling is not supported in the current configuration`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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)"
|
||||
}
|
||||
},
|
||||
"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);
|
||||
},
|
||||
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`);
|
||||
} catch (error) {
|
||||
console.error(`[${extensionName}] Error registering function tool:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize extension
|
||||
jQuery(async () => {
|
||||
// Load settings HTML
|
||||
const settingsHtml = await $.get(`${extensionFolderPath}/example.html`);
|
||||
// Visual extensions go in the right column (extensions_settings2)
|
||||
$("#extensions_settings2").append(settingsHtml);
|
||||
console.log(`[${extensionName}] Initializing...`);
|
||||
|
||||
// Register event listeners
|
||||
$("#sillybubble_enabled").on("input", onEnabledInput);
|
||||
$("#sillybubble_image_url").on("input", onImageUrlInput);
|
||||
$("#sillybubble_default_style").on("input", onDefaultStyleInput);
|
||||
$("#sillybubble_test_button").on("click", onTestButtonClick);
|
||||
|
||||
// Register the custom function for AI to call
|
||||
registerCustomFunction({
|
||||
name: 'generateChatBubbleImage',
|
||||
displayName: 'Generate Chat Bubble Image',
|
||||
description: 'Creates a markdown image link with URL-encoded text parameter for dynamic chat bubbles',
|
||||
parameters: [
|
||||
{
|
||||
name: 'text',
|
||||
displayName: 'Text',
|
||||
description: 'The text to display in the chat bubble',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'style',
|
||||
displayName: 'Style',
|
||||
description: 'The visual style of the chat bubble (optional)',
|
||||
type: 'string',
|
||||
required: false,
|
||||
}
|
||||
],
|
||||
isPublic: true, // Make sure function is exposed to the AI
|
||||
run: async function(text, style) {
|
||||
return generateChatBubbleImage(text, style);
|
||||
}
|
||||
});
|
||||
|
||||
// Log to console to verify registration
|
||||
console.log(`[${extensionName}] Function registered: generateChatBubbleImage`);
|
||||
|
||||
// Add to context if needed - this might be required to expose to AI
|
||||
try {
|
||||
const context = getContext();
|
||||
if (context && typeof context.addExtensionFunction === 'function') {
|
||||
context.addExtensionFunction('generateChatBubbleImage', generateChatBubbleImage);
|
||||
console.log(`[${extensionName}] Function added to context: generateChatBubbleImage`);
|
||||
}
|
||||
// Load settings HTML
|
||||
const settingsHtml = await $.get(`${extensionFolderPath}/example.html`);
|
||||
// Visual extensions go in the right column (extensions_settings2)
|
||||
$("#extensions_settings2").append(settingsHtml);
|
||||
|
||||
// Register event listeners
|
||||
$("#sillybubble_enabled").on("input", onEnabledInput);
|
||||
$("#sillybubble_image_url").on("input", onImageUrlInput);
|
||||
$("#sillybubble_default_style").on("input", onDefaultStyleInput);
|
||||
$("#sillybubble_test_button").on("click", onTestButtonClick);
|
||||
|
||||
// Wait for the document to fully load before trying to register tools
|
||||
$(document).ready(() => {
|
||||
setTimeout(() => {
|
||||
// Try to register the function tool after a short delay
|
||||
// to ensure all SillyTavern systems are initialized
|
||||
registerFunctionTool();
|
||||
|
||||
// Also add the function to extension context
|
||||
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);
|
||||
}
|
||||
}, 2000); // Wait 2 seconds for SillyTavern to initialize
|
||||
});
|
||||
|
||||
// Load settings
|
||||
loadSettings();
|
||||
console.log(`[${extensionName}] Initialization complete`);
|
||||
} catch (error) {
|
||||
console.error(`[${extensionName}] Error adding function to context:`, error);
|
||||
console.error(`[${extensionName}] Initialization error:`, error);
|
||||
}
|
||||
|
||||
// Load settings
|
||||
loadSettings();
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user