From fb14c951ac7cacb35b0e6902041bff4417d1120e Mon Sep 17 00:00:00 2001 From: Lucas 'Paperboy' Rose-Winters Date: Wed, 22 Oct 2025 08:45:28 +1100 Subject: [PATCH] fix: add debug logging and fix Present Characters rendering PROBLEM (reported by Salixfire): - Present Characters panel showing placeholder instead of actual characters - Thought bubbles work correctly but main panel doesn't - Need to toggle settings off/on to get thoughts to appear - No way to debug on mobile devices CHANGES: 1. Added comprehensive debug logging to renderThoughts() (src/systems/rendering/thoughts.js): - Log when function is called and with what data - Log each line being parsed and how many parts it has - Log character extraction (emoji, name, traits, relationship, thoughts) - Log why characters are accepted or rejected - Log final character count and whether showing placeholder - All logs visible in mobile-friendly debug panel 2. Fixed toggle to refresh content (index.js:283-291): - When user toggles "Show Present Characters" on, now calls renderThoughts() - Previously only showed/hid container without refreshing content - This ensures panel displays latest data when toggled 3. Normalized parsing logic (src/systems/rendering/thoughts.js:111): - Changed renderThoughts() to require >= 3 parts (was >= 2) - Now matches updateChatThoughts() requirement - Consistent with current prompt format: Emoji:Name | Relationship | Thoughts - Removed 2-part format fallback code (unreachable now) - Both functions now use same validation rules EXPECTED OUTCOME: - User can enable debug mode and see exactly what data is being parsed - Toggle will properly refresh the panel content - We can diagnose from debug logs why placeholder is shown - More consistent behavior between main panel and thought bubbles Debug logs will help us identify: - If characterThoughts data is empty/malformed when renderThoughts() is called - If parsing is rejecting valid character data - If there's a timing issue with data availability - What the actual AI response format looks like Related to previous commit (37878fc) that added debug mode toggle. --- index.js | 4 ++ src/systems/rendering/thoughts.js | 67 ++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index 5d276fd..dd0e699 100644 --- a/index.js +++ b/index.js @@ -284,6 +284,10 @@ async function initUI() { extensionSettings.showCharacterThoughts = $(this).prop('checked'); saveSettings(); updateSectionVisibility(); + // Refresh the content when toggling on/off + if (extensionSettings.showCharacterThoughts) { + renderThoughts(); + } }); $('#rpg-toggle-inventory').on('change', function() { diff --git a/src/systems/rendering/thoughts.js b/src/systems/rendering/thoughts.js index 7edb78f..af42aa6 100644 --- a/src/systems/rendering/thoughts.js +++ b/src/systems/rendering/thoughts.js @@ -11,11 +11,22 @@ import { lastGeneratedData, committedTrackerData, $thoughtsContainer, - FALLBACK_AVATAR_DATA_URI + FALLBACK_AVATAR_DATA_URI, + addDebugLog } from '../../core/state.js'; import { saveChatData } from '../../core/persistence.js'; import { getSafeThumbnailUrl } from '../../utils/avatars.js'; +/** + * Helper to log to both console and debug logs array + */ +function debugLog(message, data = null) { + console.log(message, data || ''); + if (extensionSettings.debugMode) { + addDebugLog(message, data); + } +} + /** * Fuzzy name matching that handles: * - Exact matches: "Sabrina" === "Sabrina" @@ -54,6 +65,10 @@ export function renderThoughts() { return; } + debugLog('[RPG Thoughts] ==================== RENDERING PRESENT CHARACTERS ===================='); + debugLog('[RPG Thoughts] showCharacterThoughts setting:', extensionSettings.showCharacterThoughts); + debugLog('[RPG Thoughts] Container exists:', !!$thoughtsContainer); + // Add updating class for animation if (extensionSettings.enableAnimations) { $thoughtsContainer.addClass('rpg-content-updating'); @@ -64,25 +79,36 @@ export function renderThoughts() { lastGeneratedData.characterThoughts = ''; } + debugLog('[RPG Thoughts] Raw characterThoughts data:', lastGeneratedData.characterThoughts); + debugLog('[RPG Thoughts] Data length:', lastGeneratedData.characterThoughts.length + ' chars'); + const lines = lastGeneratedData.characterThoughts.split('\n'); const presentCharacters = []; - // console.log('[RPG Companion] Raw Present Characters:', lastGeneratedData.characterThoughts); - // console.log('[RPG Companion] Split into lines:', lines); + debugLog('[RPG Thoughts] Split into lines count:', lines.length); + debugLog('[RPG Thoughts] Lines:', lines); // Parse format: [Emoji]: [Name, Status, Demeanor] | [Relationship] | [Thoughts] // Also supports 4-part format: [Emoji]: [Name, Status] | [Demeanor] | [Relationship] | [Thoughts] + let lineNumber = 0; for (const line of lines) { + lineNumber++; + // Skip empty lines, headers, dividers, and code fences if (line.trim() && !line.includes('Present Characters') && !line.includes('---') && !line.trim().startsWith('```')) { + debugLog(`[RPG Thoughts] Processing line ${lineNumber}:`, line); + // Match the new format with pipes const parts = line.split('|').map(p => p.trim()); + debugLog(`[RPG Thoughts] Split into ${parts.length} parts:`, parts); - if (parts.length >= 2) { + // Require at least 3 parts (Emoji:Name | Relationship | Thoughts) + // This matches updateChatThoughts() and the current prompt format + if (parts.length >= 3) { // First part: [Emoji]: [Name, Status, Demeanor] const firstPart = parts[0].trim(); const emojiMatch = firstPart.match(/^(.+?):\s*(.+)$/); @@ -91,6 +117,8 @@ export function renderThoughts() { const emoji = emojiMatch[1].trim(); const info = emojiMatch[2].trim(); + debugLog(`[RPG Thoughts] Emoji match found - emoji: "${emoji}", info: "${info}"`); + // Handle both 3-part and 4-part formats let relationship, thoughts, traits; @@ -100,7 +128,8 @@ export function renderThoughts() { thoughts = parts[2].trim(); const infoParts = info.split(',').map(p => p.trim()); traits = infoParts.slice(1).join(', '); - } else if (parts.length >= 4) { + debugLog('[RPG Thoughts] Parsed as 3-part format'); + } else { // 4-part format: Emoji:Name,traits | Demeanor | Relationship | Thoughts // Add the demeanor to traits and use last two parts for relationship/thoughts const demeanor = parts[1].trim(); @@ -109,23 +138,26 @@ export function renderThoughts() { const infoParts = info.split(',').map(p => p.trim()); const baseTraits = infoParts.slice(1).join(', '); traits = baseTraits ? `${baseTraits}, ${demeanor}` : demeanor; - } else { - // Fallback for 2-part format - relationship = parts[1].trim(); - thoughts = ''; - const infoParts = info.split(',').map(p => p.trim()); - traits = infoParts.slice(1).join(', '); + debugLog('[RPG Thoughts] Parsed as 4-part format'); } // Parse name from info (first part before comma) const infoParts = info.split(',').map(p => p.trim()); const name = infoParts[0] || ''; + debugLog(`[RPG Thoughts] Extracted - name: "${name}", traits: "${traits}", relationship: "${relationship}", thoughts: "${thoughts}"`); + if (name && name.toLowerCase() !== 'unavailable') { presentCharacters.push({ emoji, name, traits, relationship, thoughts }); - // console.log('[RPG Companion] Parsed character:', { name, relationship, thoughts }); + debugLog(`[RPG Thoughts] ✓ Added character: ${name}`); + } else { + debugLog(`[RPG Thoughts] ✗ Rejected character - name: "${name}" (unavailable or empty)`); } + } else { + debugLog('[RPG Thoughts] ✗ No emoji match found in first part'); } + } else { + debugLog(`[RPG Thoughts] ✗ Not enough parts (${parts.length} < 3, need at least Emoji:Name | Relationship | Thoughts)`); } } } @@ -138,14 +170,16 @@ export function renderThoughts() { 'Lover': '❤️' }; + debugLog('[RPG Thoughts] ==================== PARSING COMPLETE ===================='); + debugLog('[RPG Thoughts] Total characters parsed:', presentCharacters.length); + debugLog('[RPG Thoughts] Characters array:', presentCharacters); + // Build HTML let html = ''; - // console.log('[RPG Companion] Total characters parsed:', presentCharacters.length); - // console.log('[RPG Companion] Characters array:', presentCharacters); - // If no characters parsed, show a placeholder editable card if (presentCharacters.length === 0) { + debugLog('[RPG Thoughts] ⚠ No characters parsed - showing placeholder card'); // Get default character portrait (try to use the current character if in 1-on-1 chat) // Use a base64-encoded SVG placeholder as fallback to avoid 400 errors let defaultPortrait = FALLBACK_AVATAR_DATA_URI; @@ -249,6 +283,9 @@ export function renderThoughts() { $thoughtsContainer.html(html); + debugLog('[RPG Thoughts] ✓ HTML rendered to container'); + debugLog('[RPG Thoughts] ======================================================='); + // Add event handlers for editable character fields $thoughtsContainer.find('.rpg-editable').on('blur', function() { const character = $(this).data('character');