Tools
The built-in shared tools, their Zod schemas, and the needsApproval flag.
What a Tool Is
A tool is a tool() call from the Vercel AI SDK with three required fields. Input schemas are defined with Zod.
import { tool } from "ai";
import { z } from "zod";
export const myTool = tool({
description:
"What this tool does — the LLM reads this to decide when to call it",
inputSchema: z.object({
query: z.string().describe("The search query"),
}),
execute: async ({ query }) => {
// Always return an object, never throw
return { result: "..." };
},
});Every field in the Zod schema must have a .describe() string. The LLM
uses these descriptions to fill in parameters. Without them, the model guesses
— and guesses wrong.
The needsApproval Flag
Some tools are marked with needsApproval: true. When the ToolLoopAgent encounters one of these, it pauses execution and emits a tool-approval-request event instead of running the tool immediately.
The UI renders an approval UI. Once the user approves, the tool runs and the loop continues.
Currently only format_post uses this flag — the agent pauses and shows the user the generated outline before committing to writing the final post.
In the Workflow context, this same flag triggers an email to the team owner for out-of-band approval.
Factory Tools
Some tools need runtime context (team ID) and are exported as factory functions:
// Usage: buildGenerateImageTool(team.id)
export function buildGenerateImageTool(teamId: string) {
return tool({
description: "Generate an image using GPT Image",
inputSchema: z.object({
visualPrompt: z.string().describe("Detailed image description"),
}),
execute: async ({ visualPrompt }) => {
// uses teamId to namespace Supabase storage path
},
});
}Factory tools: buildGenerateImageTool(teamId), memoryTool(teamId).
Tool Reference
| Tool | File | Description | needsApproval |
|---|---|---|---|
web_search | Tavily SDK | Search the web for current information | No |
web_extract | Tavily SDK | Extract full content from a URL | No |
generate_outline | generate-outline.ts | Structure content into sections before writing | No |
format_post | format-post.ts | Write the final formatted post from an approved outline | Yes |
generate_image | generate-image.ts | Generate an image via GPT Image | No |
generate_reel_script | generate-reel-script.ts | Write a short-form video script | No |
format_reel | format-reel.ts | Finalize the reel package with caption, hashtags, scenes | No |
generate_script_outline | generate-script-outline.ts | Structure a long-form script | No |
format_script | format-script.ts | Write a full long-form script with acts and timestamps | No |
generate_thumbnail_concept | generate-thumbnail-concept.ts | Generate 3 thumbnail design concepts | No |
extract_receipt_data | extract-receipt-data.ts | OCR a receipt image into structured line items | No |
read_document | read-document.ts | Fetch and parse a PDF from a URL | No |
analyze_legal_document | analyze-legal-document.ts | Deep risk and obligation analysis of a legal document | No |
send_analysis_email | send-analysis-email.ts | Email an analysis result to a recipient | No |
memory | memory-tool.ts | Read, write, or search the team's persistent memory | No |
Tool Output Shape
Tools should always return an object, never throw. On failure:
execute: async ({ url }) => {
try {
// ...
} catch (err) {
return { error: "Failed to fetch document", details: String(err) };
}
};Returning { error: "..." } lets the agent surface the error in its response and decide whether to retry or inform the user.