630 lines
27 KiB
JavaScript
630 lines
27 KiB
JavaScript
console.log('RTS-MODE: index.js script loading...');
|
|
|
|
// Test if jQuery is available
|
|
console.log('RTS-MODE: jQuery available:', typeof jQuery !== 'undefined');
|
|
console.log('RTS-MODE: $ available:', typeof $ !== 'undefined');
|
|
|
|
import { extension_settings, saveSettingsDebounced } from '../../../script.js';
|
|
import { renderExtensionTemplateAsync } from '../../extensions.js';
|
|
import { eventSource, event_types } from '../../events.js';
|
|
import { createMapCanvas } from './ui/MapCanvas.js';
|
|
import { createResourcePanel } from './ui/ResourcePanel.js';
|
|
import { rtsUI } from './ui/RTSUIController.js';
|
|
import GameStateManager from './src/GameStateManager.js';
|
|
import { sendTurn } from './src/LLMAdapter.js';
|
|
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
|
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
|
import { ARGUMENT_TYPE, SlashCommandArgument } from '../../slash-commands/SlashCommandArgument.js';
|
|
import './js/rts-mode.js';
|
|
|
|
console.log('RTS-MODE: All imports successful');
|
|
|
|
const extensionId = 'rts-mode';
|
|
const extensionName = 'RTS Chat Mode';
|
|
|
|
// RTS-mode specific settings
|
|
const rtsSettings = {
|
|
structuredOutput: false,
|
|
autoSchemaUpdates: true,
|
|
contentFilter: true,
|
|
};
|
|
|
|
// Export settings for use in other modules
|
|
export { rtsSettings };
|
|
|
|
/**
|
|
* Generates a comprehensive JSON schema based on the current game state structure
|
|
* @param {object} gameState - Current game state to base schema on
|
|
* @returns {object} Complete JSON schema for AI responses
|
|
*/
|
|
function generateRTSJSONSchema(gameState) {
|
|
// Ensure gameState is a valid object
|
|
const safeGameState = gameState && typeof gameState === 'object' ? gameState : {};
|
|
|
|
return {
|
|
"type": "object",
|
|
"properties": {
|
|
"narrative": {
|
|
"type": "string",
|
|
"description": "Brief atmospheric narrative (2-3 sentences max) focusing on immediate sensory details and events."
|
|
},
|
|
"state": {
|
|
"type": "object",
|
|
"description": "Complete updated game state",
|
|
"properties": {
|
|
"turn": {
|
|
"type": "integer",
|
|
"description": "Current turn number"
|
|
},
|
|
"currentZone": {
|
|
"type": "string",
|
|
"description": "Current zone/area the player is in"
|
|
},
|
|
"threatLevel": {
|
|
"type": "string",
|
|
"enum": ["none", "low", "medium", "high", "extreme"],
|
|
"description": "Current threat level"
|
|
},
|
|
"lastEvent": {
|
|
"type": "string",
|
|
"description": "Description of the last significant event"
|
|
},
|
|
"casualties": {
|
|
"type": "object",
|
|
"properties": {
|
|
"total": { "type": "integer", "minimum": 0 },
|
|
"recent": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"cause": { "type": "string" },
|
|
"location": { "type": "string" },
|
|
"perpetrator": { "type": "string" },
|
|
"turn": { "type": "integer" },
|
|
"description": { "type": "string" }
|
|
},
|
|
"required": ["name", "cause", "location", "perpetrator", "turn"]
|
|
}
|
|
},
|
|
"byZone": { "type": "object" },
|
|
"byAnimal": { "type": "object" }
|
|
},
|
|
"required": ["total", "recent", "byZone", "byAnimal"]
|
|
},
|
|
"escapedAnimals": {
|
|
"type": "object",
|
|
"properties": {
|
|
"total": { "type": "integer", "minimum": 0 },
|
|
"active": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"name": { "type": "string" },
|
|
"type": { "type": "string" },
|
|
"currentLocation": { "type": "string" },
|
|
"escapedFrom": { "type": "string" },
|
|
"threat": { "type": "string", "enum": ["low", "medium", "high", "extreme"] },
|
|
"lastSeen": { "type": "integer" },
|
|
"behavior": { "type": "string" }
|
|
},
|
|
"required": ["id", "name", "type", "currentLocation", "threat", "behavior"]
|
|
}
|
|
},
|
|
"byType": { "type": "object" },
|
|
"byZone": { "type": "object" }
|
|
},
|
|
"required": ["total", "active", "byType", "byZone"]
|
|
},
|
|
"activeIncidents": {
|
|
"type": "object",
|
|
"properties": {
|
|
"emergency": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"type": { "type": "string" },
|
|
"description": { "type": "string" },
|
|
"location": { "type": "string" },
|
|
"priority": { "type": "string", "enum": ["emergency", "high", "medium", "low"] },
|
|
"turn": { "type": "integer" }
|
|
},
|
|
"required": ["type", "description", "location", "priority"]
|
|
}
|
|
},
|
|
"ongoing": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"type": { "type": "string" },
|
|
"description": { "type": "string" },
|
|
"location": { "type": "string" },
|
|
"priority": { "type": "string", "enum": ["emergency", "high", "medium", "low"] },
|
|
"turn": { "type": "integer" }
|
|
},
|
|
"required": ["type", "description", "location", "priority"]
|
|
}
|
|
},
|
|
"resolved": { "type": "array" }
|
|
},
|
|
"required": ["emergency", "ongoing", "resolved"]
|
|
},
|
|
"personnel": {
|
|
"type": "object",
|
|
"properties": {
|
|
"alive": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"name": { "type": "string" },
|
|
"type": { "type": "string", "enum": ["visitor", "staff", "keeper", "veterinarian"] },
|
|
"position": {
|
|
"type": "object",
|
|
"properties": {
|
|
"x": { "type": "number" },
|
|
"y": { "type": "number" }
|
|
},
|
|
"required": ["x", "y"]
|
|
},
|
|
"status": { "type": "string" },
|
|
"lastSeen": { "type": "integer" },
|
|
"description": { "type": "string" }
|
|
},
|
|
"required": ["id", "name", "type", "position", "status"]
|
|
}
|
|
},
|
|
"injured": { "type": "array" },
|
|
"missing": { "type": "array" },
|
|
"evacuated": { "type": "array" }
|
|
},
|
|
"required": ["alive", "injured", "missing", "evacuated"]
|
|
},
|
|
"playerPosition": {
|
|
"type": "object",
|
|
"properties": {
|
|
"x": { "type": "number" },
|
|
"y": { "type": "number" }
|
|
},
|
|
"required": ["x", "y"],
|
|
"description": "Player's current map coordinates"
|
|
},
|
|
"visibleEntities": {
|
|
"type": "array",
|
|
"description": "All entities currently visible to the player (within ~5 tiles)",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"name": { "type": "string" },
|
|
"type": { "type": "string" },
|
|
"position": {
|
|
"type": "object",
|
|
"properties": {
|
|
"x": { "type": "number" },
|
|
"y": { "type": "number" }
|
|
},
|
|
"required": ["x", "y"]
|
|
},
|
|
"status": { "type": "string" },
|
|
"action": { "type": "string", "description": "What the entity is currently doing" },
|
|
"description": { "type": "string" }
|
|
},
|
|
"required": ["id", "name", "type", "position"]
|
|
}
|
|
},
|
|
"environment": {
|
|
"type": "object",
|
|
"properties": {
|
|
"timeOfDay": { "type": "string", "enum": ["evening", "night", "dawn", "morning", "afternoon"] },
|
|
"weather": { "type": "string", "enum": ["clear", "rain", "storm", "fog"] },
|
|
"powerStatus": { "type": "string", "enum": ["full", "partial", "none"] },
|
|
"evacuationStatus": { "type": "string", "enum": ["open", "blocked", "chaos"] },
|
|
"zooStatus": { "type": "string", "enum": ["normal", "incident", "chaos", "lockdown"] }
|
|
},
|
|
"required": ["timeOfDay", "weather", "powerStatus", "evacuationStatus", "zooStatus"]
|
|
}
|
|
},
|
|
"required": ["turn", "currentZone", "threatLevel", "casualties", "escapedAnimals", "activeIncidents", "personnel", "playerPosition", "visibleEntities", "environment"]
|
|
},
|
|
"entityUpdates": {
|
|
"type": "array",
|
|
"description": "Specific entity position and status changes for map synchronization",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"x": { "type": "number" },
|
|
"y": { "type": "number" },
|
|
"status": { "type": "string" },
|
|
"action": { "type": "string" }
|
|
},
|
|
"required": ["id", "x", "y"]
|
|
}
|
|
}
|
|
},
|
|
"required": ["narrative", "state"],
|
|
"additionalProperties": false
|
|
};
|
|
}
|
|
|
|
// Dynamic schema - will be populated when needed
|
|
let RTS_JSON_SCHEMA = generateRTSJSONSchema();
|
|
|
|
|
|
function getModelName(settings) {
|
|
if (!settings) return undefined;
|
|
|
|
const source = settings.chat_completion_source;
|
|
if (!source) {
|
|
// Fallback for older structures or different contexts
|
|
return settings.model;
|
|
}
|
|
|
|
// Maps chat completion source to its corresponding model property name
|
|
const modelPropertyMap = {
|
|
'openai': 'openai_model',
|
|
'google': 'google_model',
|
|
'vertexai': 'vertexai_model',
|
|
'claude': 'claude_model',
|
|
'openrouter': 'openrouter_model',
|
|
'mistralai': 'mistralai_model',
|
|
'cohere': 'cohere_model',
|
|
'groq': 'groq_model',
|
|
'deepseek': 'deepseek_model',
|
|
'nanogpt': 'nanogpt_model',
|
|
'xai': 'xai_model',
|
|
'ai21': 'ai21_model',
|
|
'aimlapi': 'aimlapi_model',
|
|
'moonshot': 'moonshot_model',
|
|
'perplexity': 'perplexity_model',
|
|
'pollinations': 'pollinations_model',
|
|
'custom': 'custom_model',
|
|
};
|
|
|
|
const modelPropertyName = modelPropertyMap[source];
|
|
return modelPropertyName ? settings[modelPropertyName] : settings.model;
|
|
}
|
|
|
|
|
|
function isModelCompatible(chatCompletionSettings) {
|
|
// TODO: Expand this list with more models that support structured output
|
|
const compatibleModels = [
|
|
'claude-3',
|
|
'gpt-4',
|
|
'gemini',
|
|
];
|
|
|
|
const modelName = getModelName(chatCompletionSettings);
|
|
if (!modelName) {
|
|
console.warn('RTS: Could not determine model name from settings', chatCompletionSettings);
|
|
return false;
|
|
}
|
|
|
|
const modelNameLower = modelName.toLowerCase();
|
|
return compatibleModels.some(m => modelNameLower.includes(m));
|
|
}
|
|
|
|
async function loadRtsSettings() {
|
|
// Load settings
|
|
Object.assign(rtsSettings, extension_settings[extensionId]);
|
|
|
|
// Set UI elements
|
|
$('#rts-structured-output-toggle').prop('checked', rtsSettings.structuredOutput);
|
|
$('#rts-content-filter-toggle').prop('checked', rtsSettings.contentFilter);
|
|
|
|
// Auto-schema is enabled by default
|
|
if (rtsSettings.autoSchemaUpdates === undefined) {
|
|
rtsSettings.autoSchemaUpdates = true;
|
|
extension_settings[extensionId].autoSchemaUpdates = true;
|
|
saveSettingsDebounced();
|
|
}
|
|
}
|
|
|
|
function onStructuredOutputToggle(event) {
|
|
const value = Boolean($(event.target).prop('checked'));
|
|
rtsSettings.structuredOutput = value;
|
|
extension_settings[extensionId].structuredOutput = value;
|
|
saveSettingsDebounced();
|
|
}
|
|
|
|
function onContentFilterToggle(event) {
|
|
const value = Boolean($(event.target).prop('checked'));
|
|
rtsSettings.contentFilter = value;
|
|
extension_settings[extensionId].contentFilter = value;
|
|
saveSettingsDebounced();
|
|
}
|
|
|
|
function onAutoSchemaToggle(enabled) {
|
|
rtsSettings.autoSchemaUpdates = enabled;
|
|
extension_settings[extensionId].autoSchemaUpdates = enabled;
|
|
saveSettingsDebounced();
|
|
console.log('RTS: Auto-schema updates', enabled ? 'enabled' : 'disabled');
|
|
}
|
|
|
|
|
|
// Function to get current settings (for dropdown sync)
|
|
function getRTSSettings() {
|
|
return { ...rtsSettings };
|
|
}
|
|
|
|
// Export functions for use in RTSUIController
|
|
export { getRTSSettings, onAutoSchemaToggle, onStructuredOutputToggle };
|
|
|
|
let root;
|
|
let topButton;
|
|
let uiMounted = false;
|
|
|
|
async function addTopBarButton() {
|
|
console.log('RTS Chat Mode: Adding top bar button...');
|
|
if (topButton) {
|
|
console.warn('RTS Chat Mode: Top button already exists, skipping creation.');
|
|
return;
|
|
}
|
|
topButton = $(await renderExtensionTemplateAsync('rts-mode', 'button'));
|
|
$('#top-settings-holder').append(topButton);
|
|
|
|
// Set up direct RTS UI toggle functionality
|
|
topButton.on('click', async (e) => {
|
|
e.stopPropagation();
|
|
console.log('RTS Mode button clicked');
|
|
|
|
try {
|
|
// Toggle between fullscreen RTS UI and normal SillyTavern UI
|
|
if (rtsUI.isActive()) {
|
|
await rtsUI.exitFullscreen();
|
|
// Update button to show we're back to normal mode
|
|
topButton.find('i').removeClass('fa-eye-slash').addClass('fa-chess-board');
|
|
topButton.attr('title', 'Toggle RTS UI').attr('data-i18n', '[title]Toggle RTS UI');
|
|
console.log('RTS UI hidden, returned to SillyTavern interface');
|
|
} else {
|
|
await rtsUI.enterFullscreen();
|
|
// Update button to show we're in fullscreen mode
|
|
topButton.find('i').removeClass('fa-chess-board').addClass('fa-eye-slash');
|
|
topButton.attr('title', 'Hide RTS UI').attr('data-i18n', '[title]Hide RTS UI');
|
|
console.log('RTS UI activated');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error toggling RTS UI:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function mountUI() {
|
|
if (!document.getElementById('rts-mode-root')) {
|
|
root = document.createElement('div');
|
|
root.id = 'rts-mode-root';
|
|
document.body.appendChild(root);
|
|
|
|
createMapCanvas(root);
|
|
createResourcePanel(root);
|
|
|
|
console.log('RTS Chat Mode UI mounted.');
|
|
uiMounted = true;
|
|
|
|
// Update button icon to show UI is active
|
|
topButton?.find('i').removeClass('fa-chess-board').addClass('fa-eye-slash');
|
|
topButton?.attr('title', 'Hide RTS UI').attr('data-i18n', '[title]Hide RTS UI');
|
|
}
|
|
}
|
|
|
|
function unmountUI() {
|
|
if (root) {
|
|
root.remove();
|
|
root = null;
|
|
console.log('RTS Chat Mode UI unmounted.');
|
|
uiMounted = false;
|
|
|
|
// Update button icon to show UI is hidden
|
|
topButton?.find('i').removeClass('fa-eye-slash').addClass('fa-chess-board');
|
|
topButton?.attr('title', 'Toggle RTS UI').attr('data-i18n', '[title]Toggle RTS UI');
|
|
}
|
|
}
|
|
|
|
async function onRtsStartCommand() {
|
|
console.log('RTS Start command executed.');
|
|
|
|
const presetSelect = /** @type {HTMLSelectElement} */ (document.getElementById('rts-preset-select'));
|
|
const selectedPreset = presetSelect ? presetSelect.value : '/scripts/extensions/rts-mode/presets/zoo_escape.json';
|
|
await rtsUI.loadPreset(selectedPreset);
|
|
|
|
GameStateManager.reset();
|
|
|
|
// Update schema for fresh game state
|
|
updateSchemaForGameState(GameStateManager.getState());
|
|
|
|
// If RTS UI is active, update it
|
|
if (rtsUI.isActive()) {
|
|
rtsUI.updateUI();
|
|
rtsUI.addLogEntry('system', 'Game state reset. New campaign begins!');
|
|
}
|
|
|
|
return 'RTS game has been reset with the selected preset.';
|
|
}
|
|
|
|
function onRtsCmdCommand(args, value) {
|
|
console.log('RTS Command executed with args:', args, 'value:', value);
|
|
if (value) {
|
|
// The UI will now be updated by the 'rts-narrative-update' event listener
|
|
sendTurn(value);
|
|
return `RTS Command executed: ${value}`;
|
|
}
|
|
return 'No command provided';
|
|
}
|
|
|
|
async function onRtsUICommand() {
|
|
console.log('RTS UI toggle command executed.');
|
|
|
|
if (rtsUI.isActive()) {
|
|
await rtsUI.exitFullscreen();
|
|
// Update button state to match
|
|
if (topButton) {
|
|
topButton.find('i').removeClass('fa-eye-slash').addClass('fa-chess-board');
|
|
topButton.attr('title', 'Toggle RTS UI').attr('data-i18n', '[title]Toggle RTS UI');
|
|
}
|
|
return 'RTS UI hidden. Returned to normal SillyTavern interface.';
|
|
} else {
|
|
await rtsUI.enterFullscreen();
|
|
// Update button state to match
|
|
if (topButton) {
|
|
topButton.find('i').removeClass('fa-chess-board').addClass('fa-eye-slash');
|
|
topButton.attr('title', 'Hide RTS UI').attr('data-i18n', '[title]Hide RTS UI');
|
|
}
|
|
return 'RTS UI activated. Use ESC key or /rts-ui to return to normal interface.';
|
|
}
|
|
}
|
|
|
|
jQuery(async function() {
|
|
console.log('RTS Chat Mode: jQuery ready, initializing extension...');
|
|
|
|
// Load settings
|
|
extension_settings[extensionId] = extension_settings[extensionId] || {};
|
|
loadRtsSettings();
|
|
|
|
await addTopBarButton();
|
|
|
|
// Add event listeners
|
|
$('#rts-structured-output-toggle').on('input', onStructuredOutputToggle);
|
|
$('#rts-content-filter-toggle').on('input', onContentFilterToggle);
|
|
|
|
// Register slash commands
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-start',
|
|
callback: onRtsStartCommand,
|
|
helpString: 'Resets the RTS game state.',
|
|
}));
|
|
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-cmd',
|
|
callback: onRtsCmdCommand,
|
|
helpString: 'Sends a command to the RTS game master.',
|
|
unnamedArgumentList: [
|
|
new SlashCommandArgument('command', [ARGUMENT_TYPE.STRING], true),
|
|
],
|
|
}));
|
|
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-ui',
|
|
callback: onRtsUICommand,
|
|
aliases: ['rts-toggle', 'rts-fullscreen'],
|
|
helpString: 'Toggles the full-screen RTS interface.',
|
|
}));
|
|
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-observe',
|
|
callback: () => onRtsCmdCommand([], 'Look around carefully to assess the situation.'),
|
|
helpString: 'Quick action: Observe the surroundings.',
|
|
}));
|
|
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-move',
|
|
callback: () => onRtsCmdCommand([], 'Move to a specific location.'),
|
|
helpString: 'Quick action: Move to another location.',
|
|
}));
|
|
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-hide',
|
|
callback: () => onRtsCmdCommand([], 'Find a hiding spot.'),
|
|
helpString: 'Quick action: Find a place to hide.',
|
|
}));
|
|
|
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|
name: 'rts-interact',
|
|
callback: () => onRtsCmdCommand([], 'Interact with something in the environment.'),
|
|
helpString: 'Quick action: Interact with nearby objects or people.',
|
|
}));
|
|
|
|
// Listen for game state updates to keep schema current
|
|
document.addEventListener('rts-narrative-update', (event) => {
|
|
if (event instanceof CustomEvent && rtsSettings.autoSchemaUpdates && event.detail && event.detail.state) {
|
|
updateSchemaForGameState(event.detail.state);
|
|
}
|
|
});
|
|
|
|
console.log('RTS Chat Mode: Extension initialized successfully');
|
|
});
|
|
|
|
/**
|
|
* Updates the JSON schema based on current game state to optimize for what's actually needed
|
|
* @param {object} gameState - Current game state
|
|
*/
|
|
function updateSchemaForGameState(gameState) {
|
|
if (!gameState) {
|
|
RTS_JSON_SCHEMA = generateRTSJSONSchema();
|
|
return;
|
|
}
|
|
|
|
// Analyze current state to determine what fields are actually needed
|
|
const schemaOptimizations = {
|
|
// Always require core fields
|
|
coreFields: ["turn", "currentZone", "threatLevel", "playerPosition", "visibleEntities", "environment"],
|
|
|
|
// Conditionally require tracking fields based on game progression
|
|
conditionalFields: []
|
|
};
|
|
|
|
// If game has progressed beyond setup, require tracking systems
|
|
if (gameState.turn > 0) {
|
|
schemaOptimizations.conditionalFields.push("casualties", "escapedAnimals", "activeIncidents");
|
|
}
|
|
|
|
// Always require personnel since we track visitors and staff
|
|
schemaOptimizations.conditionalFields.push("personnel");
|
|
|
|
// Generate optimized schema
|
|
const baseSchema = generateRTSJSONSchema(gameState);
|
|
|
|
// Update required fields in state object based on analysis
|
|
const stateRequired = [...schemaOptimizations.coreFields, ...schemaOptimizations.conditionalFields];
|
|
baseSchema.properties.state.required = stateRequired;
|
|
|
|
// Add contextual descriptions based on current state
|
|
if (gameState.turn === 0) {
|
|
baseSchema.properties.narrative.description = "Brief description of the peaceful zoo atmosphere before any incidents occur.";
|
|
baseSchema.properties.state.properties.casualties.description = "Should remain at zero totals for pre-incident state.";
|
|
baseSchema.properties.state.properties.escapedAnimals.description = "Should remain empty for pre-incident state.";
|
|
} else {
|
|
baseSchema.properties.narrative.description = "Brief atmospheric narrative (2-3 sentences max) focusing on immediate danger, actions, and consequences.";
|
|
}
|
|
|
|
// Optimize entity schema based on visible entities
|
|
if (gameState.visibleEntities && gameState.visibleEntities.length > 0) {
|
|
// Add more specific validation for entity types we've seen
|
|
const entityTypes = [...new Set(gameState.visibleEntities.map(e => e.type))];
|
|
if (entityTypes.length > 0) {
|
|
baseSchema.properties.state.properties.visibleEntities.items.properties.type.enum = entityTypes;
|
|
}
|
|
}
|
|
|
|
RTS_JSON_SCHEMA = baseSchema;
|
|
console.log('RTS: Updated JSON schema for turn', gameState.turn, 'with required fields:', stateRequired);
|
|
}
|
|
|
|
eventSource.on(event_types.CHAT_COMPLETION_SETTINGS_READY, (data) => {
|
|
const { chatCompletionSettings } = SillyTavern.getContext();
|
|
console.log('RTS: Chat completion settings ready:', chatCompletionSettings);
|
|
console.log('RTS: Structured output setting:', rtsSettings.structuredOutput);
|
|
console.log('RTS: Model compatibility check:', isModelCompatible(chatCompletionSettings));
|
|
if (rtsSettings.structuredOutput && isModelCompatible(chatCompletionSettings)) {
|
|
// Update schema based on current game state before sending
|
|
try {
|
|
const currentState = GameStateManager.getState();
|
|
updateSchemaForGameState(currentState);
|
|
} catch (error) {
|
|
console.warn('RTS: Could not update schema with current state:', error);
|
|
RTS_JSON_SCHEMA = generateRTSJSONSchema();
|
|
}
|
|
|
|
data.responseMimeType = "application/json";
|
|
data.responseSchema = RTS_JSON_SCHEMA;
|
|
console.log('RTS: Using structured output with dynamic schema');
|
|
//dump the schema to console for debugging
|
|
console.log('RTS: Current JSON schema:', JSON.stringify(RTS_JSON_SCHEMA, null, 2));
|
|
}
|
|
}); |