import { tool } from "ai"; import { z } from "zod"; const CreateRecipeInputSchema = z.object({ title: z.string().min(1).max(200), description: z.string().max(2000).optional(), baseServings: z.number().int().min(1).max(100).default(4), recipeType: z.enum(["dish", "drink"]).default("dish"), difficulty: z.enum(["easy", "medium", "hard"]).optional(), prepMins: z.number().int().min(0).max(1440).optional(), cookMins: z.number().int().min(0).max(1440).optional(), ingredients: z.array(z.object({ rawName: z.string().min(1).max(200).describe("Ingredient name only, e.g. 'flour' — never combined with quantity/unit"), quantity: z.number().optional().describe("A number only, e.g. 0.25, 1.5, 2"), unit: z.string().max(50).optional().describe("e.g. 'cup', 'tbsp', 'g'"), })).min(1).max(100), steps: z.array(z.object({ instruction: z.string().min(1).max(2000), })).min(1).max(100), }); export type CreateRecipeToolInput = z.infer; /** * Lets the cooking assistant propose a new recipe from the conversation. * Deliberately does NOT write to the database — `execute` just validates and * echoes the input back as a draft. The chat UI renders that draft with an * explicit Confirm button, which POSTs to the existing /api/v1/recipes * endpoint (the same one the manual recipe editor uses) — so nothing gets * created without the user directly approving it, and there's exactly one * code path that actually writes a recipe row. */ export const createRecipeTool = tool({ description: "Propose creating a new recipe based on the conversation. This only drafts the recipe for the user to review — it does not save anything. Only call this when the user has actually asked you to create/save/write down a recipe, not just discussed one.", inputSchema: CreateRecipeInputSchema, execute: async (input: CreateRecipeToolInput) => input, });