Introduction
Agent Rules are the decision-making engine of your StateSet agents. They enable sophisticated, context-aware behaviors that adapt to customer needs, business policies, and real-time conditions. This guide will show you how to create rules that make your agents truly intelligent.
What are Agent Rules?
Rules define how your agents respond to specific situations. They work on an “if-then” basis but can incorporate complex logic, multiple conditions, and sophisticated actions. Think of rules as your agent’s decision tree—guiding every interaction toward the best possible outcome.
How Rules Work
Why Rules Matter
Consistent Responses Ensure every customer gets the right answer, every time
Business Logic Embed your policies and procedures directly into agent behavior
Dynamic Adaptation Adjust responses based on context, customer history, and real-time data
Getting Started
Prerequisites
StateSet account with API access
At least one agent created
Understanding of your business rules and policies
Installation
npm install stateset-node
Creating Rules
Basic Rule Structure
Every rule consists of:
Name : Unique identifier
Conditions : When the rule should trigger
Actions : What should happen
Priority : Order of execution
Scope : Where the rule applies
Simple Rule Example
Let’s start with a basic rule for handling refund inquiries:
import { StateSetClient } from 'stateset-node' ;
const client = new StateSetClient ({
apiKey: process . env . STATESET_API_KEY
});
async function createRefundRule ( agentId ) {
const rule = await client . rules . create ({
agent_id: agentId ,
name: 'refund_inquiry_handler' ,
description: 'Handles customer refund inquiries with appropriate care' ,
priority: 100 , // Higher priority executes first
conditions: {
any: [
{ field: 'message.text' , operator: 'contains' , value: 'refund' },
{ field: 'message.text' , operator: 'contains' , value: 'money back' },
{ field: 'message.text' , operator: 'matches' , value: '/return.*money/i' }
]
},
actions: [
{
type: 'set_attribute' ,
attribute: 'conversation_tone' ,
value: 'empathetic_professional'
},
{
type: 'add_context' ,
context: {
topic: 'refund' ,
sensitivity: 'high' ,
require_order_lookup: true
}
},
{
type: 'send_message' ,
message: 'I understand you have questions about a refund. I \' d be happy to help you with that. Could you please provide your order number?'
}
],
metadata: {
category: 'customer_service' ,
compliance: 'required' ,
last_reviewed: new Date (). toISOString ()
}
});
return rule ;
}
Complex Rule with Multiple Conditions
Here’s a more sophisticated rule that considers customer history and order value:
async function createVIPCustomerRule ( agentId ) {
const vipRule = await client . rules . create ({
agent_id: agentId ,
name: 'vip_customer_treatment' ,
description: 'Provides premium service to VIP customers' ,
priority: 200 , // Executes before standard rules
conditions: {
all: [
{
any: [
{ field: 'customer.lifetime_value' , operator: 'greater_than' , value: 5000 },
{ field: 'customer.tier' , operator: 'equals' , value: 'platinum' },
{ field: 'customer.orders_count' , operator: 'greater_than' , value: 50 }
]
},
{
field: 'conversation.sentiment' ,
operator: 'in' ,
value: [ 'negative' , 'very_negative' ]
}
]
},
actions: [
{
type: 'escalate' ,
target: 'vip_support_team' ,
priority: 'immediate'
},
{
type: 'set_attribute' ,
attribute: 'service_level' ,
value: 'white_glove'
},
{
type: 'apply_discount' ,
discount_type: 'percentage' ,
value: 10 ,
code: 'VIP_CARE'
},
{
type: 'send_message' ,
message: 'I sincerely apologize for any inconvenience. As one of our valued customers, I \' m immediately escalating this to our VIP support team who will assist you right away.'
},
{
type: 'log_event' ,
event: 'vip_escalation' ,
data: {
customer_id: '{{customer.id}}' ,
reason: 'negative_sentiment' ,
automated: true
}
}
]
});
return vipRule ;
}
Advanced Rule Patterns
Time-Based Rules
Create rules that adapt based on time of day, business hours, or dates:
const afterHoursRule = await client . rules . create ({
agent_id: agentId ,
name: 'after_hours_support' ,
conditions: {
any: [
{
field: 'current_time' ,
operator: 'outside_range' ,
value: { start: '09:00' , end: '17:00' , timezone: 'America/New_York' }
},
{
field: 'current_day' ,
operator: 'in' ,
value: [ 'Saturday' , 'Sunday' ]
},
{
field: 'current_date' ,
operator: 'in' ,
value: [ '2024-12-25' , '2024-01-01' ] // Holidays
}
]
},
actions: [
{
type: 'set_expectation' ,
message: 'Thanks for reaching out! Our team is currently offline, but I can still help with many requests.'
},
{
type: 'limit_functions' ,
allowed: [ 'order_status' , 'track_package' , 'faq_lookup' ],
message_on_restricted: 'For this request, our human team will need to assist you. They \' ll respond within one business day.'
}
]
});
Dynamic Routing Rules
Route conversations based on content and context:
const routingRule = await client . rules . create ({
agent_id: agentId ,
name: 'intelligent_routing' ,
priority: 300 ,
conditions: {
evaluate: 'routing_logic'
},
routing_logic: `
// Technical issues go to tech support
if (message.text.match(/error|bug|crash|not working/i)) {
return 'technical_support';
}
// Billing issues to finance team
if (message.text.match(/charge|bill|payment|invoice/i)) {
return 'billing_team';
}
// Sales inquiries to sales team
if (message.text.match(/pricing|discount|upgrade|plan/i) && !customer.is_existing) {
return 'sales_team';
}
// VIP customers always get premium support
if (customer.tier === 'vip' || customer.lifetime_value > 10000) {
return 'vip_support';
}
// Default to general support
return 'general_support';
` ,
actions: [
{
type: 'route_to_team' ,
team: '{{routing_result}}' ,
transfer_context: true ,
message: 'I \' m connecting you with our {{routing_result.friendly_name}} team who can best assist with your request.'
}
]
});
Compliance and Security Rules
Ensure sensitive data is handled appropriately:
const complianceRule = await client . rules . create ({
agent_id: agentId ,
name: 'pii_protection' ,
priority: 500 , // Highest priority
conditions: {
any: [
{
field: 'message.text' ,
operator: 'matches' ,
value: '/ \\ b \\ d{3}- \\ d{2}- \\ d{4} \\ b/' // SSN pattern
},
{
field: 'message.text' ,
operator: 'matches' ,
value: '/ \\ b(?: \\ d{4}[ \\ s-]?){3} \\ d{4} \\ b/' // Credit card pattern
}
]
},
actions: [
{
type: 'mask_sensitive_data' ,
patterns: [ 'ssn' , 'credit_card' ],
replacement: '[REDACTED]'
},
{
type: 'send_message' ,
message: 'For your security, please don \' t share sensitive information like SSN or credit card numbers in chat. I can help you without this information.'
},
{
type: 'log_security_event' ,
event_type: 'pii_attempted' ,
severity: 'medium'
}
]
});
Rule Conditions
Condition Operators
StateSet supports a comprehensive set of operators:
// Comparison operators
{ field : 'order.total' , operator : 'greater_than' , value : 100 }
{ field : 'customer.age' , operator : 'between' , value : { min : 18 , max : 65 } }
// String operators
{ field : 'message.text' , operator : 'contains' , value : 'urgent' }
{ field : 'customer.email' , operator : 'ends_with' , value : '@company.com' }
{ field : 'product.sku' , operator : 'matches' , value : '/^PROD- \\ d{6}$/' }
// Array operators
{ field : 'customer.tags' , operator : 'includes' , value : 'vip' }
{ field : 'order.items' , operator : 'includes_any' , value : [ 'electronics' , 'computers' ] }
// Date operators
{ field : 'customer.created_at' , operator : 'before' , value : '2024-01-01' }
{ field : 'order.date' , operator : 'within_last' , value : { amount : 30 , unit : 'days' } }
// Null checks
{ field : 'customer.phone' , operator : 'is_null' , value : true }
{ field : 'order.discount_code' , operator : 'is_not_null' , value : true }
Complex Condition Logic
Combine conditions with AND/OR logic:
const complexRule = await client . rules . create ({
conditions: {
all: [ // AND logic
{
any: [ // OR logic
{ field: 'customer.status' , operator: 'equals' , value: 'gold' },
{ field: 'customer.lifetime_value' , operator: 'greater_than' , value: 1000 }
]
},
{
field: 'current_promotion.active' ,
operator: 'equals' ,
value: true
},
{
not: { // NOT logic
field: 'customer.flags' ,
operator: 'includes' ,
value: 'promotional_opt_out'
}
}
]
}
});
Rule Actions
Available Action Types
// Conversation Control
{ type : 'set_attribute' , attribute : 'tone' , value : 'formal' }
{ type : 'add_tag' , tag : 'urgent_issue' }
{ type : 'set_priority' , level : 'high' }
// Message Actions
{ type : 'send_message' , message : 'Your custom message here' }
{ type : 'send_template' , template_id : 'welcome_back_vip' }
{ type : 'suggest_responses' , options : [ 'Yes' , 'No' , 'Tell me more' ] }
// Function Execution
{ type : 'execute_function' , function : ' check_inventory ', params : { sku : '{{product.sku}}' } }
{ type : 'disable_function' , function : ' process_payment ', reason : ' after_hours ' }
// Routing and Escalation
{ type : 'route_to_team' , team : 'technical_support' }
{ type : 'escalate_to_human' , priority : 'immediate' , reason : '{{escalation_reason}}' }
// Data Operations
{ type : 'update_customer' , fields : { last_contact : '{{current_timestamp}}' } }
{ type : 'create_ticket' , priority : 'medium' , category : 'billing' }
{ type : 'log_event' , event : 'rule_triggered' , data : { rule_id : '{{rule.id}}' } }
Action Sequencing
Control the flow of actions:
const sequencedRule = await client . rules . create ({
actions: [
{
type: 'execute_function' ,
function: 'check_order_status' ,
store_result: 'order_status'
},
{
type: 'conditional_action' ,
condition: 'order_status.status === "shipped"' ,
then: {
type: 'send_message' ,
message: 'Great news! Your order has shipped and is on its way.'
},
else: {
type: 'send_message' ,
message: 'Your order is being prepared and will ship soon.'
}
}
]
});
Testing Rules
Rule Testing Framework
async function testRule ( ruleId , testCases ) {
const results = await client . rules . test ({
rule_id: ruleId ,
test_cases: testCases
});
results . forEach ( result => {
console . log ( `Test Case: ${ result . name } ` );
console . log ( `Expected: ${ result . expected } ` );
console . log ( `Actual: ${ result . actual } ` );
console . log ( `Passed: ${ result . passed } ` );
});
return results ;
}
// Define test cases
const testCases = [
{
name: 'VIP customer with complaint' ,
input: {
message: { text: 'This service is terrible!' },
customer: { tier: 'vip' , lifetime_value: 15000 },
conversation: { sentiment: 'very_negative' }
},
expected_actions: [ 'escalate' , 'apply_discount' ]
},
{
name: 'Regular customer inquiry' ,
input: {
message: { text: 'What are your business hours?' },
customer: { tier: 'standard' },
conversation: { sentiment: 'neutral' }
},
expected_actions: [ 'send_message' ]
}
];
await testRule ( vipRule . id , testCases );
Rule Management
Rule Versioning
Keep track of rule changes:
const ruleWithVersion = await client . rules . create ({
agent_id: agentId ,
name: 'return_policy_v2' ,
version: '2.0.0' ,
changelog: 'Updated return window from 30 to 60 days' ,
replaces: 'rule_abc123' , // ID of previous version
effective_date: '2024-02-01' ,
actions: [
{
type: 'send_message' ,
message: 'Our return policy allows returns within 60 days of purchase.'
}
]
});
Bulk Rule Operations
Manage multiple rules efficiently:
// Import rules from configuration
async function importRules ( agentId , rulesConfig ) {
const imported = await client . rules . bulkCreate ({
agent_id: agentId ,
rules: rulesConfig ,
conflict_resolution: 'skip' , // or 'overwrite'
validate_before_import: true
});
console . log ( `Imported ${ imported . success . length } rules` );
if ( imported . failures . length > 0 ) {
console . error ( 'Failed imports:' , imported . failures );
}
}
// Export rules for backup
async function exportRules ( agentId ) {
const rules = await client . rules . export ({
agent_id: agentId ,
format: 'json' ,
include_disabled: false
});
// Save to file or version control
fs . writeFileSync ( 'rules-backup.json' , JSON . stringify ( rules , null , 2 ));
}
Monitoring & Analytics
// Get rule analytics
const analytics = await client . rules . getAnalytics ({
rule_id: ruleId ,
timeframe: '30d' ,
metrics: [ 'trigger_count' , 'success_rate' , 'avg_execution_time' ]
});
console . log ( `Rule Performance:
Triggered: ${ analytics . trigger_count } times
Success Rate: ${ analytics . success_rate } %
Avg Execution: ${ analytics . avg_execution_time } ms
Most Common Trigger: ${ analytics . top_trigger_condition }
` );
// Set up alerts
await client . rules . createAlert ({
rule_id: ruleId ,
alert_conditions: [
{
metric: 'error_rate' ,
threshold: 5 ,
window: '1h' ,
notification: 'email'
}
]
});
Best Practices
1. Rule Priority and Order
// Good: Clear priority hierarchy
const rules = [
{ name: 'security_check' , priority: 1000 }, // Always first
{ name: 'compliance_filter' , priority: 900 }, // Before business logic
{ name: 'vip_treatment' , priority: 500 }, // Special handling
{ name: 'standard_routing' , priority: 100 }, // Normal flow
{ name: 'fallback_handler' , priority: 1 } // Catch-all
];
// Optimize condition checking
const efficientRule = await client . rules . create ({
conditions: {
// Check simple conditions first
all: [
{ field: 'message.length' , operator: 'less_than' , value: 10 }, // Fast
{ field: 'customer.tier' , operator: 'equals' , value: 'vip' }, // Fast
{ field: 'message.text' , operator: 'matches' , value: '/complex.*regex/i' } // Slower
]
},
// Cache results for repeated checks
cache_ttl: 300 // 5 minutes
});
3. Error Handling
const robustRule = await client . rules . create ({
error_handling: {
on_condition_error: 'skip_rule' ,
on_action_error: 'continue_next_action' ,
fallback_message: 'I encountered an issue, but I \' m still here to help!' ,
log_errors: true
}
});
Common Patterns
Customer Segmentation Rules
const segmentationRules = [
{
name: 'new_customer_welcome' ,
conditions: { field: 'customer.orders_count' , operator: 'equals' , value: 0 },
actions: [{ type: 'send_template' , template: 'first_time_buyer_welcome' }]
},
{
name: 'loyal_customer_perks' ,
conditions: { field: 'customer.orders_count' , operator: 'greater_than' , value: 10 },
actions: [{ type: 'apply_loyalty_discount' , percentage: 15 }]
},
{
name: 'win_back_inactive' ,
conditions: { field: 'customer.last_order_date' , operator: 'before' , value: '90_days_ago' },
actions: [{ type: 'send_template' , template: 'we_miss_you_offer' }]
}
];
Contextual Help Rules
const contextualHelpRule = await client . rules . create ({
name: 'smart_help_suggestions' ,
conditions: {
evaluate: `
const keywords = message.text.toLowerCase();
const page = context.current_page;
if (page === 'checkout' && keywords.includes('coupon')) {
return 'show_coupon_help';
} else if (page === 'product' && keywords.includes('size')) {
return 'show_size_guide';
} else if (keywords.includes('ship')) {
return 'show_shipping_info';
}
return null;
`
},
actions: [
{
type: 'dynamic_action' ,
action: '{{evaluation_result}}'
}
]
});
Troubleshooting
Common Issues
Rules Not Triggering
Check rule priority and order
Verify conditions are correctly formatted
Ensure rule is enabled and not expired
Conflicting Rules
Use priority levels to control execution order
Implement exclusive rule groups
Add conflict detection in conditions
Performance Issues
Optimize complex regex patterns
Use caching for expensive operations
Limit the number of active rules
Next Steps
Pro Tip : Start with simple rules and gradually add complexity. Use the testing framework to validate rules before deploying to production.
For support and examples, visit our GitHub repository or contact support@stateset.com .