Welcome back! In the previous chapter, Tool Behavior Definition, we gave our AI a set of "Standing Orders" so it knows when to sleep.
Now, we need to build the machinery that actually makes the waiting happen. This brings us to the core engineering concept of this tool: Asynchronous Flow Control.
To understand why we build SleepTool this way, let's look at a kitchen analogy.
Scenario A: The Blocking Chef (Synchronous) Imagine a chef making bread. They knead the dough and need to let it rise for one hour. In a "Blocking" scenario, the chef sets the dough on the counter and stares at it for 60 minutes. They don't move. They don't clean. If a customer walks in, the chef ignores them because they are "busy waiting."
bash sleep 60. The computer freezes on that task.Scenario B: The Asynchronous Chef (Non-Blocking) The chef kneads the dough, sets a timer, and puts the dough aside. Now, while the dough rises, the chef chops vegetables, wipes the counter, or takes a new order. When the timer dings, the chef goes back to the dough.
SleepTool. The program sets a background timer and stays open to handle other requests.We want our AI to be the Asynchronous Chef.
In JavaScript (the language we are using), the tool allowing us to "do other things while waiting" is called a Promise.
Think of a Promise like a Restaurant Pager/Buzzer.
We need our tool to hand the System a "buzzer" that goes off after a specific number of seconds.
We define the logic in a file called handler.ts. This file contains the function that executes when the AI calls the tool.
First, the function needs to know how long to wait. The AI sends this as an argument.
// In handler.ts
interface SleepArgs {
seconds: number;
}
// We define a function that takes these arguments
export const sleepHandler = async ({ seconds }: SleepArgs) => {
// ... logic goes here ...
};
Explanation:
seconds (a number).seconds equals 10.
Now, we create the "Restaurant Buzzer." We use a built-in function called setTimeout.
// Inside sleepHandler ...
console.error(`Sleeping for ${seconds}s...`);
// Return a "Buzzer" (Promise) that rings after the time is up
return new Promise((resolve) => {
// Multiply by 1000 because computer time is in milliseconds
setTimeout(resolve, seconds * 1000);
});
Explanation:
new Promise: Creates the buzzer.setTimeout: This is the internal clock. It counts down in the background.resolve: This is the action of the buzzer going off. It tells the system "I'm done waiting!"Let's visualize what happens in the system when the AI decides to use this tool. Notice how the System stays "awake" to watch the timer.
Ctrl+C or sends a "Cancel" signal during this time, the System can hear it and stop the tool immediately.
Here is the complete, simplified implementation in handler.ts.
// handler.ts
// The function exported to the system
export default async function sleep({ seconds }: { seconds: number }) {
// Log so we can see it in the console
process.stderr.write(`Sleeping for ${seconds}s... `)
// The Async Magic: Wait without blocking
await new Promise(resolve => setTimeout(resolve, seconds * 1000))
// Return a success message to the AI
return `Slept for ${seconds}s`
}
Example Input/Output:
{ seconds: 3 }"Slept for 3s" to the AI.Because we used this asynchronous approach:
bash) would.
You have successfully implemented the engine of the SleepTool!
seconds and waits.However, there is a hidden risk. If the AI sleeps for a very long time (say, 30 minutes), the system might think the connection has died. We need a way to gently tap the AI on the shoulder to say, "I'm still here, just waiting."
We will solve this in the next chapter.
Next Chapter: Periodic Heartbeat Handling
Generated by Code IQ