deepsearcher
Version:
DeepResearch Agent with LangGraph, use any llm and web search to build your own deep research agent
1 lines • 43.1 kB
Source Map (JSON)
{"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';\nexport { HumanMessage, AIMessage, SystemMessage, BaseMessage } from 'langchain';","import { Send, START, END, StateGraph } from '@langchain/langgraph';\nimport { RunnableConfig } from '@langchain/core/runnables';\nimport { ChatOpenAI, type ClientOptions } from '@langchain/openai';\nimport { AnthropicInput, ChatAnthropic } from '@langchain/anthropic';\nimport { ChatGoogleGenerativeAI } from '@langchain/google-genai';\nimport { ChatVertexAI } from '@langchain/google-vertexai';\nimport { AIMessage, createAgent, HumanMessage, toolStrategy } from 'langchain';\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, replaceVariable } from './utils.js';\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 interface DeepResearchOptions extends ClientOptions {\n type?: 'openai' | 'anthropic' | 'gemini' | 'vertexai';\n systemPrompt?: string;\n temperature?: number;\n /**\n * Enable URL format in citations (default: true)\n * - true: output format is <sup>[[id](url)]</sup>\n * - false: output format is [[citation:id]]\n */\n enableCitationUrl?: boolean;\n}\n\nexport class DeepResearch {\n private readonly options?: DeepResearchOptions;\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?: DeepResearchOptions;\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, queryGeneratorModel } = configuration;\n const { systemPrompt = 'You are a helpful research assistant.', temperature = 0.1 } = this.options || {};\n\n const topic = getResearchTopic(state.messages);\n const currentDate = getCurrentDate();\n\n const client = this.createClient(queryGeneratorModel, temperature);\n const agent = createAgent({\n model: client,\n tools: [],\n systemPrompt,\n responseFormat: toolStrategy(SearchQueryListSchema, {\n toolMessageContent: `I will generate ${numberOfInitialQueries} search queries based on your input.`,\n }),\n });\n\n const prompt = replaceVariable(\n queryWriterInstructions,\n {\n number_queries: numberOfInitialQueries,\n current_date: currentDate,\n research_topic: topic,\n }\n );\n\n try {\n const result = await agent.invoke({\n messages: [\n new HumanMessage(prompt),\n ]\n }, {\n tags: [NodeEnum.GenerateQuery]\n });\n\n // Ensure a valid query list is returned\n const queryList = result.structuredResponse?.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, rationale: result.structuredResponse?.rationale };\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(), loopIndex: 1 })\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 const { temperature = 0.1, enableCitationUrl = true } = this.options || {};\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 const client = this.createClient(queryGeneratorModel, temperature);\n const agent = createAgent({\n model: client,\n tools: [],\n });\n\n const prompt = replaceVariable(\n searcherInstructions,\n {\n current_date: getCurrentDate(),\n research_topic: state.query,\n search_results: formattedSearchResults,\n }\n );\n\n const result = await agent.invoke({\n messages: [\n new HumanMessage(prompt),\n ]\n }, {\n tags: [NodeEnum.Research]\n });\n\n // Extract the AI message content from the agent result\n const lastMessage = result.messages[result.messages.length - 1];\n\n // Return content and referenced indexes, content contains citation marks with URL\n const { content, segmentIndexes } = getCitations(lastMessage, searchResults, enableCitationUrl);\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 researchLoopCount: state.loopIndex,\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 const { temperature = 0.1 } = this.options || {};\n\n // const researchLoopCount = (state.researchLoopCount ?? 0) + 1;\n\n const researchTopic = getResearchTopic(state.messages);\n const summaries = state.researchResult.join('\\n\\n');\n\n const client = this.createClient(reflectionModel, temperature);\n const agent = createAgent({\n model: client,\n tools: [],\n responseFormat: toolStrategy(ReflectionSchema, {\n toolMessageContent: 'I will analyze the research summaries and determine if more information is needed.',\n }),\n });\n\n const prompt = replaceVariable(\n reflectionInstructions,\n {\n research_topic: researchTopic,\n summaries,\n number_queries: numberOfInitialQueries,\n }\n );\n\n try {\n const result = await agent.invoke({\n messages: [\n new HumanMessage(prompt),\n ]\n }, {\n tags: [NodeEnum.Reflection]\n });\n\n const structuredResponse = result.structuredResponse;\n\n return {\n // researchLoopCount,\n reflectionState: {\n isSufficient: structuredResponse?.isSufficient ?? true,\n knowledgeGap: structuredResponse?.knowledgeGap ?? '',\n followUpQueries: structuredResponse?.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 loopIndex: researchLoopCount + 1,\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 const { systemPrompt = 'You are a helpful research assistant.', temperature = 0.1, enableCitationUrl = true } = this.options || {};\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 client = this.createClient(model, temperature);\n const agent = createAgent({\n model: client,\n tools: [],\n systemPrompt,\n });\n\n const prompt = replaceVariable(\n answerInstructions,\n {\n research_topic: researchTopic,\n summaries,\n current_date: currentDate,\n }\n );\n\n const result = await agent.invoke({\n messages: [\n new HumanMessage(prompt),\n ],\n }, {\n tags: [NodeEnum.FinalizeAnswer],\n });\n\n // Extract the AI message content from the agent result\n const lastMessage = result.messages[result.messages.length - 1];\n const messageContent = typeof lastMessage.content === 'string' \n ? lastMessage.content \n : JSON.stringify(lastMessage.content);\n\n const sourcesGathered: SearchResultItem[] = [];\n for (const source of state.sourcesGathered) {\n let isIncluded = false;\n\n if (enableCitationUrl) {\n // Check for URL citation formats when enableCitationUrl is true\n const citationWithUrl = `<sup>[[${source.id}](${source.url})]</sup>`;\n const citationWithoutUrl = `<sup>[[${source.id}]]</sup>`;\n isIncluded = messageContent.includes(citationWithUrl) || messageContent.includes(citationWithoutUrl);\n } else {\n // Check for simple citation format when enableCitationUrl is false\n const simpleCitation = `[[citation:${source.id}]]`;\n isIncluded = messageContent.includes(simpleCitation);\n }\n\n if (isIncluded) {\n sourcesGathered.push(source);\n }\n }\n\n return {\n messages: [new AIMessage(messageContent)],\n sourcesGathered,\n };\n }\n\n private createClient(model: string, temperature = 0.1) {\n const { apiKey, type = 'openai', baseURL, ...rest } = this.options || {};\n switch (type) {\n case 'anthropic': {\n const options: AnthropicInput = {\n model: model,\n anthropicApiKey: apiKey as string,\n temperature,\n ...rest,\n };\n if (baseURL) {\n options.anthropicApiUrl = baseURL;\n }\n return new ChatAnthropic(options);\n }\n case 'gemini':\n return new ChatGoogleGenerativeAI({\n model: model,\n apiKey: apiKey as string,\n baseUrl: baseURL || undefined,\n temperature,\n ...rest,\n });\n case 'vertexai':\n return new ChatVertexAI({\n model: model,\n apiKey: apiKey as string,\n temperature,\n ...rest,\n });\n case 'openai':\n default:\n return new ChatOpenAI({\n model: model,\n openAIApiKey: apiKey,\n temperature,\n configuration: {\n apiKey,\n baseURL,\n ...rest,\n }\n });\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 type { AIMessage } from 'langchain';\nimport type { 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 rationale: Annotation<string>,\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 reducer: (current, update) => Math.max(current, update ?? 0),\n default: () => 0,\n }),\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 loopIndex: Annotation<number>,\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\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 the format [[citation:1]], [[citation: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 [[citation:1]], [[citation:2]], [[citation: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 [[citation:1]][[citation:2]]\n\nExample output format:\n\"According to recent studies, XYZ technology has shown significant improvements [[citation:1]]. Market adoption rates have increased by 25% in 2024 [[citation:2]][[citation: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- **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\nReflect carefully on the Summaries to identify knowledge gaps and produce a follow-up query.\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 in the format [[citation:number]].\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]] or [[citation:1]], [[citation:2]] etc. to cite specific search results\n * - Multiple sources can be cited as [[1]][[2]] or [[citation:1]][[citation:2]]\n * Formatted Citation Format:\n * - If enableUrl is true: `<sup>[[id](url)]</sup>` if URL exists, `<sup>[[id]]</sup>` if no URL\n * - If enableUrl is false: `[[citation:id]]`\n */\nexport function getCitations(\n response: AIMessageChunk | { content: string | unknown },\n sources: SearchResultItem[],\n enableUrl = true\n) {\n const text = typeof response.content === 'string'\n ? response.content\n : JSON.stringify(response.content);\n\n const replaceCitationMark = (text: string): string => {\n return (\n text\n // Convert [[citation:number]] to [citation](number)\n .replace(/\\[\\[citation:(\\d+)]]/g, '[citation]($1)')\n // Convert [[number]] to [citation](number)\n .replace(/\\[\\[(\\d+)]]/g, '[citation]($1)')\n // Convert [number] to [citation](number)\n .replace(/(?<!\\[)\\[(\\d+)](?!])/g, '[citation]($1)')\n );\n };\n\n // Get numbers from the application content\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 with URL or keep simple format\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\n // If enableUrl is false, return simple citation format\n if (!enableUrl) {\n return `[[citation:${source.id}]]`;\n }\n\n // If enableUrl is true, return URL format\n if (source.url) {\n return `<sup>[[${source.id}](${source.url})]</sup>`;\n }\n return `<sup>[[${source.id}]]</sup>`;\n });\n\n return {\n content: insertedText,\n segmentIndexes: citationNumbers,\n };\n}\n\nexport const getCurrentDate = () => new Date().toISOString();\n\n/**\n * replace the variable in the string with the value\n * e.g replaceVariable(`abc{query}, efg.`, { query: '456' })\n */\nexport function replaceVariable(\n text: string,\n obj: Record<string, string | number>\n): string {\n if (!(typeof text === 'string')) return text;\n\n for (const key in obj) {\n const val = obj[key];\n if (!['string', 'number'].includes(typeof val)) continue;\n\n text = text.replace(new RegExp(`{(${key})}`, 'g'), String(val));\n }\n return text || '';\n}"],"mappings":"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","names":["index_exports","__export","DeepResearch","EventStreamEnum","NodeEnum","__toCommonJS","import_langgraph","import_openai","import_anthropic","import_google_genai","import_google_vertexai","import_langchain","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","enableUrl","text","replaceCitationMark","getCitationNumber","regex","numbers","match","formattedText","citationRegex","citationNumbers","str","index","source","getCurrentDate","replaceVariable","obj","key","val","NodeEnum","EventStreamEnum","DeepResearch","searcher","options","workflow","OverallAnnotation","ConfigurationSchema","ResearchState","state","config","configuration","getConfigurationFromRunnableConfig","numberOfInitialQueries","queryGeneratorModel","systemPrompt","temperature","topic","getResearchTopic","currentDate","getCurrentDate","client","agent","SearchQueryListSchema","prompt","replaceVariable","queryWriterInstructions","result","queryList","error","query","idx","enableCitationUrl","searchResults","formattedSearchResults","title","content","date","score","index","searcherInstructions","lastMessage","segmentIndexes","getCitations","_","reflectionModel","researchTopic","summaries","ReflectionSchema","reflectionInstructions","structuredResponse","reflectionState","researchLoopCount","maxResearchLoops","followUpQueries","isSufficient","numberOfRanQueries","model","answerInstructions","messageContent","sourcesGathered","source","isIncluded","citationWithUrl","citationWithoutUrl","simpleCitation","apiKey","type","baseURL","rest","import_langchain"]}