File size: 7,541 Bytes
e706de2 | 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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | /**
* Exercise 6: Build a Conversation Validator
*
* Goal: Validate conversation structure and message sequences
*
* Requirements:
* - Check if conversation follows proper patterns
* - Validate message ordering
* - Ensure tool messages link to AI tool calls
* - Check for required message types
* - Return detailed validation errors
*
* Validation Rules:
* 1. First message should be a SystemMessage (recommended)
* 2. Tool messages must follow AI messages with tool calls
* 3. No empty message content
* 4. Human and AI messages should alternate (after system)
* 5. Tool messages must have valid toolCallId
*/
import { HumanMessage, AIMessage, SystemMessage, ToolMessage } from '../../../../src/index.js';
/**
* TODO: Implement validateMessage
*
* Validates a single message
*
* @param {BaseMessage} message - The message to validate
* @returns {Object} { valid: boolean, errors: string[] }
*/
function validateMessage(message) {
const errors = [];
// TODO: Check if message content is not empty
if (message.content !== '') {
throw Error('Empty')
}
// TODO: Check if message has a type
if (!Object.hasOwn(message, 'type')) {
throw Error('No type')
}
// TODO: For tool messages, check toolCallId exists
// TODO: For AI messages, validate tool calls structure
return {
valid: errors.length === 0,
errors
};
}
/**
* TODO: Implement validateConversation
*
* Validates an entire conversation structure
*
* @param {Array<BaseMessage>} messages - The conversation to validate
* @returns {Object} { valid: boolean, errors: string[], warnings: string[] }
*/
function validateConversation(messages) {
const errors = [];
const warnings = [];
// TODO: Check if conversation is empty
// TODO: Warn if first message is not system message
// TODO: Validate each message individually
// TODO: Check message ordering (alternating human/AI)
// TODO: Validate tool message follows AI message with tool calls
// TODO: Check for tool call ID matches
return {
valid: errors.length === 0,
errors,
warnings
};
}
/**
* TODO: Implement validateToolCallSequence
*
* Validates that tool messages correctly reference AI tool calls
*
* @param {Array<BaseMessage>} messages - Messages to check
* @returns {Object} Validation result
*/
function validateToolCallSequence(messages) {
// TODO: Find all AI messages with tool calls
// TODO: Find all tool messages
// TODO: Check that every tool message references a valid tool call
// TODO: Check that all tool calls have corresponding tool messages
}
// ============================================================================
// Tests
// ============================================================================
async function runTests() {
console.log('π§ͺ Testing Conversation Validator...\n');
try {
// Test 1: Valid simple conversation
console.log('Test 1: Valid simple conversation');
const validConv = [
new SystemMessage("You are helpful"),
new HumanMessage("Hi"),
new AIMessage("Hello!")
];
const result1 = validateConversation(validConv);
console.log(` Valid: ${result1.valid}`);
console.log(` Errors: ${result1.errors.length}`);
console.log(` Warnings: ${result1.warnings.length}`);
console.assert(result1.valid === true, 'Should be valid');
console.log('β
Valid conversation passes\n');
// Test 2: Missing system message (warning)
console.log('Test 2: Missing system message');
const noSystem = [
new HumanMessage("Hi"),
new AIMessage("Hello!")
];
const result2 = validateConversation(noSystem);
console.log(` Valid: ${result2.valid}`);
console.log(` Warnings: ${result2.warnings}`);
console.assert(result2.warnings.length > 0, 'Should have warning');
console.log('β
Missing system message triggers warning\n');
// Test 3: Empty message content (error)
console.log('Test 3: Empty message content');
const emptyContent = [
new SystemMessage(""),
new HumanMessage("Hi")
];
const result3 = validateConversation(emptyContent);
console.log(` Valid: ${result3.valid}`);
console.log(` Errors: ${result3.errors}`);
console.assert(result3.valid === false, 'Should be invalid');
console.log('β
Empty content caught\n');
// Test 4: Tool message without AI tool call (error)
console.log('Test 4: Tool message without preceding AI tool call');
const badToolSequence = [
new SystemMessage("You are helpful"),
new HumanMessage("Calculate 2+2"),
new ToolMessage("4", "call_123") // No AI tool call before this
];
const result4 = validateConversation(badToolSequence);
console.log(` Valid: ${result4.valid}`);
console.log(` Errors: ${result4.errors}`);
console.assert(result4.valid === false, 'Should be invalid');
console.log('β
Invalid tool sequence caught\n');
// Test 5: Valid tool call sequence
console.log('Test 5: Valid tool call sequence');
const validToolSeq = [
new SystemMessage("You are helpful"),
new HumanMessage("Calculate 2+2"),
new AIMessage("Let me calculate", {
toolCalls: [{
id: 'call_123',
type: 'function',
function: { name: 'calculator', arguments: '{"a":2,"b":2}' }
}]
}),
new ToolMessage("4", "call_123"),
new AIMessage("The answer is 4")
];
const result5 = validateConversation(validToolSeq);
console.log(` Valid: ${result5.valid}`);
console.log(` Errors: ${result5.errors.length}`);
console.assert(result5.valid === true, 'Should be valid');
console.log('β
Valid tool sequence passes\n');
// Test 6: Single message validation
console.log('Test 6: Single message validation');
const goodMsg = new HumanMessage("Hello");
const result6a = validateMessage(goodMsg);
console.assert(result6a.valid === true, 'Valid message should pass');
const badMsg = new HumanMessage("");
const result6b = validateMessage(badMsg);
console.assert(result6b.valid === false, 'Empty message should fail');
console.log('β
Single message validation works\n');
// Test 7: Empty conversation
console.log('Test 7: Empty conversation');
const result7 = validateConversation([]);
console.log(` Valid: ${result7.valid}`);
console.assert(result7.valid === false, 'Empty conversation should be invalid');
console.log('β
Empty conversation caught\n');
console.log('π All tests passed!');
} catch (error) {
console.error('β Test failed:', error.message);
console.error(error.stack);
}
}
// Run tests
if (import.meta.url === `file://${process.argv[1]}`) {
runTests();
}
export { validateMessage, validateConversation, validateToolCallSequence }; |