agent updates

This commit is contained in:
Brian Madison
2025-10-02 21:45:59 -05:00
parent c6704b4b6e
commit 3f40ef4756
69 changed files with 2596 additions and 55160 deletions

View File

@@ -0,0 +1,160 @@
const fs = require('fs-extra');
const path = require('node:path');
const { getSourcePath } = require('./project-root');
/**
* Builds activation blocks from fragments based on agent profile
*/
class ActivationBuilder {
constructor() {
this.fragmentsDir = getSourcePath('utility', 'models', 'fragments');
this.fragmentCache = new Map();
}
/**
* Load a fragment file
* @param {string} fragmentName - Name of fragment file (e.g., 'activation-init.xml')
* @returns {string} Fragment content
*/
async loadFragment(fragmentName) {
// Check cache first
if (this.fragmentCache.has(fragmentName)) {
return this.fragmentCache.get(fragmentName);
}
const fragmentPath = path.join(this.fragmentsDir, fragmentName);
if (!(await fs.pathExists(fragmentPath))) {
throw new Error(`Fragment not found: ${fragmentName}`);
}
const content = await fs.readFile(fragmentPath, 'utf8');
this.fragmentCache.set(fragmentName, content);
return content;
}
/**
* Build complete activation block based on agent profile
* @param {Object} profile - Agent profile from AgentAnalyzer
* @param {Object} metadata - Agent metadata (module, name, etc.)
* @param {Array} agentSpecificActions - Optional agent-specific critical actions
* @returns {string} Complete activation block XML
*/
async buildActivation(profile, metadata = {}, agentSpecificActions = []) {
let activation = '<activation critical="MANDATORY">\n';
// 1. Build sequential steps
const steps = await this.buildSteps(metadata, agentSpecificActions);
activation += this.indent(steps, 2) + '\n';
// 2. Build menu handlers section with dynamic handlers
const menuHandlers = await this.loadFragment('menu-handlers.xml');
// Build extract list (comma-separated list of used attributes)
const extractList = profile.usedAttributes.join(', ');
// Build handlers (load only needed handlers)
const handlers = await this.buildHandlers(profile);
const processedHandlers = menuHandlers.replace('{DYNAMIC_EXTRACT_LIST}', extractList).replace('{DYNAMIC_HANDLERS}', handlers);
activation += '\n' + this.indent(processedHandlers, 2) + '\n';
// 3. Always include rules
const rules = await this.loadFragment('activation-rules.xml');
activation += this.indent(rules, 2) + '\n';
activation += '</activation>';
return activation;
}
/**
* Build handlers section based on profile
* @param {Object} profile - Agent profile
* @returns {string} Handlers XML
*/
async buildHandlers(profile) {
const handlerFragments = [];
for (const attrType of profile.usedAttributes) {
const fragmentName = `handler-${attrType}.xml`;
try {
const handler = await this.loadFragment(fragmentName);
handlerFragments.push(handler);
} catch {
console.warn(`Warning: Handler fragment not found: ${fragmentName}`);
}
}
return handlerFragments.join('\n');
}
/**
* Build sequential activation steps
* @param {Object} metadata - Agent metadata
* @param {Array} agentSpecificActions - Optional agent-specific actions
* @returns {string} Steps XML
*/
async buildSteps(metadata = {}, agentSpecificActions = []) {
const stepsTemplate = await this.loadFragment('activation-steps.xml');
// Extract basename from agent ID (e.g., "bmad/bmm/agents/pm.md" → "pm")
const agentBasename = metadata.id ? metadata.id.split('/').pop().replace('.md', '') : metadata.name || 'agent';
// Build agent-specific steps
let agentStepsXml = '';
let currentStepNum = 4; // Steps 1-3 are standard
if (agentSpecificActions && agentSpecificActions.length > 0) {
agentStepsXml = agentSpecificActions
.map((action) => {
const step = `<step n="${currentStepNum}">${action}</step>`;
currentStepNum++;
return step;
})
.join('\n');
}
// Calculate final step numbers
const menuStep = currentStepNum;
const haltStep = currentStepNum + 1;
const inputStep = currentStepNum + 2;
const executeStep = currentStepNum + 3;
// Replace placeholders
const processed = stepsTemplate
.replace('{agent-file-basename}', agentBasename)
.replace('{module}', metadata.module || 'core')
.replace('{AGENT_SPECIFIC_STEPS}', agentStepsXml)
.replace('{MENU_STEP}', menuStep.toString())
.replace('{HALT_STEP}', haltStep.toString())
.replace('{INPUT_STEP}', inputStep.toString())
.replace('{EXECUTE_STEP}', executeStep.toString());
return processed;
}
/**
* Indent XML content
* @param {string} content - Content to indent
* @param {number} spaces - Number of spaces to indent
* @returns {string} Indented content
*/
indent(content, spaces) {
const indentation = ' '.repeat(spaces);
return content
.split('\n')
.map((line) => (line ? indentation + line : line))
.join('\n');
}
/**
* Clear fragment cache (useful for testing or hot reload)
*/
clearCache() {
this.fragmentCache.clear();
}
}
module.exports = { ActivationBuilder };