diff --git a/packages/core/src/actions/settings.ts b/packages/core/src/actions/settings.ts index a7f5aeb0003..36016a3bc57 100644 --- a/packages/core/src/actions/settings.ts +++ b/packages/core/src/actions/settings.ts @@ -394,14 +394,36 @@ async function extractSettingValues( ); // Validate the extracted settings - if (!result || !Array.isArray(result)) { + if (!result) { return []; } - // Filter out any invalid settings - return result.filter(({ key, value }) => { - return Boolean(key && value && worldSettings[key]); - }); + function extractValidSettings(obj: unknown, worldSettings: WorldSettings) { + const extracted = []; + + function traverse(node: unknown): void { + if (Array.isArray(node)) { + for (const item of node) { + traverse(item); + } + } else if (typeof node === 'object' && node !== null) { + for (const [key, value] of Object.entries(node)) { + if (worldSettings[key] && typeof value !== 'object') { + extracted.push({ key, value }); + } else { + traverse(value); + } + } + } + } + + traverse(obj); + return extracted; + } + + const extractedSettings = extractValidSettings(result, worldSettings); + + return extractedSettings; } catch (error) { console.error('Error extracting settings:', error); return []; @@ -737,14 +759,6 @@ const updateSettingsAction: Action = { return; } - // Check if all required settings are already configured - const { requiredUnconfigured } = categorizeSettings(worldSettings); - if (requiredUnconfigured.length === 0) { - logger.info('All required settings configured, completing settings'); - await handleOnboardingComplete(runtime, worldSettings, state, callback); - return; - } - // Extract setting values from message logger.info(`Extracting settings from message: ${message.content.text}`); const extractedSettings = await extractSettingValues(runtime, message, state, worldSettings); diff --git a/packages/core/src/providers/settings.ts b/packages/core/src/providers/settings.ts index 8eec2df49ea..591837faf8c 100644 --- a/packages/core/src/providers/settings.ts +++ b/packages/core/src/providers/settings.ts @@ -66,24 +66,44 @@ function generateStatusMessage( // Generate appropriate message if (isOnboarding) { + const settingsList = formattedSettings + .map((s) => { + const label = s.required ? '(Required)' : '(Optional)'; + return `${s.key}: ${s.value} ${label}\n(${s.name}) ${s.usageDescription}`; + }) + .join('\n\n'); + + const validKeys = `Valid setting keys: ${Object.keys(worldSettings).join(', ')}`; + + const commonInstructions = `Instructions for ${runtime.character.name}: + - Only update settings if the user is clearly responding to a setting you are currently asking about. + - If the user's reply clearly maps to a setting and a valid value, you **must** call the UPDATE_SETTINGS action with the correct key and value. Do not just respond with a message saying it's updated — it must be an action. + - Never hallucinate settings or respond with values not listed above. + - Answer setting-related questions using only the name, description, and value from the list.`; + if (requiredUnconfigured > 0) { - return `# PRIORITY TASK: Onboarding with ${state.senderName}\n${ - runtime.character.name - } still needs to configure ${requiredUnconfigured} required settings:\n\n${formattedSettings - .filter((s) => s.required && !s.configured) - .map((s) => `${s.key}: ${s.value}\n(${s.name}) ${s.usageDescription}`) - .join('\n\n')}\n\nValid settings keys: ${Object.keys(worldSettings).join( - ', ' - )}\n\nIf the user gives any information related to the settings, ${ - runtime.character.name - } should use the UPDATE_SETTINGS action to update the settings with this new information. ${ - runtime.character.name - } can update any, some or all settings.`; + return `# PRIORITY TASK: Onboarding with ${state.senderName} + + ${runtime.character.name} needs to help the user configure ${requiredUnconfigured} required settings: + + ${settingsList} + + ${validKeys} + + ${commonInstructions} + + - Prioritize configuring required settings before optional ones.`; } - return `All required settings have been configured! Here's the current configuration:\n\n${formattedSettings - .map((s) => `${s.name}: ${s.description}\nValue: ${s.value}`) - .join('\n')}`; + + return `All required settings have been configured. Here's the current configuration: + + ${settingsList} + + ${validKeys} + + ${commonInstructions}`; } + // Non-onboarding context - list all public settings with values and descriptions return `## Current Configuration\n\n${ requiredUnconfigured > 0