fix(ai-context): sync manual edits to committed tracker data

Fixes critical issue where manual edits (add location, add item, change
stats, etc.) were invisible to AI in next generation, causing edits to be
immediately overwritten.

Root Cause:
- Manual edits updated extensionSettings and lastGeneratedData
- AI prompt builder used committedTrackerData (NOT extensionSettings)
- Manual edits were never synced to committedTrackerData
- Result: AI didn't see manual changes, overwrote them

Solution - Sync to Both Data Stores:

All manual edit points now update BOTH:
1. lastGeneratedData (for display)
2. committedTrackerData (for AI context)

Files Modified:

1. **src/systems/interaction/inventoryActions.js**
   - updateLastGeneratedDataInventory() now sets committedTrackerData.userStats
   - Affects: add/remove items, add/remove locations

2. **src/systems/rendering/userStats.js**
   - All 3 edit handlers now set committedTrackerData.userStats
   - Affects: stat values (health, etc.), mood emoji, conditions
   - Also fixed: now uses buildInventorySummary() for proper v2 format

3. **src/systems/rendering/infoBox.js**
   - updateInfoBoxField() now sets committedTrackerData.infoBox
   - Affects: date, weather, temperature, time, location

4. **src/systems/rendering/thoughts.js**
   - updateCharacterField() now sets committedTrackerData.characterThoughts
   - Affects: character emoji, name, traits, thoughts, relationship

Impact - Manual Edits Now Persist:

Before:
- Add location "Home" → Next generation → Location gone 
- Add item "Sword" → Next generation → Item gone 
- Change health to 25% → AI ignores it 

After:
- Add location "Home" → Next generation → Location persists ✓
- Add item "Sword" → Next generation → Item included ✓
- Change health to 25% → AI acknowledges low health ✓

Works in Both Modes:
- Together mode: AI sees manual edits in injected prompt ✓
- Separate mode: AI sees manual edits in context ✓

User Experience:
- "I edited it, so it should stay" - now works as expected
- AI builds on manual changes instead of overwriting them
- Minimal overhead (just string copies)

Fixes: Manual inventory/stats edits being overwritten by AI generation
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-20 08:05:08 +11:00
parent 7b320b8d0b
commit f09c42ec6e
4 changed files with 47 additions and 15 deletions
+11 -5
View File
@@ -3,7 +3,7 @@
* Handles all user interactions with the inventory v2 system
*/
import { extensionSettings, lastGeneratedData } from '../../core/state.js';
import { extensionSettings, lastGeneratedData, committedTrackerData } from '../../core/state.js';
import { saveSettings, saveChatData, updateMessageSwipeData } from '../../core/persistence.js';
import { buildInventorySummary } from '../generation/promptBuilder.js';
import { renderInventory } from '../rendering/inventory.js';
@@ -37,15 +37,16 @@ let openForms = {
};
/**
* Updates lastGeneratedData.userStats to include current inventory in text format.
* This ensures the AI context stays synced with manual edits.
* Updates lastGeneratedData.userStats AND committedTrackerData.userStats to include
* current inventory in text format.
* This ensures manual edits are immediately visible to AI in next generation.
*/
function updateLastGeneratedDataInventory() {
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
// Rebuild the lastGeneratedData.userStats text format
lastGeneratedData.userStats =
// Rebuild the userStats text format
const statsText =
`Health: ${stats.health}%\n` +
`Satiety: ${stats.satiety}%\n` +
`Energy: ${stats.energy}%\n` +
@@ -53,6 +54,11 @@ function updateLastGeneratedDataInventory() {
`Arousal: ${stats.arousal}%\n` +
`${stats.mood}: ${stats.conditions}\n` +
`${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
}
/**
+5
View File
@@ -7,6 +7,7 @@ import { getContext } from '../../../../../../extensions.js';
import {
extensionSettings,
lastGeneratedData,
committedTrackerData,
$infoBoxContainer
} from '../../core/state.js';
import { saveChatData } from '../../core/persistence.js';
@@ -429,6 +430,10 @@ export function updateInfoBoxField(field, value) {
lastGeneratedData.infoBox = updatedLines.join('\n');
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
committedTrackerData.infoBox = updatedLines.join('\n');
// Update the message's swipe data
const chat = getContext().chat;
if (chat && chat.length > 0) {
+5
View File
@@ -9,6 +9,7 @@ import { selected_group, getGroupMembers } from '../../../../../../group-chats.j
import {
extensionSettings,
lastGeneratedData,
committedTrackerData,
$thoughtsContainer,
FALLBACK_AVATAR_DATA_URI
} from '../../core/state.js';
@@ -320,6 +321,10 @@ export function updateCharacterField(characterName, field, value) {
lastGeneratedData.characterThoughts = updatedLines.join('\n');
// console.log('[RPG Companion] 💾 Updated lastGeneratedData.characterThoughts:', lastGeneratedData.characterThoughts);
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
committedTrackerData.characterThoughts = updatedLines.join('\n');
// Also update the last assistant message's swipe data
const chat = getContext().chat;
if (chat && chat.length > 0) {
+26 -10
View File
@@ -8,6 +8,7 @@ import { user_avatar } from '../../../../../../../script.js';
import {
extensionSettings,
lastGeneratedData,
committedTrackerData,
$userStatsContainer,
FALLBACK_AVATAR_DATA_URI
} from '../../core/state.js';
@@ -17,6 +18,7 @@ import {
updateMessageSwipeData
} from '../../core/persistence.js';
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
import { buildInventorySummary } from '../generation/promptBuilder.js';
/**
* Renders the user stats panel with health bars, mood, inventory, and classic stats.
@@ -178,13 +180,15 @@ export function renderUserStats() {
// Update the setting
extensionSettings.userStats[field] = value;
// Also update lastGeneratedData to keep it in sync
if (!lastGeneratedData.userStats) {
lastGeneratedData.userStats = '';
}
// Regenerate the userStats text with updated value
const statsText = `Health: ${extensionSettings.userStats.health}%\nSatiety: ${extensionSettings.userStats.satiety}%\nEnergy: ${extensionSettings.userStats.energy}%\nHygiene: ${extensionSettings.userStats.hygiene}%\nArousal: ${extensionSettings.userStats.arousal}%\n${extensionSettings.userStats.mood}: ${extensionSettings.userStats.conditions}\nInventory: ${extensionSettings.userStats.inventory}`;
// Rebuild userStats text with proper inventory format
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
const statsText = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\n${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
saveSettings();
saveChatData();
@@ -199,9 +203,15 @@ export function renderUserStats() {
const value = $(this).text().trim();
extensionSettings.userStats.mood = value || '😐';
// Update lastGeneratedData
const statsText = `Health: ${extensionSettings.userStats.health}%\nSatiety: ${extensionSettings.userStats.satiety}%\nEnergy: ${extensionSettings.userStats.energy}%\nHygiene: ${extensionSettings.userStats.hygiene}%\nArousal: ${extensionSettings.userStats.arousal}%\n${extensionSettings.userStats.mood}: ${extensionSettings.userStats.conditions}\nInventory: ${extensionSettings.userStats.inventory}`;
// Rebuild userStats text with proper inventory format
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
const statsText = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\n${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
saveSettings();
saveChatData();
@@ -212,9 +222,15 @@ export function renderUserStats() {
const value = $(this).text().trim();
extensionSettings.userStats.conditions = value || 'None';
// Update lastGeneratedData
const statsText = `Health: ${extensionSettings.userStats.health}%\nSatiety: ${extensionSettings.userStats.satiety}%\nEnergy: ${extensionSettings.userStats.energy}%\nHygiene: ${extensionSettings.userStats.hygiene}%\nArousal: ${extensionSettings.userStats.arousal}%\n${extensionSettings.userStats.mood}: ${extensionSettings.userStats.conditions}\nInventory: ${extensionSettings.userStats.inventory}`;
// Rebuild userStats text with proper inventory format
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
const statsText = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\n${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
saveSettings();
saveChatData();