Skip to content

f4: Tools

Up to now TripMate answered from what the model already knows. For “what greeting should I use right now?” it will guess: generic hola, or buenos días with no tie to your clock.

A tool closes that gap. The model calls your function when it needs a fact it cannot know on its own; the return value flows back into the answer.

This challenge adds one tool: read the real time from the machine running the script. “Right now” is your desk clock, not a timezone table in the repo.

In a hurry? These three steps are the whole challenge. Everything below is the why and the how.

  1. Run npm run f4. No [tool fired] getUserTime line; the greeting is not tied to your clock.
  2. Edit start/agent.ts: TODO 1 (getUserTime execute), TODO 2 (add getUserTime to tools).
  3. Done when getUserTime fires, the log shows your real time, and the greeting matches that hour band.
prompt  ->  model  ->  needs the clock?  ->  [ getUserTime ]  --.
   answer  <-  model  <-------- tool result -------------------'

One tool, one gap. In f2, steps was 1 with no tools. After you wire this, steps climbs when the model calls the tool and answers.

The full shape on something unrelated, server uptime, a value the model cannot know:

const getServerUptime = tool({
  description: `
Get how long this server process has been running.
`.trim(),
  inputSchema: z.object({}),
  execute: async () => {
    const uptimeSeconds = Math.round(process.uptime());
    console.log(`  [tool fired] getServerUptime() -> ${uptimeSeconds}s`);
    return { uptimeSeconds };
  },
});

TripMate’s getUserTime uses the same shape: description, inputSchema, execute. Your job is the execute body and wiring the tool into the agent.

Open start/agent.ts. getUserTime is declared but its execute throws, and the tool is not in the tools map yet.

Run it:

npm run f4

You get an answer with steps: 1. It may sound fine. Scroll up for the trace; there is no clock tool in the run.

  1. Spot the gap. Run the starter. No getUserTime in the output. The model had to guess the time of day.

  2. Write getUserTime’s execute (TODO 1). Read the current local time from the platform with new Date().toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }). Return that string so the model can pick the greeting. Log [tool fired] getUserTime() -> ... (the finish file also logs timezone for you to read).

  3. Wire the tool (TODO 2). Add getUserTime to the agent tools map. Run again. You should see the tool fire, then an answer that cites the time (buenos días / buenas tardes / buenas noches). steps should be 2.

  4. Poke. Run at a different time of day, or change the prompt (“I’m heading to France…”) and see whether the model still reaches for the clock.

  5. Check you’ve got it. You can say why the model could not know the hour without the tool, you saw getUserTime fire, and the greeting lines up with the logged time.

Stuck? finish/agent.ts after you try.

  • No [tool fired] line. getUserTime is missing from the tools map, or execute still throws.
  • Tool fires, greeting band feels off. Small models wobble on cutoffs (14:00 vs 15:00). Pass when the tool ran and the answer cites the time from the log.
  • Looking up Madrid in a table. That teaches lookup data (closer to r1). This lesson is platform clock truth that changes every run.
Why a tool instead of "reply with the right greeting" in the prompt?

The prompt can ask for buenos días or buenas tardes. It cannot tell the model what hour it is on your laptop. Only code running on your machine can read that clock.

What the model sends when it calls a tool

The model emits a structured tool call: name plus arguments as JSON. The SDK runs your execute and feeds the return value back into the loop. That round trip is why steps climbs.

Where do two tools show up?

This challenge uses one tool so the wiring stays clear. Patterns track challenges combine several tools in one run; the same loop, more calls.

Next up is f5: a cheap guardrail check runs before the agent and decides whether the request is safe and on-topic.