const Anthropic = require('@anthropic-ai/sdk'); const { anthropicApiKey } = require('../config'); if (!anthropicApiKey) { console.warn('[taskClassifier] ANTHROPIC_API_KEY is not set — classification calls will fail. Running in degraded mode.'); } const client = new Anthropic({ apiKey: anthropicApiKey }); const CLAUDE_MODEL = 'claude-sonnet-4-20250514'; const VALID_TASK_TYPES = ['learn_skill', 'troubleshoot', 'follow_up', 'accessibility', 'unknown']; const VALID_URGENCY = ['low', 'medium', 'high']; async function classifyMessage(text, userProfile) { const profileSummary = userProfile ? [ `Name: ${userProfile.name || 'unknown'}`, `OS: ${userProfile.os_type || 'unknown'}`, `Vocabulary level: ${userProfile.vocabulary_level || 'basic'}`, `Comfort level: ${userProfile.comfort_level !== undefined ? userProfile.comfort_level : 1}/5`, ].join(', ') : 'No profile available'; const systemPrompt = `You are a classifier for PC Pal, an AI tutor that helps elderly users with their computers. Classify the user's message into one of these task types: - learn_skill: wants to learn something new - troubleshoot: has a problem to fix - follow_up: following up on a previous step - accessibility: requesting accessibility help - unknown: doesn't fit any category Respond with ONLY a JSON object, no markdown, no explanation: {"taskType": "", "topic": "", "urgency": ""} Urgency: high = safety/critical failure, medium = frustrating problem, low = general question`; const userMessage = `User profile: ${profileSummary}\nUser message: "${text}"\nClassify this message.`; try { const response = await client.messages.create({ model: CLAUDE_MODEL, max_tokens: 200, system: systemPrompt, messages: [{ role: 'user', content: userMessage }], }); const rawText = response.content[0]?.text?.trim() || ''; const jsonText = rawText.replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/, '').trim(); let parsed; try { parsed = JSON.parse(jsonText); } catch (parseErr) { console.error('[taskClassifier] Failed to parse Claude response:', rawText); return { taskType: 'unknown', topic: 'unclassified', urgency: 'low' }; } const taskType = VALID_TASK_TYPES.includes(parsed.taskType) ? parsed.taskType : 'unknown'; const topic = typeof parsed.topic === 'string' ? parsed.topic.slice(0, 100) : 'unclassified'; const urgency = VALID_URGENCY.includes(parsed.urgency) ? parsed.urgency : 'low'; return { taskType, topic, urgency }; } catch (err) { console.error('[taskClassifier] Claude API error:', err.message); return { taskType: 'unknown', topic: 'unclassified', urgency: 'low' }; } } module.exports = { classifyMessage };