import type { Result } from "../../types/result"; import { z } from "zod"; import { Err, Ok } from "../../types/result"; const searchResponseSchema = z.object({ results: z.array(z.object({ title: z.string(), url: z.string(), content: z.string().optional().default(""), })), unresponsive_engines: z.array(z.tuple([z.string(), z.string()])).optional().default([]), }); export const searchInputSchema = z.object({ query: z.string(), results: z.number().int().positive().describe("Number of search results to return; choose this for every search."), }); export const searchOutputSchema = z.object({ results: z.array(z.object({ title: z.string(), link: z.string(), snippet: z.string(), })), warnings: z.array(z.object({ engine: z.string(), reason: z.string() })), }); type SearchOutput = z.infer; export const limitSearchResults = (output: SearchOutput, results: number): SearchOutput => ({ results: output.results.slice(0, results), warnings: output.warnings, }); export const readSearchResponse = (body: unknown): Result => { const parsed = searchResponseSchema.safeParse(body); if (!parsed.success) { return Err("Search returned an unexpected response format."); } const warnings = parsed.data.unresponsive_engines.map(([engine, reason]) => ({ engine, reason })); if (parsed.data.results.length === 0 && warnings.length > 0) { return Err(`Search returned no results because engines failed: ${warnings.map(warning => `${warning.engine}: ${warning.reason}`).join("; ")}`); } return Ok({ results: parsed.data.results.map(item => ({ title: item.title, link: item.url, snippet: item.content, })), warnings, }); };