feat: cooking assistant can propose adding items to a shopping list

Second tool alongside createRecipe, same safety shape: addToShoppingList's
execute only validates/echoes input, no DB write. The proposal card lets
the user pick an existing list (fetched lazily) or name a new one, then
confirms through the exact two-call flow AddToShoppingListButton already
uses — POST /api/v1/shopping-lists (if new) then POST .../items — no new
persistence code path.

generateMealPlan intentionally not built as a tool: the existing
/api/v1/ai/meal-plan/generate endpoint generates and writes in one step
with a week/preferences input, not a specific plan payload, so it has no
"save this exact draft" entry point to confirm against without a larger
refactor. Documented as a known gap rather than forcing a weaker pattern.

v0.46.0
This commit is contained in:
Arnaud
2026-07-17 18:37:07 +02:00
parent 982d4e3264
commit 9eecdbac3c
11 changed files with 244 additions and 11 deletions
@@ -0,0 +1,27 @@
import { tool } from "ai";
import { z } from "zod";
const AddToShoppingListInputSchema = z.object({
items: z.array(z.object({
rawName: z.string().min(1).max(200).describe("Ingredient/item 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),
suggestedListName: z.string().max(100).optional().describe("Suggested name if the user wants a new list, e.g. 'Weekend BBQ'"),
});
export type AddToShoppingListToolInput = z.infer<typeof AddToShoppingListInputSchema>;
/**
* Lets the cooking assistant propose adding items to a shopping list — same
* safety shape as createRecipeTool: `execute` only validates/echoes the
* input, no DB write. The chat UI resolves which list (existing or new)
* and POSTs through the existing /api/v1/shopping-lists(/{id}/items)
* endpoints, the same ones AddToShoppingListButton already uses.
*/
export const addToShoppingListTool = tool({
description:
"Propose adding ingredients/items to a shopping list, e.g. from a recipe just discussed. This only drafts the item list for the user to review and pick a target list — it does not save anything. Only call this when the user has actually asked to add items to a shopping list.",
inputSchema: AddToShoppingListInputSchema,
execute: async (input: AddToShoppingListToolInput) => input,
});