import type { ComparisonRequest, ComparisonResult, ResearchProgress, } from "./types"; import { searchItem, type SearchResult } from "./providers/tavily"; import { generateComparisonWithResearch } from "./providers/openai"; import { getActiveProvider } from "./providers"; export type { ComparisonRequest, ComparisonResult, ResearchProgress, } from "./types"; export async function* runResearch( request: ComparisonRequest ): AsyncGenerator { yield { stage: "parsing", message: "Analyzing comparison request..." }; if (!request.items || request.items.length < 2) { yield { stage: "error", error: "At least 2 items are required for comparison", }; return; } const provider = getActiveProvider(); const searchResults: Record = {}; if (provider.hasSearch) { for (let i = 0; i < request.items.length; i++) { const item = request.items[i]; const results = await searchItem(item, request.query); searchResults[item] = results; yield { stage: "searching", item, results: results.length, }; yield { stage: "researching", item, progress: Math.round(((i + 1) / request.items.length) * 50), }; } } else { for (let i = 0; i < request.items.length; i++) { yield { stage: "researching", item: request.items[i], progress: Math.round(((i + 0.5) / request.items.length) * 80), }; } } yield { stage: "synthesizing", message: `Synthesizing research into structured comparison using ${provider.name}...`, }; try { const result = await provider.synthesize(request, searchResults); yield { stage: "complete", result }; } catch (error) { yield { stage: "error", error: error instanceof Error ? error.message : "Research failed unexpectedly", }; } } export async function executeResearch( request: ComparisonRequest ): Promise { for await (const progress of runResearch(request)) { if (progress.stage === "complete") { return progress.result; } if (progress.stage === "error") { throw new Error(progress.error); } } throw new Error("Research completed without producing a result"); }