lenzcom's picture
Upload folder using huggingface_hub
e706de2 verified
/**
* 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
*/