Tools are external functions or APIs that AI agents can invoke to perform actions or retrieve information. PromptSmith provides a type-safe, schema-driven approach to tool definition that:
Documents tools in the system prompt for the AI model
Validates parameters at runtime using Zod schemas
Infers types automatically for execution functions
Exports to AI SDKs seamlessly (Vercel AI SDK, Mastra)
Design Principle: Tools are registered with metadata only in the builder. The system prompt includes tool documentation, but execution logic runs in your application when the AI requests to use a tool.
import { z } from 'zod';const weatherTool = { name: "get_weather", // Unique identifier description: "...", // When and how to use it schema: z.object({ ... }), // Parameter structure execute: async (args) => { } // Optional: execution logic};
Explains what the tool does and when to use it. Be specific about:
Purpose: What does it return?
Use cases: When should the AI choose this tool?
Important details: Rate limits, data freshness, required permissions
Good Description
Poor Description
description: "Retrieves current weather data for a given location. " + "Use when the user asks about weather conditions, temperature, " + "or forecasts. Returns temperature, conditions, humidity, and wind speed."
Why it’s good: Specific about what it returns and when to use it.
description: "Gets weather"
Why it’s poor: Vague, doesn’t explain when to use it or what it returns.
A Zod schema defining the tool’s input parameters. This serves dual purposes:
Documentation: Introspected to generate parameter docs in the system prompt
Validation: Can validate arguments at runtime
Use .describe() on each field to provide parameter descriptions:
schema: z.object({ location: z.string().describe("City name or ZIP code"), units: z.enum(["celsius", "fahrenheit"]) .optional() .describe("Temperature units (defaults to celsius)")})
See schemas.ts:180-211 for schema parsing implementation.
// Array of stringsz.array(z.string()).describe("List of tags")// Array of objectsz.array(z.object({ id: z.string(), name: z.string()})).describe("List of users")// Array with min/max lengthz.array(z.string()) .min(1) .max(10) .describe("1-10 search keywords")
search_database: Searches the product database for matching items. Parameters: query(string,required): Search query text limit(number,optional): Maximum results to return category(enum,required): Category to search
See builder.ts:2184-2199 and builder.ts:2424-2451 for TOON generation.
builder .withTool({ name: "book_flight", description: "Book a flight", schema: z.object({ flightId: z.string(), passengers: z.array(z.object({ name: z.string(), email: z.string().email() })) }) }) .withExamples([{ user: "Book flight BA123 for John Doe ([email protected])", assistant: "I'll book that flight for you. *calls book_flight with flightId: 'BA123' and passenger details*", explanation: "Shows how to extract structured data from natural language and invoke the booking tool" }]);
See builder.ts:750-814 for examples implementation.
{ name: "search_products", description: "Search for products in the catalog. Use when user wants to find items.", schema: z.object({ query: z.string().describe("Search keywords"), category: z.string().optional().describe("Filter by category"), minPrice: z.number().optional().describe("Minimum price filter"), maxPrice: z.number().optional().describe("Maximum price filter"), limit: z.number().default(10).describe("Max results (default 10)") })}
builder .withTool({ name: "search_flights", description: "Search for available flights. Always use this before booking." }) .withTool({ name: "check_availability", description: "Check seat availability for a specific flight. Use after searching." }) .withTool({ name: "book_flight", description: "Book a flight. Only use after confirming availability and getting user confirmation." }) .withConstraint("must", "Always search flights before booking") .withConstraint("must", "Always confirm with user before finalizing bookings");