File size: 4,491 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 |
/**
* Exercise 1: Build a Simple Logging Callback
*
* Goal: Understand the basic callback lifecycle
*
* In this exercise, you'll:
* 1. Extend BaseCallback to create a custom logger
* 2. Implement onStart, onEnd, and onError methods
* 3. Format output with emoji indicators
* 4. See how callbacks observe Runnable execution
*
* This is the foundation of observability in your framework!
*/
import {Runnable} from '../../../../src/index.js';
import {BaseCallback} from '../../../../src/utils/callbacks.js';
// TODO: Create SimpleLoggerCallback that extends BaseCallback
class SimpleLoggerCallback extends BaseCallback {
constructor(options = {}) {
super();
this.showTimestamp = options.showTimestamp ?? false;
}
// TODO: Implement onStart - log when runnable starts
// Use emoji: ▶️
// Log to console: runnable name and input
async onStart(runnable, input, config) {
// Your code here
}
// TODO: Implement onEnd - log when runnable completes
// Use emoji: ✔️
// Log to console: runnable name and output
async onEnd(runnable, output, config) {
// Your code here
}
// TODO: Implement onError - log when runnable errors
// Use emoji: ❌
// Log to console: runnable name and error message
async onError(runnable, error, config) {
// Your code here
}
}
// Test Runnables
class GreeterRunnable extends Runnable {
async _call(input, config) {
return `Hello, ${input}!`;
}
}
class UpperCaseRunnable extends Runnable {
async _call(input, config) {
if (typeof input !== 'string') {
throw new Error('Input must be a string');
}
return input.toUpperCase();
}
}
class ErrorRunnable extends Runnable {
async _call(input, config) {
throw new Error('Intentional error for testing');
}
}
// TODO: Test your callback
async function exercise1() {
console.log('=== Exercise 1: Simple Logging Callback ===\n');
// TODO: Create an instance of your SimpleLoggerCallback
const logger = null; // Replace with your code
const config = {
callbacks: [logger]
};
// Test 1: Normal execution
console.log('--- Test 1: Normal Execution ---');
const greeter = new GreeterRunnable();
// TODO: Invoke greeter with "World" and config
const result1 = null; // Replace with your code
console.log('Final result:', result1);
console.log();
// Test 2: Pipeline
console.log('--- Test 2: Pipeline ---');
const upper = new UpperCaseRunnable();
const pipeline = greeter.pipe(upper);
// TODO: Invoke pipeline with "claude" and config
const result2 = null; // Replace with your code
console.log('Final result:', result2);
console.log();
// Test 3: Error handling
console.log('--- Test 3: Error Handling ---');
const errorRunnable = new ErrorRunnable();
try {
// TODO: Invoke errorRunnable with "test" and config
// Replace with your code
} catch (error) {
console.log('Caught error (expected):', error.message);
}
console.log('\n✓ Exercise 1 complete!');
}
// Run the exercise
exercise1().catch(console.error);
/**
* Expected Output:
*
* --- Test 1: Normal Execution ---
* ▶️ Starting: GreeterRunnable
* Input: World
* ✔️ Completed: GreeterRunnable
* Output: Hello, World!
* Final result: Hello, World!
*
* --- Test 2: Pipeline ---
* ▶️ Starting: RunnableSequence
* Input: claude
* ▶️ Starting: GreeterRunnable
* Input: claude
* ✔️ Completed: GreeterRunnable
* Output: Hello, claude!
* ▶️ Starting: UpperCaseRunnable
* Input: Hello, claude!
* ✔️ Completed: UpperCaseRunnable
* Output: HELLO, CLAUDE!
* ✔️ Completed: RunnableSequence
* Output: HELLO, CLAUDE!
* Final result: HELLO, CLAUDE!
*
* --- Test 3: Error Handling ---
* ▶️ Starting: ErrorRunnable
* Input: test
* ❌ ErrorRunnable: Intentional error for testing
* Caught error (expected): Intentional error for testing
*
* Learning Points:
* 1. Callbacks see every step in execution
* 2. onStart fires before _call()
* 3. onEnd fires after successful _call()
* 4. onError fires when _call() throws error
* 5. Callbacks don't change the output - they just observe
*/ |