UNPKG

deepsearcher

Version:

DeepResearch Agent with LangGraph, use any llm and web search to build your own deep research agent

1 lines 36.4 kB
{"version":3,"sources":["../src/index.ts","../src/graph.ts","../src/schema.ts","../src/state.ts","../src/configuration.ts","../src/prompts.ts","../src/utils.ts"],"sourcesContent":["export * from './graph.js';\nexport * from './types.js';\nexport type { Configuration } from './configuration.js';","import { Send, START, END, StateGraph } from '@langchain/langgraph';\nimport { RunnableConfig, RunnableSequence } from '@langchain/core/runnables';\nimport { ChatOpenAI, type ClientOptions } from '@langchain/openai';\nimport { ReflectionSchema, SearchQueryListSchema } from './schema.js';\nimport {\n OverallAnnotation,\n OutputAnnotation,\n ResearchState,\n} from './state.js';\nimport {\n Configuration,\n ConfigurationSchema,\n getConfigurationFromRunnableConfig,\n} from './configuration.js';\nimport {\n answerInstructions,\n queryWriterInstructions,\n reflectionInstructions,\n searcherInstructions,\n} from './prompts.js';\nimport { SearcherFunction, SearchResultItem } from './types.js';\nimport { getCitations, getCurrentDate, getResearchTopic } from './utils.js';\nimport { ChatPromptTemplate } from '@langchain/core/prompts';\nimport { AIMessage } from '@langchain/core/messages';\nimport { StructuredOutputParser } from '@langchain/core/output_parsers';\n\nexport enum NodeEnum {\n GenerateQuery = 'generate_query',\n Research = 'research',\n Reflection = 'reflection',\n FinalizeAnswer = 'finalize_answer',\n}\n\nexport enum EventStreamEnum {\n ChatModelStart = 'on_chat_model_start',\n ChatModelStream = 'on_chat_model_stream',\n ChatModelEnd = 'on_chat_model_end',\n}\n\nexport class DeepResearch {\n private readonly options?: ClientOptions;\n private readonly searcher: SearcherFunction;\n\n /**\n * @param searcher - The function to use for searching\n * @param options - The options for the Runnable, including LLM provider settings\n */\n constructor({\n searcher,\n options,\n }: {\n searcher: SearcherFunction;\n options?: ClientOptions;\n }) {\n this.searcher = searcher;\n this.options = options;\n }\n\n async compile() {\n const workflow = new StateGraph(OverallAnnotation, ConfigurationSchema);\n\n workflow.addNode(NodeEnum.GenerateQuery, this.generateQuery.bind(this));\n workflow.addNode(NodeEnum.Research, this.research.bind(this), {\n input: ResearchState,\n });\n workflow.addNode(NodeEnum.Reflection, this.reflection.bind(this));\n workflow.addNode(NodeEnum.FinalizeAnswer, this.finalizeAnswer.bind(this));\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n workflow.addEdge(START, NodeEnum.GenerateQuery);\n\n workflow.addConditionalEdges(\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n NodeEnum.GenerateQuery,\n this.continueToSearch.bind(this),\n [NodeEnum.Research]\n );\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n workflow.addEdge(NodeEnum.Research, NodeEnum.Reflection);\n\n workflow.addConditionalEdges(\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n NodeEnum.Reflection,\n this.evaluateResearch.bind(this),\n [NodeEnum.Research, NodeEnum.FinalizeAnswer]\n );\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n workflow.addEdge(NodeEnum.FinalizeAnswer, END);\n\n return workflow.compile({ name: 'DeepResearch' });\n }\n\n /**\n * LangGraph node that generates a search queries based on the User's question.\n * Create an optimized search query for research based on the User's question.\n * @param state - Overall graph state\n * @param config - Configuration for the Runnable\n */\n private async generateQuery(\n state: typeof OverallAnnotation.State,\n config: RunnableConfig<Configuration>\n ): Promise<Partial<typeof OverallAnnotation.State>> {\n const configuration = getConfigurationFromRunnableConfig(config);\n const { numberOfInitialQueries } = configuration;\n\n const llm = new ChatOpenAI({\n model: configuration.queryGeneratorModel,\n temperature: 1.0,\n configuration: this.options,\n maxRetries: 2,\n apiKey: this.options?.apiKey,\n }).withConfig({\n tags: [NodeEnum.GenerateQuery],\n });\n\n const topic = getResearchTopic(state.messages);\n const currentDate = getCurrentDate();\n\n const prompt = ChatPromptTemplate.fromTemplate(queryWriterInstructions);\n const parser = StructuredOutputParser.fromZodSchema(SearchQueryListSchema);\n const chain = RunnableSequence.from([prompt, llm, parser]);\n\n try {\n const result = await chain.invoke({\n number_queries: numberOfInitialQueries,\n current_date: currentDate,\n research_topic: topic,\n format_instructions: parser.getFormatInstructions(),\n });\n\n // Ensure a valid query list is returned\n const queryList = result.query || [];\n if (queryList.length === 0) {\n console.warn(\n 'LLM returned empty query list, using original topic as fallback'\n );\n return { generatedQueries: [topic] };\n }\n\n return { generatedQueries: queryList };\n } catch (error) {\n console.error('Failed to generate search queries:', error);\n console.warn('Using original topic as fallback due to LLM failure');\n return { generatedQueries: [topic] };\n }\n }\n\n /**\n * LangGraph routing function that sends search queries to research nodes.\n * This is used to spawn n number of research nodes, one for each search query.\n * @param state - Overall graph state\n */\n private async continueToSearch(state: typeof OverallAnnotation.State) {\n const queryList = state.generatedQueries || [];\n\n if (queryList.length === 0) {\n const topic = getResearchTopic(state.messages);\n return [new Send(NodeEnum.Research, { query: topic, id: '0' })];\n }\n\n return queryList.map(\n (query, idx) => new Send(NodeEnum.Research, { query, id: idx.toString() })\n );\n }\n\n /**\n * LangGraph node that performs research based on the search query.\n * @param state - Research graph state\n * @param config - Configuration for the Runnable\n */\n private async research(\n state: typeof ResearchState.State,\n config: RunnableConfig<Configuration>\n ): Promise<Partial<typeof OverallAnnotation.State>> {\n const configuration = getConfigurationFromRunnableConfig(config);\n const { queryGeneratorModel } = configuration;\n\n const searchResults = await this.searcher(state);\n const formattedSearchResults = searchResults\n .map(\n ({ title, content, date, score }, index) =>\n `[[${index + 1}]]. Title: ${title}\\nContent: ${content}\\nDate: ${\n date ?? 'N/A'\n }\\nConfidence Score: ${score ?? 'N/A'}`\n )\n .join('\\n\\n');\n\n // use llm to process search results\n const llm = new ChatOpenAI({\n model: queryGeneratorModel,\n temperature: 0.2,\n maxRetries: 2,\n configuration: this.options,\n apiKey: this.options?.apiKey,\n }).withConfig({\n tags: [NodeEnum.Research],\n });\n\n const prompt = ChatPromptTemplate.fromTemplate(searcherInstructions);\n const chain = RunnableSequence.from([prompt, llm]);\n\n const result = await chain.invoke({\n current_date: getCurrentDate(),\n research_topic: state.query,\n search_results: formattedSearchResults,\n });\n\n // Return content and referenced indexes, content contains citation marks [title](id)\n const { content, segmentIndexes } = getCitations(result, searchResults);\n\n const usedSources = searchResults.filter((_, index) =>\n segmentIndexes.includes(`${index + 1}`)\n );\n\n return {\n sourcesGathered: usedSources,\n searchedQueries: [state.query],\n researchResult: [content],\n };\n }\n\n /**\n * LangGraph node that identifies knowledge gaps and generates potential follow-up queries.\n * Analyzes the current summary to identify areas for further research and generates\n * potential follow-up queries. Uses structured output to extract\n * the follow-up query in JSON format.\n */\n private async reflection(\n state: typeof OverallAnnotation.State,\n config: RunnableConfig<Configuration>\n ): Promise<Partial<typeof OverallAnnotation.State>> {\n const configuration = getConfigurationFromRunnableConfig(config);\n const { reflectionModel, numberOfInitialQueries } = configuration;\n\n const researchLoopCount = (state.researchLoopCount ?? 0) + 1;\n const model = reflectionModel;\n\n const researchTopic = getResearchTopic(state.messages);\n const summaries = state.researchResult.join('\\n\\n');\n\n const llm = new ChatOpenAI({\n model,\n temperature: 0,\n maxRetries: 2,\n configuration: this.options,\n apiKey: this.options?.apiKey,\n }).withConfig({\n tags: [NodeEnum.Reflection],\n });\n\n const prompt = ChatPromptTemplate.fromTemplate(reflectionInstructions);\n const parser = StructuredOutputParser.fromZodSchema(ReflectionSchema);\n const chain = RunnableSequence.from([prompt, llm, parser]);\n\n try {\n const result = await chain.invoke({\n research_topic: researchTopic,\n summaries,\n number_queries: numberOfInitialQueries,\n format_instructions: parser.getFormatInstructions(),\n });\n\n return {\n researchLoopCount,\n reflectionState: {\n isSufficient: result.isSufficient,\n knowledgeGap: result.knowledgeGap,\n followUpQueries: result.followUpQueries || [],\n numberOfRanQueries: state.searchedQueries.length,\n }\n };\n } catch (error) {\n console.error('Failed to generate reflection:', error);\n // if reflection fails, return default value\n return {\n researchLoopCount,\n reflectionState: {\n isSufficient: true, // assume the research is sufficient\n knowledgeGap: 'Unable to analyze knowledge gaps',\n followUpQueries: [], // empty array, avoid subsequent errors\n numberOfRanQueries: state.searchedQueries.length,\n }\n };\n }\n }\n\n /**\n * LangGraph routing function that determines the next step in the research flow.\n * Controls the research loop by deciding whether to continue gathering information\n * or to finalize the summary based on the configured maximum number of research loops.\n */\n private async evaluateResearch(\n state: typeof OverallAnnotation.State,\n config: RunnableConfig<Configuration>\n ) {\n const { reflectionState, researchLoopCount } = state;\n const configuration = getConfigurationFromRunnableConfig(config);\n\n const maxResearchLoops = configuration.maxResearchLoops;\n\n const { followUpQueries = [], isSufficient, numberOfRanQueries } = reflectionState;\n\n if (researchLoopCount >= maxResearchLoops || isSufficient) {\n return NodeEnum.FinalizeAnswer;\n }\n\n // check followUpQueries is empty\n if (!followUpQueries || followUpQueries.length === 0) {\n console.warn(\n 'No follow-up queries generated, proceeding to finalize answer'\n );\n return NodeEnum.FinalizeAnswer;\n }\n\n return followUpQueries.map(\n (query, index) =>\n new Send(NodeEnum.Research, {\n query,\n id: (numberOfRanQueries + index).toString(),\n })\n );\n }\n\n /**\n * LangGraph node that finalizes the answer based on the provided summaries.\n * @param state - Overall graph state\n * @param config - Configuration for the Runnable\n */\n private async finalizeAnswer(\n state: typeof OverallAnnotation.State,\n config: RunnableConfig<Configuration>\n ): Promise<typeof OutputAnnotation.State> {\n const configuration = getConfigurationFromRunnableConfig(config);\n const { reflectionModel } = configuration;\n\n const model = reflectionModel;\n const currentDate = getCurrentDate();\n const researchTopic = getResearchTopic(state.messages);\n const summaries = state.researchResult.join('\\n\\n');\n\n if (!summaries.trim()) {\n return {\n messages: [\n new AIMessage(\n 'Sorry, no useful information was retrieved. Please try again later or ask a different question.'\n ),\n ],\n sourcesGathered: [],\n };\n }\n\n const llm = new ChatOpenAI({\n model,\n temperature: 0,\n maxRetries: 2,\n configuration: this.options,\n apiKey: this.options?.apiKey,\n }).withConfig({\n tags: [NodeEnum.FinalizeAnswer],\n });\n\n const prompt = ChatPromptTemplate.fromTemplate(answerInstructions);\n const chain = RunnableSequence.from([prompt, llm]);\n\n const result = await chain.invoke({\n current_date: currentDate,\n research_topic: researchTopic,\n summaries,\n });\n\n const sourcesGathered: SearchResultItem[] = [];\n for (const source of state.sourcesGathered) {\n const citation = `(${source.id})`;\n const textMsg = result.content as string;\n if (textMsg.includes(citation)) {\n sourcesGathered.push(source);\n }\n }\n\n return {\n messages: [new AIMessage(result.content as string)],\n sourcesGathered,\n };\n }\n}\n","import { z } from 'zod';\n\n// 搜索查询列表 Schema\nexport const SearchQueryListSchema = z.object({\n query: z\n .array(z.string())\n .describe('A list of search queries to be used for research.'),\n rationale: z\n .string()\n .describe(\n 'A brief explanation of why these queries are relevant to the research topic.'\n ),\n});\n\n// 反思 Schema\nexport const ReflectionSchema = z.object({\n isSufficient: z\n .boolean()\n .describe(\n 'Whether the provided summaries are sufficient to answer the user\\'s question.'\n ),\n knowledgeGap: z\n .string()\n .describe(\n 'A description of what information is missing or needs clarification.'\n ),\n followUpQueries: z\n .array(z.string())\n .describe('A list of follow-up queries to address the knowledge gap.'),\n});\n\nexport type SearchQueryList = z.infer<typeof SearchQueryListSchema>;\nexport type Reflection = z.infer<typeof ReflectionSchema>;\n","import { addMessages, Annotation } from '@langchain/langgraph';\nimport { AIMessage, BaseMessageLike } from '@langchain/core/messages';\nimport { SearchResultItem } from './types.js';\n\n// Global State\nexport const OverallAnnotation = Annotation.Root({\n messages: Annotation<BaseMessageLike[]>({\n reducer: addMessages,\n default: () => [],\n }),\n generatedQueries: Annotation<string[]>,\n searchedQueries: Annotation<string[]>({\n reducer: (current, update) => current.concat(update),\n default: () => [],\n }),\n researchResult: Annotation<string[]>({\n reducer: (current, update) => current.concat(update),\n default: () => [],\n }),\n sourcesGathered: Annotation<SearchResultItem[]>({\n reducer: (current, update) => current.concat(update),\n default: () => [],\n }),\n researchLoopCount: Annotation<number>,\n // reflection state\n reflectionState: Annotation<typeof ReflectionState.State>,\n});\n\n// Output state\nexport const OutputAnnotation = Annotation.Root({\n sourcesGathered: Annotation<SearchResultItem[]>,\n messages: Annotation<AIMessage[]>,\n});\n\n// Reflection state\nexport const ReflectionState = Annotation.Root({\n isSufficient: Annotation<boolean>,\n knowledgeGap: Annotation<string>,\n followUpQueries: Annotation<string[]>,\n numberOfRanQueries: Annotation<number>,\n});\n\n// research state\nexport const ResearchState = Annotation.Root({\n query: Annotation<string>,\n id: Annotation<string>,\n});\n","import { RunnableConfig } from '@langchain/core/runnables';\nimport { z } from 'zod';\n\nexport const ConfigurationSchema = z.object({\n queryGeneratorModel: z\n .string()\n .describe(\n 'The name of the language model to use for the agent\\'s query generation.'\n ),\n reflectionModel: z\n .string()\n .describe(\n 'The name of the language model to use for the agent\\'s reflection.'\n ),\n answerModel: z\n .string()\n .describe('The name of the language model to use for the agent\\'s answer.'),\n numberOfInitialQueries: z\n .number()\n .describe('The number of initial search queries to generate.'),\n maxResearchLoops: z\n .number()\n .describe('The maximum number of research loops to perform.'),\n});\n\nexport type Configuration = z.infer<typeof ConfigurationSchema>;\n\nconst DEFAULT_CONFIG: Omit<\n Configuration,\n 'queryGeneratorModel' | 'reflectionModel' | 'answerModel'\n> = {\n numberOfInitialQueries: 3,\n maxResearchLoops: 3,\n};\n\n/**\n * Create a Configuration object from a RunnableConfig.\n */\nexport function getConfigurationFromRunnableConfig(\n config?: RunnableConfig<Partial<Configuration>>\n): Configuration {\n const configurable = config?.configurable ?? {};\n\n if (\n !configurable.answerModel ||\n !configurable.queryGeneratorModel ||\n !configurable.reflectionModel\n ) {\n throw new Error(\n 'Missing required model configuration: answerModel, queryGeneratorModel, and reflectionModel must be provided'\n );\n }\n\n const rawValues: Configuration = {\n queryGeneratorModel: configurable.queryGeneratorModel,\n reflectionModel: configurable.reflectionModel,\n answerModel: configurable.answerModel,\n numberOfInitialQueries:\n configurable.numberOfInitialQueries ??\n DEFAULT_CONFIG.numberOfInitialQueries,\n maxResearchLoops:\n configurable.maxResearchLoops ?? DEFAULT_CONFIG.maxResearchLoops,\n };\n\n // Filter out undefined values and convert string numbers to numbers\n Object.entries(rawValues).forEach(([key, value]) => {\n if (value !== undefined) {\n if (key === 'numberOfInitialQueries' || key === 'maxResearchLoops') {\n const numValue =\n typeof value === 'string' ? parseInt(value, 10) : value;\n (rawValues as Record<string, unknown>)[key] = numValue;\n }\n }\n });\n\n return rawValues;\n}\n","export const queryWriterInstructions = `Your goal is to generate sophisticated and diverse search queries. These queries are intended for an advanced automated research tool capable of analyzing complex results, following links, and synthesizing information.\n\nInstructions:\n- Always prefer a single search query, only add another query if the original question requests multiple aspects or elements and one query is not enough.\n- Each query should focus on one specific aspect of the original question.\n- Don't produce more than {number_queries} queries.\n- Queries should be diverse, if the topic is broad, generate more than 1 query.\n- Don't generate multiple similar queries, 1 is enough.\n- Query should ensure that the most current information is gathered. The current date is {current_date}.\n- Use specific keywords and technical terms rather than long descriptive sentences.\n- Focus on core concepts, product names, versions, or specific features for better search results.\n- **Language Constraint**: Always respond in the same language as the user's input. If the user asks in Chinese, respond in Chinese; if in English, respond in English, etc.\n\n{format_instructions}\n\nContext: {research_topic}`;\n\nexport const searcherInstructions = `Conduct targeted searches to gather the most recent, credible information on \"{research_topic}\" and synthesize it into a verifiable text artifact.\n\nInstructions:\n- Query should ensure that the most current information is gathered. The current date is {current_date}.\n- Conduct multiple, diverse searches to gather comprehensive information.\n- Consolidate key findings while meticulously tracking the source(s) for each specific piece of information.\n- The output should be a well-written summary or report based on your search findings. \n- Only include the information found in the search results, don't make up any information.\n- For each key finding, use numbered citations in double square brackets [[1]], [[2]], etc., referring to the search result numbers below.\n- **Language Constraint**: Always respond in the same language as the user's input. If the user asks in Chinese, respond in Chinese; if in English, respond in English, etc.\n\nCitation Format:\n- Use [[1]], [[2]], [[3]] etc. to cite specific search results\n- Each important claim or data point must include a citation\n- Multiple sources can be cited as [[1]][[2]]\n\nExample output format:\n\"According to recent studies, XYZ technology has shown significant improvements [[1]]. Market adoption rates have increased by 25% in 2024 [[2]][[3]].\"\n\nSearch Results:\n{search_results}\n\nResearch Topic:\n{research_topic}\n`;\n\nexport const reflectionInstructions = `You are an expert research assistant analyzing summaries about \"{research_topic}\".\n\nInstructions:\n- Identify knowledge gaps or areas that need deeper exploration and generate a follow-up query. (1 or multiple).\n- If provided summaries are sufficient to answer the user's question, don't generate a follow-up query.\n- If there is a knowledge gap, generate a follow-up query that would help expand your understanding.\n- Don't produce more than {number_queries} follow-up queries.\n- Focus on technical details, implementation specifics, or emerging trends that weren't fully covered.\n- **Language Constraint**: Always respond in the same language as the user's input. If the user asks in Chinese, respond in Chinese; if in English, respond in English, etc.\n\nQuery Optimization Requirements:\n- Ensure the follow-up query is self-contained and includes necessary context for search.\n- Use specific keywords and technical terms rather than long descriptive sentences.\n- Focus on core concepts, product names, versions, or specific features.\n- Avoid overly complex or verbose phrasing that may reduce search effectiveness.\n\n{format_instructions}\n\nReflect carefully on the Summaries to identify knowledge gaps and produce a follow-up query. Then, produce your output following this JSON format:\n\nSummaries:\n{summaries}\n`;\n\nexport const answerInstructions = `Generate a high-quality answer to the user's question based on the provided summaries.\n\nInstructions:\n- The current date is {current_date}.\n- You are the final step of a multi-step research process, don't mention that you are the final step. \n- You have access to all the information gathered from the previous steps.\n- You have access to the user's question.\n- Generate a high-quality answer to the user's question based on the provided summaries and the user's question.\n- you MUST include all the citations from the summaries in the answer correctly: [title](id/url).\n- **Language Constraint**: Always respond in the same language as the user's input. If the user asks in Chinese, respond in Chinese; if in English, respond in English, etc.\n\nUser Context:\n- {research_topic}\n\nSummaries:\n{summaries}`;\n","import {\n HumanMessage,\n AIMessage,\n AIMessageChunk,\n BaseMessageLike,\n} from '@langchain/core/messages';\nimport { SearchResultItem } from './types.js';\n\n/**\n * Get the research topic from the messages.\n */\nexport function getResearchTopic(messages: BaseMessageLike[]) {\n // check if request has a history and combine the messages into a single string\n if (messages.length === 1) {\n const msg = messages[messages.length - 1];\n if (typeof msg === 'string') {\n return msg;\n }\n if ('content' in msg) {\n if (typeof msg.content === 'string') {\n return msg.content;\n }\n if (Array.isArray(msg.content)) {\n return msg.content\n .map(item => item.type === 'text' ? item.text : '')\n .join('\\n');\n }\n }\n return JSON.stringify(msg);\n } else {\n let researchTopic = '';\n for (const message of messages) {\n if (message instanceof HumanMessage) {\n researchTopic += `User: ${message.content}\\n`;\n } else if (message instanceof AIMessage) {\n researchTopic += `Assistant: ${message.content}\\n`;\n }\n }\n return researchTopic;\n }\n}\n\n/**\n * Extracts and formats citation information from a model's response.\n * Original Citation Format:\n * - [[1]], [[2]], [[3]] etc. to cite specific search results\n * - Multiple sources can be cited as [[1]][[2]]\n * Formatted Citation Format:\n * - `[Title](id)` to cite specific search results\n * - Multiple sources can be cited as `[Title](id)[Title](id)`\n */\nexport function getCitations(\n response: AIMessageChunk,\n sources: SearchResultItem[]\n) {\n const text = response.content as string;\n\n const replaceCitationMark = (text: string): string => {\n return (\n text\n // 直接转换 [[数字]] 为 [citation](数字)\n .replace(/\\[\\[(\\d+)]]/g, '[citation]($1)')\n // 如果还有其他格式需要处理,可以继续添加\n .replace(/\\[(\\d+)]/g, '[citation]($1)')\n );\n };\n\n // 获取应用内容中的数字\n const getCitationNumber = (text: string): string[] => {\n const regex = /\\[citation\\]\\((\\d+)\\)/g;\n const numbers: string[] = [];\n let match;\n while ((match = regex.exec(text)) !== null) {\n numbers.push(match[1]);\n }\n return numbers;\n };\n\n const formattedText = replaceCitationMark(text);\n\n // insert citations\n const citationRegex = /\\[citation\\]\\((\\d+)\\)/g;\n const citationNumbers = getCitationNumber(formattedText);\n\n const insertedText = formattedText.replace(citationRegex, str => {\n const index = parseInt(str.match(/\\((\\d+)\\)/)?.[1] ?? '0', 10);\n const source = sources[index - 1];\n if (!source) {\n return str;\n }\n const title =\n source.title.length > 32\n ? source.title.slice(0, 32) + '...'\n : source.title;\n return `[${title}](${source.id})`;\n });\n\n return {\n content: insertedText,\n segmentIndexes: citationNumbers,\n };\n}\n\nexport const getCurrentDate = () => new Date().toISOString();\n"],"mappings":"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","names":["index_exports","__export","DeepResearch","EventStreamEnum","NodeEnum","__toCommonJS","import_langgraph","import_runnables","import_openai","import_zod","SearchQueryListSchema","ReflectionSchema","import_langgraph","OverallAnnotation","current","update","OutputAnnotation","ReflectionState","ResearchState","import_zod","ConfigurationSchema","DEFAULT_CONFIG","getConfigurationFromRunnableConfig","config","configurable","rawValues","key","value","numValue","queryWriterInstructions","searcherInstructions","reflectionInstructions","answerInstructions","import_messages","getResearchTopic","messages","msg","item","researchTopic","message","getCitations","response","sources","text","replaceCitationMark","getCitationNumber","regex","numbers","match","formattedText","citationRegex","citationNumbers","str","index","source","getCurrentDate","import_prompts","import_messages","import_output_parsers","NodeEnum","EventStreamEnum","DeepResearch","searcher","options","workflow","OverallAnnotation","ConfigurationSchema","ResearchState","state","config","configuration","getConfigurationFromRunnableConfig","numberOfInitialQueries","llm","topic","getResearchTopic","currentDate","getCurrentDate","prompt","queryWriterInstructions","parser","SearchQueryListSchema","chain","queryList","error","query","idx","queryGeneratorModel","searchResults","formattedSearchResults","title","content","date","score","index","searcherInstructions","result","segmentIndexes","getCitations","_","reflectionModel","researchLoopCount","model","researchTopic","summaries","reflectionInstructions","ReflectionSchema","reflectionState","maxResearchLoops","followUpQueries","isSufficient","numberOfRanQueries","answerInstructions","sourcesGathered","source","citation"]}