interface Intent {
category: 'faq' | 'account' | 'technical' | 'billing' | 'complaint' | 'other';
confidence: number;
entities: Entity[];
sentiment: 'positive' | 'neutral' | 'negative' | 'frustrated';
urgency: 'low' | 'medium' | 'high';
}
interface Entity {
type: 'order_id' | 'product' | 'feature' | 'date' | 'amount' | 'email';
value: string;
confidence: number;
}
export default class InquiryClassifier extends AgenticSystem {
@field categories: CategoryDefinition[] = [
{
name: 'faq',
description: 'General questions about products, features, or policies',
examples: ['How do I reset my password?', 'What are your business hours?', 'Do you ship internationally?']
},
{
name: 'account',
description: 'Questions about user accounts, profiles, or settings',
examples: ['I need to update my email', 'How do I delete my account?', 'My account was locked']
},
{
name: 'technical',
description: 'Technical issues, bugs, or troubleshooting',
examples: ['The app keeps crashing', 'I get an error when I try to save', 'The sync is not working']
},
{
name: 'billing',
description: 'Payment, subscription, refund, or pricing questions',
examples: ['I was charged twice', 'How do I cancel my subscription?', 'Can I get a refund?']
},
{
name: 'complaint',
description: 'Expressions of dissatisfaction or frustration',
examples: ['This is unacceptable', 'I want to speak to a manager', 'Your service is terrible']
}
];
async classify(inquiry: string, customerContext?: CustomerContext): Promise<Intent> {
// Extract entities first
const entities = await this.extractEntities(inquiry);
// Classify with context
const contextInfo = customerContext
? `Customer has been with us ${customerContext.tenureDays} days, has ${customerContext.openTickets} open tickets, last contacted ${customerContext.daysSinceLastContact} days ago.`
: '';
const completion = await llm.complete([
{ role: 'system', content: `Classify this customer inquiry.
Categories: ${this.categories.map(c => `${c.name}: ${c.description}`).join('\n')}
Return JSON only with no additional text:
{
"category": "...",
"confidence": 0.0-1.0,
"sentiment": "positive|neutral|negative|frustrated",
"urgency": "low|medium|high",
"reasoning": "..."
}` },
{ role: 'user', content: `Inquiry: ${inquiry}\n\n${contextInfo}` }
]);
const raw = completion.choices[0].message.content;
const classification = JSON.parse(raw);
return {
category: classification.category,
confidence: classification.confidence,
entities,
sentiment: classification.sentiment,
urgency: classification.urgency
};
}
private async extractEntities(inquiry: string): Promise<Entity[]> {
const completion = await llm.complete([
{ role: 'system', content: `Extract entities from this customer inquiry.
Entity types: order_id, product, feature, date, amount, email
Return a JSON array only with no additional text, for example:
[
{"type": "order_id", "value": "123-456", "confidence": 0.92}
]` },
{ role: 'user', content: inquiry }
]);
const raw = completion.choices[0].message.content;
return JSON.parse(raw);
}
// Route based on classification
routeToHandler(intent: Intent): string {
// Complaints always get special handling
if (intent.category === 'complaint' || intent.sentiment === 'frustrated') {
return 'complaint';
}
// High urgency gets escalated faster
if (intent.urgency === 'high' && intent.confidence < 0.8) {
return 'escalation';
}
// Route by category
return intent.category;
}
}
interface CategoryDefinition {
name: string;
description: string;
examples: string[];
}
interface CustomerContext {
customerId: string;
tenureDays: number;
openTickets: number;
daysSinceLastContact: number;
previousCategories: string[];
}