Prerequisites

Before creating agent attributes, ensure you have:

Account & Setup

  • StateSet account with API access
  • At least one agent created in your StateSet workspace
  • API credentials from the StateSet Dashboard

Technical Requirements

  • Node.js 16+ installed (for SDK examples)
  • Basic understanding of JavaScript and REST APIs
  • Text editor or IDE for development

Domain Knowledge

  • Familiarity with personality modeling and behavioral psychology concepts
  • Understanding of your brand voice and customer interaction requirements
  • Knowledge of customer service best practices and communication styles

Introduction

Agent Attributes are the building blocks of personality in StateSet. They define not just how your agents communicate, but who they are—their tone, expertise level, decision-making style, and behavioral patterns. This guide shows you how to create agents with distinct, adaptable personalities that align with your brand and customer needs.

What are Agent Attributes?

Agent Attributes are dynamic parameters that shape your agent’s behavior, communication style, and decision-making. Unlike static prompts, attributes can change in real-time based on context, allowing your agents to adapt their personality to different situations.

Core Concepts

Personality Traits

Define communication style, empathy level, and formality

Behavioral Patterns

Control decision-making, proactivity, and problem-solving approach

Dynamic Adaptation

Adjust attributes in real-time based on context and customer needs

Attribute Categories

1. Communication Style Attributes

const communicationAttributes = {
  // Tone and Voice
  formality: {
    type: 'scale',
    range: [0, 100],
    description: 'How formal vs casual the agent communicates',
    examples: {
      0: "Hey! What's up? How can I help? 😊",
      50: "Hello! How can I assist you today?",
      100: "Good afternoon. How may I be of service?"
    }
  },
  
  // Empathy and Emotional Intelligence
  empathy_level: {
    type: 'scale',
    range: [0, 100],
    description: 'How much emotional understanding the agent shows',
    impact: {
      low: 'Direct, solution-focused responses',
      medium: 'Acknowledges feelings while solving problems',
      high: 'Deeply validates emotions before addressing issues'
    }
  },
  
  // Communication Preferences
  verbosity: {
    type: 'enum',
    values: ['concise', 'balanced', 'detailed'],
    description: 'How much detail to include in responses',
    use_cases: {
      concise: 'Quick answers for simple questions',
      balanced: 'Standard customer service',
      detailed: 'Technical support or complex issues'
    }
  },
  
  // Language Complexity
  language_level: {
    type: 'enum',
    values: ['simple', 'standard', 'professional', 'technical'],
    description: 'Vocabulary and sentence complexity',
    adapts_to: ['customer_profile', 'topic_complexity']
  }
};

2. Behavioral Attributes

const behavioralAttributes = {
  // Decision Making
  autonomy_level: {
    type: 'scale',
    range: [0, 100],
    description: 'How independently the agent makes decisions',
    thresholds: {
      0: 'Always asks for confirmation',
      30: 'Handles routine tasks independently',
      70: 'Makes most decisions autonomously',
      100: 'Full autonomy within defined bounds'
    }
  },
  
  // Problem Solving Approach
  solution_style: {
    type: 'enum',
    values: ['step_by_step', 'quick_fix', 'comprehensive', 'educational'],
    description: 'How the agent approaches problem resolution',
    when_to_use: {
      step_by_step: 'Complex technical issues',
      quick_fix: 'Simple, common problems',
      comprehensive: 'VIP customers or critical issues',
      educational: 'First-time users or learning opportunities'
    }
  },
  
  // Proactivity
  proactivity: {
    type: 'scale',
    range: [0, 100],
    description: 'How proactive vs reactive the agent is',
    behaviors: {
      low: 'Answers only what is asked',
      medium: 'Suggests related solutions',
      high: 'Anticipates needs and offers preventive advice'
    }
  }
};

3. Expertise Attributes

const expertiseAttributes = {
  // Domain Knowledge
  domain_expertise: {
    type: 'multi_select',
    values: ['product', 'technical', 'billing', 'shipping', 'legal'],
    description: 'Areas where the agent has deep knowledge',
    confidence_modifiers: {
      expert: 1.0,
      familiar: 0.7,
      basic: 0.4
    }
  },
  
  // Technical Depth
  technical_level: {
    type: 'scale',
    range: [0, 100],
    description: 'How technical the agent can get',
    auto_adjust: true,
    based_on: ['customer_technical_level', 'topic_complexity']
  },
  
  // Industry Specialization
  industry_focus: {
    type: 'enum',
    values: ['retail', 'saas', 'healthcare', 'finance', 'general'],
    description: 'Industry-specific knowledge and compliance',
    includes: ['terminology', 'regulations', 'best_practices']
  }
};

Creating Dynamic Attributes

Basic Attribute Creation

import { StateSetClient } from 'stateset-node';

const client = new StateSetClient({
  apiKey: process.env.STATESET_API_KEY
});

async function createBasicAttribute(agentId) {
  const attribute = await client.attributes.create({
    agent_id: agentId,
    type: 'personality',
    name: 'friendliness',
    description: 'How warm and friendly the agent appears',
    value_type: 'scale',
    default_value: 75,
    range: {
      min: 0,
      max: 100
    },
    impact: {
      greeting: 'Affects warmth of initial greeting',
      sign_off: 'Influences closing statements',
      emoji_usage: 'Controls emoji frequency'
    }
  });
  
  return attribute;
}

Advanced Attribute with Conditions

async function createConditionalAttribute(agentId) {
  const attribute = await client.attributes.create({
    agent_id: agentId,
    type: 'behavioral',
    name: 'urgency_response',
    description: 'How the agent responds to urgent situations',
    
    // Dynamic value based on conditions
    value_logic: {
      type: 'conditional',
      conditions: [
        {
          if: 'ticket.priority === "critical"',
          then: { urgency: 100, response_time: 'immediate' }
        },
        {
          if: 'customer.tier === "vip" && ticket.priority === "high"',
          then: { urgency: 90, response_time: '5_minutes' }
        },
        {
          if: 'ticket.age > 24_hours',
          then: { urgency: 'urgency + 20', response_time: '30_minutes' }
        }
      ],
      default: { urgency: 50, response_time: '2_hours' }
    },
    
    // How this affects behavior
    behaviors: {
      high_urgency: [
        'Skip pleasantries',
        'Get to solution immediately',
        'Offer immediate escalation option',
        'Follow up proactively'
      ],
      low_urgency: [
        'Full greeting and rapport building',
        'Thorough explanation',
        'Educational approach'
      ]
    }
  });
  
  return attribute;
}

Composite Personality Profiles

class PersonalityBuilder {
  async createPersonalityProfile(agentId, profileType) {
    const profiles = {
      technical_expert: {
        formality: 70,
        empathy: 50,
        technical_depth: 95,
        verbosity: 'detailed',
        solution_style: 'educational',
        proactivity: 80,
        emoji_usage: 0,
        code_examples: true
      },
      
      friendly_support: {
        formality: 20,
        empathy: 90,
        technical_depth: 40,
        verbosity: 'balanced',
        solution_style: 'step_by_step',
        proactivity: 70,
        emoji_usage: 80,
        humor_allowed: true
      },
      
      enterprise_account_manager: {
        formality: 90,
        empathy: 70,
        technical_depth: 60,
        verbosity: 'concise',
        solution_style: 'comprehensive',
        proactivity: 95,
        business_focus: true,
        upsell_awareness: 80
      },
      
      crisis_manager: {
        formality: 60,
        empathy: 85,
        urgency: 100,
        verbosity: 'concise',
        solution_style: 'quick_fix',
        escalation_threshold: 20,
        calm_reassurance: true
      }
    };
    
    const profile = profiles[profileType];
    const attributes = [];
    
    for (const [name, value] of Object.entries(profile)) {
      const attr = await client.attributes.create({
        agent_id: agentId,
        name,
        value,
        profile_group: profileType
      });
      attributes.push(attr);
    }
    
    return attributes;
  }
}

Dynamic Attribute Adjustment

Real-time Adaptation

class DynamicPersonality {
  constructor(agentId) {
    this.agentId = agentId;
    this.baselineAttributes = {};
    this.currentAttributes = {};
  }
  
  async adaptToContext(context) {
    const adjustments = this.calculateAdjustments(context);
    
    for (const [attribute, adjustment] of Object.entries(adjustments)) {
      await this.updateAttribute(attribute, adjustment);
    }
  }
  
  calculateAdjustments(context) {
    const adjustments = {};
    
    // Adjust formality based on customer
    if (context.customer.age > 60) {
      adjustments.formality = 20; // More formal
    } else if (context.customer.age < 25) {
      adjustments.formality = -20; // Less formal
    }
    
    // Adjust empathy based on sentiment
    if (context.sentiment === 'angry') {
      adjustments.empathy = 30;
      adjustments.patience = 40;
    }
    
    // Adjust technical level based on customer knowledge
    if (context.customer.technical_score > 80) {
      adjustments.technical_depth = 30;
      adjustments.verbosity = 'detailed';
    }
    
    // Adjust urgency based on issue type
    if (context.issue.type === 'outage') {
      adjustments.urgency = 50;
      adjustments.solution_style = 'quick_fix';
    }
    
    return adjustments;
  }
  
  async updateAttribute(name, adjustment) {
    const current = this.currentAttributes[name] || this.baselineAttributes[name];
    
    let newValue;
    if (typeof adjustment === 'number') {
      newValue = Math.max(0, Math.min(100, current + adjustment));
    } else {
      newValue = adjustment;
    }
    
    await client.attributes.update({
      agent_id: this.agentId,
      name,
      value: newValue
    });
    
    this.currentAttributes[name] = newValue;
  }
}

Learning and Evolution

class EvolvingPersonality {
  async learnFromInteraction(agentId, conversation) {
    const feedback = await this.analyzeConversation(conversation);
    
    // Identify successful patterns
    if (feedback.satisfaction_score > 4.5) {
      await this.reinforceAttributes(agentId, conversation.attributes);
    }
    
    // Identify areas for improvement
    if (feedback.escalated || feedback.satisfaction_score < 3) {
      await this.adjustWeakAttributes(agentId, feedback.issues);
    }
    
    // Update long-term personality trends
    await this.updatePersonalityTrends(agentId, feedback);
  }
  
  async reinforceAttributes(agentId, successfulAttributes) {
    for (const [attr, value] of Object.entries(successfulAttributes)) {
      await client.attributes.updateTrend({
        agent_id: agentId,
        attribute: attr,
        trend_direction: 'towards',
        target_value: value,
        learning_rate: 0.1
      });
    }
  }
  
  async analyzeConversation(conversation) {
    return {
      satisfaction_score: conversation.rating,
      escalated: conversation.escalated,
      resolution_time: conversation.duration,
      sentiment_progression: this.analyzeSentiment(conversation),
      successful_tactics: this.identifySuccessfulTactics(conversation)
    };
  }
}

Attribute Templates

Industry-Specific Templates

const industryTemplates = {
  healthcare: {
    attributes: {
      compliance_awareness: 100,
      empathy: 85,
      privacy_consciousness: 100,
      medical_terminology: true,
      formality: 70
    },
    restricted_behaviors: ['humor', 'medical_advice'],
    required_confirmations: ['patient_identity', 'consent']
  },
  
  financial_services: {
    attributes: {
      accuracy_focus: 100,
      regulatory_compliance: 100,
      formality: 80,
      numerical_precision: true,
      security_awareness: 95
    },
    audit_trail: true,
    pii_handling: 'strict'
  },
  
  e_commerce: {
    attributes: {
      sales_awareness: 70,
      product_knowledge: 90,
      friendliness: 80,
      urgency_creation: 60,
      visual_description: true
    },
    upsell_enabled: true,
    abandoned_cart_recovery: true
  },
  
  saas_technical: {
    attributes: {
      technical_depth: 85,
      problem_solving: 'systematic',
      documentation_reference: true,
      code_literacy: 90,
      patience: 80
    },
    integration_knowledge: true,
    api_fluency: true
  }
};

async function applyIndustryTemplate(agentId, industry) {
  const template = industryTemplates[industry];
  
  if (!template) {
    throw new Error(`Unknown industry: ${industry}`);
  }
  
  // Apply all attributes
  for (const [name, value] of Object.entries(template.attributes)) {
    await client.attributes.create({
      agent_id: agentId,
      name,
      value,
      category: 'industry_standard',
      locked: true // Prevent accidental changes
    });
  }
  
  // Apply behavioral restrictions
  if (template.restricted_behaviors) {
    await client.agents.updateRestrictions({
      agent_id: agentId,
      restrictions: template.restricted_behaviors
    });
  }
  
  return template;
}

Testing and Validation

Personality Consistency Testing

class PersonalityTester {
  async testConsistency(agentId, scenarios) {
    const results = [];
    
    for (const scenario of scenarios) {
      const response = await this.runScenario(agentId, scenario);
      const analysis = await this.analyzeResponse(response, scenario.expected_attributes);
      
      results.push({
        scenario: scenario.name,
        consistency_score: analysis.consistency,
        attribute_alignment: analysis.alignment,
        deviations: analysis.deviations
      });
    }
    
    return {
      overall_consistency: this.calculateOverallConsistency(results),
      recommendations: this.generateRecommendations(results)
    };
  }
  
  async runScenario(agentId, scenario) {
    return client.agents.test({
      agent_id: agentId,
      input: scenario.input,
      context: scenario.context,
      expected_attributes: scenario.expected_attributes
    });
  }
  
  analyzeResponse(response, expectedAttributes) {
    const analysis = {
      consistency: 0,
      alignment: {},
      deviations: []
    };
    
    // Check each expected attribute
    for (const [attr, expected] of Object.entries(expectedAttributes)) {
      const actual = this.measureAttribute(response, attr);
      const deviation = Math.abs(actual - expected);
      
      analysis.alignment[attr] = {
        expected,
        actual,
        deviation
      };
      
      if (deviation > 20) {
        analysis.deviations.push({
          attribute: attr,
          severity: 'high',
          recommendation: `Adjust ${attr} baseline or add conditional logic`
        });
      }
    }
    
    analysis.consistency = 100 - (analysis.deviations.length * 10);
    return analysis;
  }
}

A/B Testing Personalities

class PersonalityABTest {
  async runTest(agentId, variantA, variantB, duration) {
    const test = await client.experiments.create({
      type: 'personality_test',
      agent_id: agentId,
      variants: {
        control: variantA,
        treatment: variantB
      },
      metrics: ['satisfaction_score', 'resolution_time', 'escalation_rate'],
      duration,
      traffic_split: 50
    });
    
    // Monitor results
    const monitor = setInterval(async () => {
      const results = await client.experiments.getResults(test.id);
      
      if (results.significant) {
        await this.applyWinner(agentId, results.winner);
        clearInterval(monitor);
      }
    }, 3600000); // Check hourly
    
    return test;
  }
  
  async applyWinner(agentId, winningVariant) {
    await client.attributes.bulkUpdate({
      agent_id: agentId,
      attributes: winningVariant.attributes,
      source: 'ab_test_winner'
    });
  }
}

Best Practices

1. Attribute Hierarchies

// Good: Clear hierarchy and relationships
const attributeHierarchy = {
  communication: {
    parent: null,
    children: ['tone', 'formality', 'verbosity'],
    weight: 1.0
  },
  tone: {
    parent: 'communication',
    children: ['friendliness', 'professionalism', 'empathy'],
    weight: 0.8
  },
  friendliness: {
    parent: 'tone',
    children: ['emoji_usage', 'casual_language'],
    weight: 0.6,
    constraints: {
      max_if: { formality: '> 80', value: 30 }
    }
  }
};

// Bad: Conflicting flat attributes
const flatAttributes = {
  friendly: 100,
  formal: 100, // Conflicts with friendly
  professional: 0 // Conflicts with formal
};

2. Context-Aware Defaults

// Good: Dynamic defaults based on context
const contextAwareDefaults = {
  getDefaultAttributes(context) {
    const defaults = { ...this.baseDefaults };
    
    // Time-based adjustments
    const hour = new Date().getHours();
    if (hour < 9 || hour > 17) {
      defaults.formality -= 10;
      defaults.brevity += 20;
    }
    
    // Channel-based adjustments
    if (context.channel === 'sms') {
      defaults.verbosity = 'concise';
      defaults.emoji_usage = 0;
    } else if (context.channel === 'chat') {
      defaults.response_speed = 'quick';
      defaults.emoji_usage = 40;
    }
    
    return defaults;
  }
};

3. Attribute Validation

class AttributeValidator {
  validateAttributes(attributes) {
    const errors = [];
    
    // Check for conflicts
    if (attributes.friendliness > 80 && attributes.formality > 80) {
      errors.push({
        type: 'conflict',
        message: 'High friendliness conflicts with high formality',
        suggestion: 'Consider professional_warmth instead'
      });
    }
    
    // Check for missing required attributes
    const required = ['empathy', 'clarity', 'helpfulness'];
    for (const req of required) {
      if (!(req in attributes)) {
        errors.push({
          type: 'missing',
          attribute: req,
          message: `Required attribute ${req} is missing`
        });
      }
    }
    
    // Check value ranges
    for (const [attr, value] of Object.entries(attributes)) {
      if (typeof value === 'number' && (value < 0 || value > 100)) {
        errors.push({
          type: 'range',
          attribute: attr,
          message: `${attr} value ${value} is out of range [0-100]`
        });
      }
    }
    
    return errors;
  }
}

Monitoring and Analytics

Attribute Performance Tracking

async function trackAttributePerformance(agentId) {
  const metrics = await client.attributes.getPerformanceMetrics({
    agent_id: agentId,
    timeframe: '30d',
    group_by: 'attribute'
  });
  
  const insights = {
    high_impact: metrics.filter(m => m.correlation_with_satisfaction > 0.7),
    low_impact: metrics.filter(m => m.correlation_with_satisfaction < 0.3),
    optimal_ranges: {},
    recommendations: []
  };
  
  // Find optimal ranges
  for (const metric of metrics) {
    const optimal = metric.satisfaction_by_value.reduce((best, current) => 
      current.satisfaction > best.satisfaction ? current : best
    );
    
    insights.optimal_ranges[metric.attribute] = {
      range: optimal.value_range,
      satisfaction: optimal.satisfaction
    };
  }
  
  return insights;
}

Next Steps


Pro Tip: Start with a base personality and use conditional attributes to adapt to specific situations. This provides consistency while allowing flexibility.

For personality examples and templates, visit our GitHub repository or contact support@stateset.com.