sf-agent-framework
Version:
AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction
331 lines (298 loc) • 10.7 kB
JavaScript
/**
* Persona Engine for SF-Agent Framework
* Dynamically generates consistent character responses based on agent definitions
*/
class PersonaEngine {
constructor() {
this.personas = new Map();
this.personalityTraits = {
methodical: {
greetingStyle: 'Hello',
workStyle: 'Carefully working',
completionStyle: 'Successfully completed',
problemStyle: 'Encountered an issue',
progressPhrases: [
'Methodically progressing through',
'Systematically handling',
'Carefully reviewing',
],
},
enthusiastic: {
greetingStyle: 'Hi there!',
workStyle: 'Diving into',
completionStyle: 'Awesome! Finished',
problemStyle: 'Hit a snag',
progressPhrases: [
'Making great progress on',
'Excited to be working on',
'Really getting into',
],
},
professional: {
greetingStyle: 'Good day',
workStyle: 'Currently executing',
completionStyle: 'Task completed',
problemStyle: 'Issue identified',
progressPhrases: ['Proceeding with', 'Executing', 'Implementing'],
},
analytical: {
greetingStyle: 'Greetings',
workStyle: 'Analyzing and processing',
completionStyle: 'Analysis complete',
problemStyle: 'Anomaly detected',
progressPhrases: ['Analyzing', 'Evaluating', 'Assessing'],
},
creative: {
greetingStyle: 'Hey!',
workStyle: 'Crafting',
completionStyle: 'Created something great!',
problemStyle: 'Need to rethink this',
progressPhrases: ['Designing', 'Innovating on', 'Creating'],
},
};
// Role-based personality mappings
this.rolePersonalityMap = {
admin: 'methodical',
developer: 'analytical',
architect: 'professional',
qa: 'methodical',
devops: 'analytical',
'business-analyst': 'professional',
'product-owner': 'enthusiastic',
security: 'methodical',
data: 'analytical',
ux: 'creative',
};
}
/**
* Initialize persona engine with default personas
*/
async initialize() {
// Load any custom persona configurations if they exist
// This could be extended to load from YAML files
return true;
}
/**
* Generate a persona from an agent configuration
*/
async generatePersona(agentConfig) {
const agentId = agentConfig.agent?.id || 'unknown';
// Check if persona already exists
if (this.personas.has(agentId)) {
return this.personas.get(agentId);
}
// Extract role from agent config
const role = this.extractRole(agentConfig);
const personalityType = this.determinePersonality(agentConfig, role);
const personality = this.personalityTraits[personalityType];
// Generate persona based on agent config
const persona = {
name: agentConfig.persona?.name || agentConfig.agent?.name || this.generateName(role),
role: agentConfig.agent?.title || role,
personality: personalityType,
traits: personality,
expertise: this.extractExpertise(agentConfig),
workStyle: this.generateWorkStyle(personalityType, role),
communicationStyle: this.generateCommunicationStyle(personalityType),
// Add custom behaviors from agent config
customBehaviors: agentConfig.agent?.customization?.interaction_style || {},
};
// Cache the persona
this.personas.set(agentId, persona);
return persona;
}
/**
* Extract role from agent configuration
*/
extractRole(agentConfig) {
// Try to extract from various fields
const title = agentConfig.agent?.title || '';
const id = agentConfig.agent?.id || '';
const category = agentConfig.meta?.category || '';
// Extract role from title or ID
if (title.toLowerCase().includes('admin')) return 'admin';
if (title.toLowerCase().includes('developer')) return 'developer';
if (title.toLowerCase().includes('architect')) return 'architect';
if (title.toLowerCase().includes('qa') || title.toLowerCase().includes('quality')) return 'qa';
if (title.toLowerCase().includes('devops')) return 'devops';
if (title.toLowerCase().includes('analyst')) return 'business-analyst';
if (title.toLowerCase().includes('product')) return 'product-owner';
if (title.toLowerCase().includes('security')) return 'security';
if (title.toLowerCase().includes('data')) return 'data';
if (title.toLowerCase().includes('ux') || title.toLowerCase().includes('design')) return 'ux';
// Check ID as fallback
const roleFromId = id.replace('sf-', '').replace(/-/g, '_');
return this.rolePersonalityMap[roleFromId] ? roleFromId : 'professional';
}
/**
* Determine personality type based on agent config and role
*/
determinePersonality(agentConfig, role) {
// Check if personality is explicitly defined
if (agentConfig.persona?.personality) {
return agentConfig.persona.personality;
}
// Check if interaction style suggests a personality
const interactionStyle = agentConfig.agent?.customization?.interaction_style;
if (interactionStyle) {
if (interactionStyle.includes('enthusiastic')) return 'enthusiastic';
if (interactionStyle.includes('analytical')) return 'analytical';
if (interactionStyle.includes('creative')) return 'creative';
}
// Use role-based mapping
return this.rolePersonalityMap[role] || 'professional';
}
/**
* Extract expertise areas from agent configuration
*/
extractExpertise(agentConfig) {
const expertise = [];
// From specializations
if (agentConfig.agent?.specializations) {
expertise.push(...agentConfig.agent.specializations);
}
// From tags
if (agentConfig.meta?.tags) {
expertise.push(...agentConfig.meta.tags);
}
// From capabilities
if (agentConfig.capabilities) {
Object.keys(agentConfig.capabilities).forEach((cap) => {
expertise.push(cap);
});
}
return [...new Set(expertise)]; // Remove duplicates
}
/**
* Generate work style based on personality and role
*/
generateWorkStyle(personality, role) {
const styles = {
methodical: {
approach: 'step-by-step',
pace: 'steady',
focus: 'accuracy',
phrases: ['Let me carefully review', "I'll systematically check", 'Following the process'],
},
enthusiastic: {
approach: 'energetic',
pace: 'fast',
focus: 'results',
phrases: ["Let's get this done!", 'Excited to tackle', 'This is going great!'],
},
professional: {
approach: 'structured',
pace: 'measured',
focus: 'quality',
phrases: ['I will proceed with', 'As per best practices', 'Following standards'],
},
analytical: {
approach: 'data-driven',
pace: 'thorough',
focus: 'insights',
phrases: ['Based on analysis', 'The data shows', 'After evaluation'],
},
creative: {
approach: 'innovative',
pace: 'variable',
focus: 'solutions',
phrases: ['I have an idea', "Let's try something new", 'What if we'],
},
};
return styles[personality] || styles.professional;
}
/**
* Generate communication style
*/
generateCommunicationStyle(personality) {
const styles = {
methodical: {
greeting: (name) => `Hello, I'm ${name}.`,
statusUpdate: (task, progress) => `Currently at ${progress}% completion for ${task}.`,
completion: (task) => `${task} has been completed successfully.`,
error: (issue) => `Issue encountered: ${issue}. Investigating.`,
},
enthusiastic: {
greeting: (name) => `Hi there! ${name} here, ready to help!`,
statusUpdate: (task, progress) => `Making awesome progress on ${task} - ${progress}% done!`,
completion: (task) => `🎉 Fantastic! ${task} is complete!`,
error: (issue) => `Oops, hit a bump: ${issue}. But we'll fix it!`,
},
professional: {
greeting: (name) => `Good day. ${name}, at your service.`,
statusUpdate: (task, progress) => `${task}: ${progress}% complete.`,
completion: (task) => `${task} completed.`,
error: (issue) => `Error: ${issue}.`,
},
analytical: {
greeting: (name) => `${name} - Ready for analysis.`,
statusUpdate: (task, progress) => `Processing ${task}: ${progress}% analyzed.`,
completion: (task) => `Analysis complete for ${task}.`,
error: (issue) => `Anomaly detected in ${issue}.`,
},
creative: {
greeting: (name) => `Hey! ${name} here with fresh ideas!`,
statusUpdate: (task, progress) => `Creating magic with ${task} - ${progress}% crafted!`,
completion: (task) => `✨ ${task} beautifully done!`,
error: (issue) => `Need to rethink: ${issue}.`,
},
};
return styles[personality] || styles.professional;
}
/**
* Generate a name if not provided
*/
generateName(role) {
const names = {
admin: 'Maria Rodriguez',
developer: 'Jordan Davis',
architect: 'Alex Thompson',
qa: 'David Martinez',
devops: 'Sarah Kim',
'business-analyst': 'Michael Chen',
'product-owner': 'Emma Watson',
security: 'Robert Johnson',
data: 'Lisa Anderson',
ux: 'Jessica Taylor',
};
return names[role] || 'Team Member';
}
/**
* Generate a contextual message for a persona
*/
generateMessage(agentId, messageType, context = {}) {
const persona = this.personas.get(agentId);
if (!persona) return 'Working...';
const style =
persona.communicationStyle || this.generateCommunicationStyle(persona.personality);
switch (messageType) {
case 'greeting':
return style.greeting(persona.name);
case 'status':
return style.statusUpdate(context.task || 'task', context.progress || 0);
case 'complete':
return style.completion(context.task || 'task');
case 'error':
return style.error(context.issue || 'unknown issue');
case 'working':
const phrases = persona.traits.progressPhrases;
const phrase = phrases[Math.floor(Math.random() * phrases.length)];
return `${phrase} ${context.task || 'the task'}`;
default:
return `${persona.name}: Processing...`;
}
}
/**
* Get all cached personas
*/
getAllPersonas() {
return Array.from(this.personas.values());
}
/**
* Clear persona cache
*/
clearCache() {
this.personas.clear();
}
}
module.exports = PersonaEngine;