Four tools in one registry
Before the model can use a tool, it needs a description of the tool and a schema for its input. A registry keeps both next to the code that runs the tool, and each provider maps the schema into its own API format.
Study first
- Learn how tool use looks on each API. On Anthropic, read about
toolswithinput_schemaand thetool_useandtool_resultblocks in the tool use overview. On OpenAI, read about function tools and thefunction_callandfunction_call_outputitems in the function calling guide. - Learn Zod 4's
z.toJSONSchema(JSON Schema in Zod), which turns an input schema into the JSON Schema both APIs accept.
Build
- Write
src/lib/tools.tswith aTooltype (name,description,inputschema,run) and atool()helper that typesrun's input from the schema. The tool loop in the next part parses the input before any tool runs. - Register 4 tools,
calculator,read_urlandsave_note, plusweb_searchwhen a Brave Search key is configured. - Give each implementation its own module and its own test.
calculator.tsis a recursive-descent parser for+ - * / % ^and parentheses, which means one function per precedence level, each calling the next.web.tsholdsreadPageandsearchWeb. - Write
notes.ts, which keeps anotestable through the Day 5 query function, and append itscreate tableto the schema list from Day 5. The curriculum'ssave_notewrites a JSON file, but WorkBot already has a database, so the notes go there. - Write descriptions that say when to call each tool, not only what it does, because the model chooses tools from these words. The calculator's description says to call it for any calculation.
Done when
pnpm testcovers the calculator's precedence and errors, the page reader's refusals and byte cap, and the shape of the search request.
Technical notes
readPagerefuses the private address ranges, the shared range 100.64.0.0/10 and link-local 169.254.0.0/16, where cloud metadata services answer. It also refuseslocalhostand.internalnames, and any scheme but http and https.readPagefollows redirects by hand, so it checks every hop, and it reads at most 512 KB of a body.- The text extractor drops scripts, styles and tags but keeps block boundaries as line breaks, and it caps the result at 8,000 characters per page.
- The registry holds
web_searchonly whenBRAVE_SEARCH_KEYis set. - The calculator refuses anything it cannot tokenise, and any non-finite result such as
1 / 0. - No tool today changes anything outside WorkBot. When one does, on Day 27, a confirmation step goes between the model's call and the run.

