import { tool } from "ai"; import { z } from "zod"; import type { Payload, PayloadRequest, User } from "payload"; export const generatePayloadLocalTools = ( payload: Payload, req: PayloadRequest, allowedCollections: string[], ) => { const tools: Record = {}; for (const collectionSlug of allowedCollections) { const slugKey = collectionSlug.replace(/-/g, "_"); // 1. Read (Find) Tool tools[`read_${slugKey}`] = tool({ description: `Read/Find documents from the Payload CMS collection: ${collectionSlug}`, parameters: z.object({ limit: z .number() .optional() .describe("Number of documents to return, max 100."), page: z.number().optional().describe("Page number for pagination."), // Simple string-based query for demo purposes. For a robust implementation, // we'd map this to Payload's where query logic using a structured Zod schema. query: z .string() .optional() .describe("Optional text to search within the collection."), }), // @ts-expect-error - AI SDK strict mode type inference bug execute: async ({ limit = 10, page = 1, query, }: { limit?: number; page?: number; query?: string; }) => { const where = query ? { id: { equals: query } } : undefined; // Placeholder logic return await payload.find({ collection: collectionSlug as any, limit: Math.min(limit, 100), page, where, req, // Crucial for passing the user context and respecting access control! }); }, }); // 2. Read by ID Tool tools[`read_${slugKey}_by_id`] = tool({ description: `Get a specific document by its ID from the ${collectionSlug} collection.`, parameters: z.object({ id: z .union([z.string(), z.number()]) .describe("The ID of the document."), }), // @ts-expect-error - AI SDK strict mode type inference bug execute: async ({ id }: { id: string | number }) => { return await payload.findByID({ collection: collectionSlug as any, id, req, // Enforce access control }); }, }); // 3. Create Tool tools[`create_${slugKey}`] = tool({ description: `Create a new document in the ${collectionSlug} collection.`, parameters: z.object({ data: z .record(z.any()) .describe("A JSON object containing the data to insert."), }), // @ts-expect-error - AI SDK strict mode type inference bug execute: async ({ data }: { data: Record }) => { return await payload.create({ collection: collectionSlug as any, data, req, // Enforce access control }); }, }); // 4. Update Tool tools[`update_${slugKey}`] = tool({ description: `Update an existing document in the ${collectionSlug} collection.`, parameters: z.object({ id: z .union([z.string(), z.number()]) .describe("The ID of the document to update."), data: z .record(z.any()) .describe("A JSON object containing the fields to update."), }), // @ts-expect-error - AI SDK strict mode type inference bug execute: async ({ id, data, }: { id: string | number; data: Record; }) => { return await payload.update({ collection: collectionSlug as any, id, data, req, // Enforce access control }); }, }); // 5. Delete Tool tools[`delete_${slugKey}`] = tool({ description: `Delete a document from the ${collectionSlug} collection by ID.`, parameters: z.object({ id: z .union([z.string(), z.number()]) .describe("The ID of the document to delete."), }), // @ts-expect-error - AI SDK strict mode type inference bug execute: async ({ id }: { id: string | number }) => { return await payload.delete({ collection: collectionSlug as any, id, req, // Enforce access control }); }, }); } return tools; };