import { ResearcherOutput, SearchAgentInput } from './types'; import SessionManager from '@/lib/session'; import { classify } from './classifier'; import Researcher from './researcher'; import { getWriterPrompt } from '@/lib/prompts/search/writer'; import { WidgetExecutor } from './widgets'; class SearchAgent { async searchAsync(session: SessionManager, input: SearchAgentInput) { const classification = await classify({ chatHistory: input.chatHistory, enabledSources: input.config.sources, query: input.followUp, llm: input.config.llm, }); const widgetPromise = WidgetExecutor.executeAll({ classification, chatHistory: input.chatHistory, followUp: input.followUp, llm: input.config.llm, }).then((widgetOutputs) => { widgetOutputs.forEach((o) => { session.emitBlock({ id: crypto.randomUUID(), type: 'widget', data: { widgetType: o.type, params: o.data, }, }); }); return widgetOutputs; }); let searchPromise: Promise | null = null; if (!classification.classification.skipSearch) { const researcher = new Researcher(); searchPromise = researcher.research(session, { chatHistory: input.chatHistory, followUp: input.followUp, classification: classification, config: input.config, }); } const [widgetOutputs, searchResults] = await Promise.all([ widgetPromise, searchPromise, ]); session.emit('data', { type: 'researchComplete', }); const finalContext = searchResults?.searchFindings .map( (f, index) => `${f.content}`, ) .join('\n') || ''; const widgetContext = widgetOutputs .map((o) => { return `${o.llmContext}`; }) .join('\n-------------\n'); const finalContextWithWidgets = `\n${finalContext}\n\n\n${widgetContext}\n`; const writerPrompt = getWriterPrompt(finalContextWithWidgets); const answerStream = input.config.llm.streamText({ messages: [ { role: 'system', content: writerPrompt, }, ...input.chatHistory, { role: 'user', content: input.followUp, }, ], }); let accumulatedText = ''; for await (const chunk of answerStream) { accumulatedText += chunk.contentChunk; session.emit('data', { type: 'response', data: chunk.contentChunk, }); } session.emit('end', {}); } } export default SearchAgent;