Add Deception System and CYOA features with toggles, custom prompts, and proper injection ordering
This commit is contained in:
@@ -304,21 +304,6 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough
|
||||
lastGeneratedData.characterThoughts = parsedData.characterThoughts;
|
||||
}
|
||||
|
||||
// When saveTrackerHistory is enabled, store tracker data on the user's message too
|
||||
// This allows scrolling through history and seeing trackers at each point
|
||||
if (extensionSettings.saveTrackerHistory && lastMessage && lastMessage.is_user) {
|
||||
if (!lastMessage.extra) {
|
||||
lastMessage.extra = {};
|
||||
}
|
||||
lastMessage.extra.rpg_companion_data = {
|
||||
userStats: parsedData.userStats,
|
||||
infoBox: parsedData.infoBox,
|
||||
characterThoughts: parsedData.characterThoughts,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
// console.log('[RPG Companion] 💾 Stored tracker data on user message for history');
|
||||
}
|
||||
|
||||
// Also store on assistant message if present (existing behavior)
|
||||
if (lastMessage && !lastMessage.is_user) {
|
||||
if (!lastMessage.extra) {
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
formatHistoricalTrackerData,
|
||||
DEFAULT_HTML_PROMPT,
|
||||
DEFAULT_DIALOGUE_COLORING_PROMPT,
|
||||
DEFAULT_DECEPTION_PROMPT,
|
||||
DEFAULT_CYOA_PROMPT,
|
||||
DEFAULT_SPOTIFY_PROMPT,
|
||||
SPOTIFY_FORMAT_INSTRUCTION
|
||||
} from './promptBuilder.js';
|
||||
@@ -125,7 +127,7 @@ function buildHistoricalContextMap() {
|
||||
}
|
||||
|
||||
// Build the context wrapper
|
||||
const preamble = historyPersistence.contextPreamble || '[Context at this point:]';
|
||||
const preamble = historyPersistence.contextPreamble || 'Context for that moment:';
|
||||
const wrappedContext = `\n${preamble}\n${formattedContext}`;
|
||||
|
||||
// Determine which message index to store based on injection position
|
||||
@@ -261,8 +263,8 @@ export async function onGenerationStarted(type, data, dryRun) {
|
||||
// console.log('[RPG Companion] Committed Prompt:', committedTrackerData);
|
||||
|
||||
// Skip tracker injection for image generation requests
|
||||
if (data?.quietImage) {
|
||||
// console.log('[RPG Companion] Detected image generation (quietImage=true), skipping tracker injection');
|
||||
if (data?.quietImage || data?.quiet_image || data?.isImageGeneration) {
|
||||
// console.log('[RPG Companion] Detected image generation, skipping tracker injection');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -467,7 +469,7 @@ export async function onGenerationStarted(type, data, dryRun) {
|
||||
if (extensionSettings.enableHtmlPrompt && !shouldSuppress) {
|
||||
// Use custom HTML prompt if set, otherwise use default
|
||||
const htmlPromptText = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT;
|
||||
const htmlPrompt = `\n${htmlPromptText}`;
|
||||
const htmlPrompt = `\n- ${htmlPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-html', htmlPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected HTML prompt at depth 0 for together mode');
|
||||
@@ -480,7 +482,7 @@ export async function onGenerationStarted(type, data, dryRun) {
|
||||
if (extensionSettings.enableDialogueColoring && !shouldSuppress) {
|
||||
// Use custom Dialogue Coloring prompt if set, otherwise use default
|
||||
const dialogueColoringPromptText = extensionSettings.customDialogueColoringPrompt || DEFAULT_DIALOGUE_COLORING_PROMPT;
|
||||
const dialogueColoringPrompt = `\n${dialogueColoringPromptText}`;
|
||||
const dialogueColoringPrompt = `\n- ${dialogueColoringPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-dialogue-coloring', dialogueColoringPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected Dialogue Coloring prompt at depth 0 for together mode');
|
||||
@@ -489,11 +491,24 @@ export async function onGenerationStarted(type, data, dryRun) {
|
||||
setExtensionPrompt('rpg-companion-dialogue-coloring', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject Deception System prompt separately at depth 0 if enabled
|
||||
if (extensionSettings.enableDeceptionSystem && !shouldSuppress) {
|
||||
// Use custom Deception prompt if set, otherwise use default
|
||||
const deceptionPromptText = extensionSettings.customDeceptionPrompt || DEFAULT_DECEPTION_PROMPT;
|
||||
const deceptionPrompt = `\n- ${deceptionPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-deception', deceptionPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected Deception System prompt at depth 0 for together mode');
|
||||
} else {
|
||||
// Clear Deception System prompt if disabled
|
||||
setExtensionPrompt('rpg-companion-deception', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject Spotify prompt separately at depth 0 if enabled
|
||||
if (extensionSettings.enableSpotifyMusic && !shouldSuppress) {
|
||||
// Use custom Spotify prompt if set, otherwise use default
|
||||
const spotifyPromptText = extensionSettings.customSpotifyPrompt || DEFAULT_SPOTIFY_PROMPT;
|
||||
const spotifyPrompt = `\n${spotifyPromptText} ${SPOTIFY_FORMAT_INSTRUCTION}`;
|
||||
const spotifyPrompt = `\n- ${spotifyPromptText} ${SPOTIFY_FORMAT_INSTRUCTION}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-spotify', spotifyPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected Spotify prompt at depth 0 for together mode');
|
||||
@@ -501,6 +516,20 @@ export async function onGenerationStarted(type, data, dryRun) {
|
||||
// Clear Spotify prompt if disabled
|
||||
setExtensionPrompt('rpg-companion-spotify', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject CYOA prompt separately at depth 0 if enabled (injected last to appear last in prompt)
|
||||
if (extensionSettings.enableCYOA && !shouldSuppress) {
|
||||
// Use custom CYOA prompt if set, otherwise use default
|
||||
const cyoaPromptText = extensionSettings.customCYOAPrompt || DEFAULT_CYOA_PROMPT;
|
||||
const cyoaPrompt = `\n- ${cyoaPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-zzz-cyoa', cyoaPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected CYOA prompt at depth 0 for together mode');
|
||||
} else {
|
||||
// Clear CYOA prompt if disabled
|
||||
setExtensionPrompt('rpg-companion-zzz-cyoa', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
} else if (extensionSettings.generationMode === 'separate' || extensionSettings.generationMode === 'external') {
|
||||
// In SEPARATE and EXTERNAL modes, inject the contextual summary for main roleplay generation
|
||||
const contextSummary = generateContextualSummary();
|
||||
@@ -528,7 +557,7 @@ Ensure these details naturally reflect and influence the narrative. Character be
|
||||
if (extensionSettings.enableHtmlPrompt && !shouldSuppress) {
|
||||
// Use custom HTML prompt if set, otherwise use default
|
||||
const htmlPromptText = extensionSettings.customHtmlPrompt || DEFAULT_HTML_PROMPT;
|
||||
const htmlPrompt = `\n${htmlPromptText}`;
|
||||
const htmlPrompt = `\n- ${htmlPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-html', htmlPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected HTML prompt at depth 0 for separate/external mode');
|
||||
@@ -537,11 +566,37 @@ Ensure these details naturally reflect and influence the narrative. Character be
|
||||
setExtensionPrompt('rpg-companion-html', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject Dialogue Coloring prompt separately at depth 0 if enabled
|
||||
if (extensionSettings.enableDialogueColoring && !shouldSuppress) {
|
||||
// Use custom Dialogue Coloring prompt if set, otherwise use default
|
||||
const dialogueColoringPromptText = extensionSettings.customDialogueColoringPrompt || DEFAULT_DIALOGUE_COLORING_PROMPT;
|
||||
const dialogueColoringPrompt = `\n- ${dialogueColoringPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-dialogue-coloring', dialogueColoringPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected Dialogue Coloring prompt at depth 0 for separate/external mode');
|
||||
} else {
|
||||
// Clear Dialogue Coloring prompt if disabled
|
||||
setExtensionPrompt('rpg-companion-dialogue-coloring', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject Deception System prompt separately at depth 0 if enabled
|
||||
if (extensionSettings.enableDeceptionSystem && !shouldSuppress) {
|
||||
// Use custom Deception prompt if set, otherwise use default
|
||||
const deceptionPromptText = extensionSettings.customDeceptionPrompt || DEFAULT_DECEPTION_PROMPT;
|
||||
const deceptionPrompt = `\n- ${deceptionPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-deception', deceptionPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected Deception System prompt at depth 0 for separate/external mode');
|
||||
} else {
|
||||
// Clear Deception System prompt if disabled
|
||||
setExtensionPrompt('rpg-companion-deception', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject Spotify prompt separately at depth 0 if enabled
|
||||
if (extensionSettings.enableSpotifyMusic && !shouldSuppress) {
|
||||
// Use custom Spotify prompt if set, otherwise use default
|
||||
const spotifyPromptText = extensionSettings.customSpotifyPrompt || DEFAULT_SPOTIFY_PROMPT;
|
||||
const spotifyPrompt = `\n${spotifyPromptText} ${SPOTIFY_FORMAT_INSTRUCTION}`;
|
||||
const spotifyPrompt = `\n- ${spotifyPromptText} ${SPOTIFY_FORMAT_INSTRUCTION}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-spotify', spotifyPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected Spotify prompt at depth 0 for separate/external mode');
|
||||
@@ -550,6 +605,19 @@ Ensure these details naturally reflect and influence the narrative. Character be
|
||||
setExtensionPrompt('rpg-companion-spotify', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Inject CYOA prompt separately at depth 0 if enabled (injected last to appear last in prompt)
|
||||
if (extensionSettings.enableCYOA && !shouldSuppress) {
|
||||
// Use custom CYOA prompt if set, otherwise use default
|
||||
const cyoaPromptText = extensionSettings.customCYOAPrompt || DEFAULT_CYOA_PROMPT;
|
||||
const cyoaPrompt = `\n- ${cyoaPromptText}\n`;
|
||||
|
||||
setExtensionPrompt('rpg-companion-zzz-cyoa', cyoaPrompt, extension_prompt_types.IN_CHAT, 0, false);
|
||||
// console.log('[RPG Companion] Injected CYOA prompt at depth 0 for separate/external mode');
|
||||
} else {
|
||||
// Clear CYOA prompt if disabled
|
||||
setExtensionPrompt('rpg-companion-zzz-cyoa', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
// Clear together mode injections
|
||||
setExtensionPrompt('rpg-companion-inject', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
setExtensionPrompt('rpg-companion-example', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
@@ -559,6 +627,9 @@ Ensure these details naturally reflect and influence the narrative. Character be
|
||||
setExtensionPrompt('rpg-companion-example', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
setExtensionPrompt('rpg-companion-context', '', extension_prompt_types.IN_CHAT, 1, false);
|
||||
setExtensionPrompt('rpg-companion-html', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
setExtensionPrompt('rpg-companion-dialogue-coloring', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
setExtensionPrompt('rpg-companion-deception', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
setExtensionPrompt('rpg-companion-zzz-cyoa', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
setExtensionPrompt('rpg-companion-spotify', '', extension_prompt_types.IN_CHAT, 0, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,16 @@ export const DEFAULT_HTML_PROMPT = `If appropriate, include inline HTML, CSS, an
|
||||
*/
|
||||
export const DEFAULT_DIALOGUE_COLORING_PROMPT = `Wrap all character/NPC "dialogues" in unique <font color=######>tags</font>, exemplary: <font color=#abc123>"You're pretty good."</font> Assign a distinct color to each speaker and reuse it whenever they speak again.`;
|
||||
|
||||
/**
|
||||
* Default Deception System prompt text
|
||||
*/
|
||||
export const DEFAULT_DECEPTION_PROMPT = `When a character is lying or deceiving, you should follow up that line with the <lie> tag, containing a brief description of the truth and the lie's reason, using the template below (replace placeholders in brackets). This will be hidden from the user's view, but not to you, making it useful for future consequences: <lie>[Character] is [lying/deceiving/omitting], the truth is [truth]. Reason: [reason].</lie>`;
|
||||
|
||||
/**
|
||||
* Default CYOA prompt text
|
||||
*/
|
||||
export const DEFAULT_CYOA_PROMPT = `Since this is a "Choose Your Own Adventure" type of game, you must finish your response by creating a numbered list of 5 different possible action or dialogue options (depending on the scene) for the user to choose from. Make sure they all fit their persona well. They will respond with their choice on how to progress.`;
|
||||
|
||||
/**
|
||||
* Default Spotify music prompt text (customizable by users)
|
||||
*/
|
||||
@@ -229,7 +239,6 @@ function buildAttributesString() {
|
||||
*/
|
||||
export function generateTrackerExample() {
|
||||
let example = '';
|
||||
const useXmlTags = extensionSettings.saveTrackerHistory;
|
||||
|
||||
// Use COMMITTED data for generation context, not displayed data
|
||||
// Apply locks before sending to AI (for JSON format only)
|
||||
@@ -310,19 +319,11 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon
|
||||
|
||||
// Only add tracker instructions if at least one tracker is enabled
|
||||
if (hasAnyTrackers) {
|
||||
// Determine format based on saveTrackerHistory setting
|
||||
const useXmlTags = extensionSettings.saveTrackerHistory;
|
||||
const openTag = useXmlTags ? '<trackers>\n' : '';
|
||||
const closeTag = useXmlTags ? '\n</trackers>' : '';
|
||||
const codeBlockMarker = '';
|
||||
const endCodeBlockMarker = '';
|
||||
|
||||
// Universal instruction header
|
||||
if (useXmlTags) {
|
||||
instructions += `\nAt the start of every reply, you must attach an update to the trackers in EXACTLY the JSON format shown below, enclosed in <trackers></trackers> XML tags. `;
|
||||
} else {
|
||||
instructions += '\nAt the start of every reply, you must attach an update to the trackers in EXACTLY the JSON format shown below as a single unified JSON object containing all enabled tracker fields. ';
|
||||
}
|
||||
instructions += '\nAt the start of every reply, you must attach an update to the trackers in EXACTLY the JSON format shown below as a single unified JSON object containing all enabled tracker fields. ';
|
||||
|
||||
// Append custom instruction portion if available
|
||||
const customPrompt = extensionSettings.customTrackerInstructionsPrompt;
|
||||
@@ -789,7 +790,7 @@ export function formatHistoricalTrackerData(trackerData, trackerConfig, userName
|
||||
let statsFormatted = '';
|
||||
|
||||
// Custom stats with persistInHistory enabled
|
||||
if (userStatsData.stats && Array.isArray(userStatsData.stats)) {
|
||||
if (userStatsData.stats && Array.isArray(userStatsData.stats) && userStatsConfig.customStats) {
|
||||
for (const stat of userStatsData.stats) {
|
||||
const configStat = userStatsConfig.customStats.find(s => s.id === stat.id);
|
||||
if (configStat?.persistInHistory && stat.value !== undefined) {
|
||||
@@ -1169,7 +1170,7 @@ export async function generateSeparateUpdatePrompt() {
|
||||
continue;
|
||||
}
|
||||
|
||||
const preamble = historyPersistence.contextPreamble || '[Context at this point:]';
|
||||
const preamble = historyPersistence.contextPreamble || 'Context for that moment:';
|
||||
const wrappedContext = `\n${preamble}\n${formattedContext}`;
|
||||
|
||||
// Determine target message based on position
|
||||
|
||||
Reference in New Issue
Block a user