Spaces:
Sleeping
Sleeping
File size: 6,747 Bytes
53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b 5647c24 53d0d6b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 'use strict';
// Mock the Anthropic SDK before any module that requires it is loaded.
let mockCreate;
jest.mock('@anthropic-ai/sdk', () => {
mockCreate = jest.fn();
return jest.fn().mockImplementation(() => ({
messages: { create: mockCreate },
}));
});
jest.mock('../config', () => ({
anthropicApiKey: 'test-key',
}));
const { classifyMessage } = require('../core/taskClassifier');
function makeResponse(jsonPayload) {
return { content: [{ text: JSON.stringify(jsonPayload) }] };
}
const SAMPLE_PROFILE = {
name: 'Alice',
os_type: 'Windows',
vocabulary_level: 'basic',
comfort_level: 2,
};
beforeEach(() => { jest.clearAllMocks(); });
describe('classifyMessage — correct task type classification', () => {
test('returns learn_skill for learning requests', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'learn_skill', topic: 'sending email', urgency: 'low' }));
const result = await classifyMessage('How do I send an email?', SAMPLE_PROFILE);
expect(result.taskType).toBe('learn_skill');
});
test('returns troubleshoot for error/problem messages', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'troubleshoot', topic: 'computer not turning on', urgency: 'high' }));
const result = await classifyMessage("My computer won't turn on.", SAMPLE_PROFILE);
expect(result.taskType).toBe('troubleshoot');
});
test('returns follow_up for "I did that" type messages', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'follow_up', topic: 'follow-up step', urgency: 'low' }));
const result = await classifyMessage('I did that, now what?', SAMPLE_PROFILE);
expect(result.taskType).toBe('follow_up');
});
test('returns accessibility for accessibility requests', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'accessibility', topic: 'text too small', urgency: 'medium' }));
const result = await classifyMessage('The text is too small for me to read.', SAMPLE_PROFILE);
expect(result.taskType).toBe('accessibility');
});
test('returns unknown for unrelated messages', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'unknown', topic: 'unrelated topic', urgency: 'low' }));
const result = await classifyMessage('What is the weather like today?', SAMPLE_PROFILE);
expect(result.taskType).toBe('unknown');
});
});
describe('classifyMessage — topic and urgency passthrough', () => {
test('returns the topic', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'learn_skill', topic: 'printing a document', urgency: 'low' }));
const result = await classifyMessage('How do I print?', SAMPLE_PROFILE);
expect(result.topic).toBe('printing a document');
});
test('returns the urgency', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'troubleshoot', topic: 'screen blank', urgency: 'high' }));
const result = await classifyMessage('My screen is blank!', SAMPLE_PROFILE);
expect(result.urgency).toBe('high');
});
});
describe('classifyMessage — error handling', () => {
test('returns fallback when API throws', async () => {
mockCreate.mockRejectedValue(new Error('Network error'));
const result = await classifyMessage('Something is wrong.', SAMPLE_PROFILE);
expect(result).toEqual({ taskType: 'unknown', topic: 'unclassified', urgency: 'low' });
});
test('returns fallback for malformed JSON', async () => {
mockCreate.mockResolvedValue({ content: [{ text: 'not json' }] });
const result = await classifyMessage('Help me.', SAMPLE_PROFILE);
expect(result).toEqual({ taskType: 'unknown', topic: 'unclassified', urgency: 'low' });
});
test('returns fallback for missing fields', async () => {
mockCreate.mockResolvedValue({ content: [{ text: '{"foo": "bar"}' }] });
const result = await classifyMessage('Help me.', SAMPLE_PROFILE);
expect(result.taskType).toBe('unknown');
});
test('returns fallback for empty content', async () => {
mockCreate.mockResolvedValue({ content: [] });
const result = await classifyMessage('Help me.', SAMPLE_PROFILE);
expect(result).toEqual({ taskType: 'unknown', topic: 'unclassified', urgency: 'low' });
});
});
describe('classifyMessage — validation', () => {
const VALID_TYPES = ['learn_skill', 'troubleshoot', 'follow_up', 'accessibility', 'unknown'];
test.each(VALID_TYPES)('accepts valid taskType "%s"', async (type) => {
mockCreate.mockResolvedValue(makeResponse({ taskType: type, topic: 'test', urgency: 'low' }));
const result = await classifyMessage('Test.', SAMPLE_PROFILE);
expect(result.taskType).toBe(type);
});
test('maps unrecognized taskType to unknown', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'invented', topic: 'test', urgency: 'low' }));
const result = await classifyMessage('Test.', SAMPLE_PROFILE);
expect(result.taskType).toBe('unknown');
});
test('maps unrecognized urgency to low', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'troubleshoot', topic: 'test', urgency: 'critical' }));
const result = await classifyMessage('Test.', SAMPLE_PROFILE);
expect(result.urgency).toBe('low');
});
});
describe('classifyMessage — null/undefined profile', () => {
test('works with null profile', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'learn_skill', topic: 'email', urgency: 'low' }));
const result = await classifyMessage('How do I send an email?', null);
expect(result.taskType).toBe('learn_skill');
});
test('works with undefined profile', async () => {
mockCreate.mockResolvedValue(makeResponse({ taskType: 'troubleshoot', topic: 'printer', urgency: 'medium' }));
const result = await classifyMessage('My printer is broken.', undefined);
expect(result.taskType).toBe('troubleshoot');
});
});
describe('classifyMessage — markdown stripping', () => {
test('handles ```json fences', async () => {
const payload = { taskType: 'troubleshoot', topic: 'wifi', urgency: 'high' };
mockCreate.mockResolvedValue({ content: [{ text: '```json\n' + JSON.stringify(payload) + '\n```' }] });
const result = await classifyMessage('WiFi dropping.', SAMPLE_PROFILE);
expect(result.taskType).toBe('troubleshoot');
});
test('handles plain ``` fences', async () => {
const payload = { taskType: 'learn_skill', topic: 'zoom', urgency: 'low' };
mockCreate.mockResolvedValue({ content: [{ text: '```\n' + JSON.stringify(payload) + '\n```' }] });
const result = await classifyMessage('How do I use Zoom?', SAMPLE_PROFILE);
expect(result.taskType).toBe('learn_skill');
});
});
|