feat: add structured skills parsing with categories and levels

Add AI tracker awareness for skills system with proper level and category support.

Changes:
- Add extractSkills() parser function to extract structured skills data
  - Parses category-based format: "CategoryName:\n- SkillName (Lv X)"
  - Falls back to legacy string format for backward compatibility
  - Returns structured data: { version: 1, categories: {}, uncategorized: [] }

- Update prompt instructions to request structured skills format
  - AI now generates: "Skills:\nCombat:\n- Swordsmanship (Lv 5)"
  - Supports multiple categories (Combat, Magic, Social, Crafting, etc.)
  - Includes Uncategorized section for skills without clear category

- Add buildSkillsSummary() utility function
  - Converts structured skills data back to formatted text
  - Ready for future feature: syncing manual skill edits to AI context

Parser integration:
- parseUserStats() now uses extractSkills() to parse Skills section
- Stores structured data in extensionSettings.userStats.skills
- Widget reads structured data for display and level-up/down functionality

AI workflow:
1. AI generates skills in structured format (via prompt instructions)
2. Parser extracts to structured data (via extractSkills)
3. Widget displays with level controls (already implemented)
4. Raw text flows through committedTrackerData to next generation

Note: Manual skill edits (level-up/down in widget) are not yet synced back
to AI context. This requires additional work to regenerate the raw text
when skills are manually modified. buildSkillsSummary is ready for this.

Refs: Skills widget implementation (previous session)
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-11-06 22:06:22 +11:00
parent 0a5bad6b1c
commit 0f96c62c62
2 changed files with 142 additions and 7 deletions
+54 -3
View File
@@ -10,6 +10,53 @@ import { extensionSettings, committedTrackerData, FEATURE_FLAGS } from '../../co
// Type imports
/** @typedef {import('../../types/inventory.js').InventoryV2} InventoryV2 */
/**
* Builds a formatted skills summary for AI context injection.
* Converts structured skills data to multi-line plaintext format organized by category.
*
* @param {Object|string} skills - Current skills (structured or legacy string)
* @returns {string} Formatted skills summary for prompt injection
* @example
* // Structured input: { version: 1, categories: { Combat: [{name: 'Swordsmanship', level: 5}] }, uncategorized: [] }
* // Returns: "Skills:\nCombat:\n- Swordsmanship (Lv 5)"
*/
export function buildSkillsSummary(skills) {
// Handle legacy string format
if (typeof skills === 'string') {
return `Skills: ${skills}`;
}
// Handle structured format
if (skills && typeof skills === 'object' && skills.version) {
let summary = 'Skills:';
const categories = skills.categories || {};
const uncategorized = skills.uncategorized || [];
// Add categorized skills
for (const [categoryName, skillsList] of Object.entries(categories)) {
if (skillsList && skillsList.length > 0) {
summary += `\n${categoryName}:`;
for (const skill of skillsList) {
summary += `\n- ${skill.name} (Lv ${skill.level})`;
}
}
}
// Add uncategorized skills
if (uncategorized.length > 0) {
summary += '\nUncategorized:';
for (const skill of uncategorized) {
summary += `\n- ${skill.name} (Lv ${skill.level})`;
}
}
return summary;
}
// Empty or invalid
return 'Skills: None';
}
/**
* Builds a formatted inventory summary for AI context injection.
* Converts v2 inventory structure to multi-line plaintext format.
@@ -166,9 +213,13 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon
// Add skills section if enabled
if (userStatsConfig?.skillsSection?.enabled) {
const skillFields = userStatsConfig.skillsSection.customFields || [];
const skillFieldsText = skillFields.map(f => `[${f}]`).join(', ');
instructions += `Skills: [${skillFieldsText || 'Skill1, Skill2, etc.'}]\n`;
instructions += `Skills:\n`;
instructions += `[Category Name]:\n`;
instructions += `- [Skill Name] (Lv [1-100])\n`;
instructions += `- [Another Skill] (Lv [1-100])\n`;
instructions += `Uncategorized:\n`;
instructions += `- [Uncategorized Skill] (Lv [1-100])\n`;
instructions += `(Organize skills by logical categories like Combat, Magic, Social, Crafting, etc. Include level as integer 1-100. Skills without a clear category go in Uncategorized.)\n`;
}
// Add inventory format based on feature flag