code: """
  # The core idea of a Multi-Document Agent
  
  The core idea of a Multi-Document Agent is to simulate a knowledgeable assistant that can draw upon information from
  multiple separate documents to provide informed, accurate answers to user queries. Unlike a traditional, single-document
  agent that can only access and understand information from one source, a multi-document agent has the capability to
  consider a broader range of information sources, similar to how a human expert would consult various references to
  answer complex questions.
  
  ## How a multi-document agent works
  
  Here's an outline of how a multi-document agent works:
  
  1. **Document Agents**: Each document (or set of related documents) is paired with a document agent. This agent is
  responsible for understanding the content within its assigned document(s). It has capabilities such as semantic search,
  to find relevant snippets within the document, and summarization, to distill the document's content into a concise form.
  
  2. **Top-Level Agent**: A top-level agent oversees the document agents. When a user asks a question, the top-level
  agent determines which document agents might have relevant information and directs the query appropriately.
  
  3. **Tool Retrieval**: The top-level agent uses a retriever mechanism to identify which tools (i.e., query engines of
  the individual document agents) are most relevant for the given query.
  
  4. **Reranking**: Retrieved documents or relevant snippets are reranked (possibly by an external system like Cohere)
  to refine the set of candidate responses, ensuring that the most relevant information is considered.
  
  5. **Query Planning Tool**: This tool is dynamically created based on the retrieved tools to plan out an effective
  strategy for leveraging the selected documents to answer the user's query.
  
  6. **Answering Queries**: To answer a query, the top-level agent orchestrates the use of the retrieved and reranked
  tools, conducting a "chain of thought" process over the set of relevant documents to formulate a comprehensive response.
  
  7. **Integration**: The responses from the document agents are integrated into a single coherent answer for the user.
  
  This setup is particularly powerful for complex queries that require cross-referencing information, understanding
  nuanced details, or comparing statements from multiple sources. The multi-document agent is designed to mimic a human
  expert's approach to research and analysis, using a rich set of data and tools for a more robust and informed response.
  """
  # System imports
  from contextlib import asynccontextmanager
  from dataclasses import dataclass
  import json
  from pathlib import Path
  import os
  import pickle
  from urllib.parse import urlparse
  from typing import Sequence
  
  # Third-party imports
  from dotenv import load_dotenv
  from llama_index import download_loader
  from llama_index.llms import OpenAI
  from llama_index import ServiceContext
  from llama_index import Document
  from llama_index import VectorStoreIndex, SummaryIndex
  from llama_index.agent import OpenAIAgent
  from llama_index import load_index_from_storage, StorageContext
  from llama_index.tools import QueryEngineTool, ToolMetadata
  from llama_index.node_parser import SentenceSplitter
  from llama_index import VectorStoreIndex
  from llama_index.objects import (
      ObjectIndex,
      SimpleToolNodeMapping,
      ObjectRetriever,
  )
  from llama_index.retrievers import BaseRetriever
  from llama_index.postprocessor import CohereRerank
  from llama_index.tools import QueryPlanTool
  from llama_index.query_engine import SubQuestionQueryEngine
  from llama_index.llms import OpenAI
  from llama_index.agent import FnRetrieverOpenAIAgent, ReActAgent
  from tqdm import tqdm
  from llama_index.schema import BaseNode
  from fastapi import FastAPI, Response
  from fastapi.middleware.cors import CORSMiddleware
  
  #
  
  load_dotenv()
  
  #
  
  
  class CustomRetriever(BaseRetriever):
      def __init__(self, vector_retriever, postprocessor=None) -> None:
          self._vector_retriever = vector_retriever
          self._postprocessor = postprocessor or CohereRerank(
              top_n=5, api_key=os.getenv("COHERE_API_KEY")
          )
          super().__init__()
  
      def _retrieve(self, query_bundle):
          retrieved_nodes = self._vector_retriever.retrieve(query_bundle)
          filtered_nodes = self._postprocessor.postprocess_nodes(
              retrieved_nodes, query_bundle=query_bundle
          )
  
          return filtered_nodes
  
  
  class CustomObjectRetriever(ObjectRetriever):
      def __init__(self, retriever, object_node_mapping, all_tools, llm=None) -> None:
          self._retriever = retriever
          self._object_node_mapping = object_node_mapping
          self._llm = llm or OpenAI(
              "gpt-4-0613",
              api_key=os.getenv("OPENAI_API_KEY"),
          )
  
      def retrieve(self, query_bundle):
          nodes = self._retriever.retrieve(query_bundle)
          tools = [self._object_node_mapping.from_node(n.node) for n in nodes]
  
          sub_question_sc = ServiceContext.from_defaults(llm=self._llm)
          sub_question_engine = SubQuestionQueryEngine.from_defaults(
              query_engine_tools=tools, service_context=sub_question_sc
          )
          sub_question_description = f"""\
  
  Useful for any queries that involve comparing multiple documents. ALWAYS use this tool for comparison queries - make sure to call this \
  tool with the original query. Do NOT use the other tools for any queries involving multiple documents.
  """
          sub_question_tool = QueryEngineTool(
              query_engine=sub_question_engine,
              metadata=ToolMetadata(
                  name="compare_tool", description=sub_question_description
              ),
          )
  
          return tools + [sub_question_tool]
  
  
  def download_website(
      url: str,
      corpus_name: str,
      data_base_path: str = "./data",
  ) -> str:
      domain = urlparse(url).netloc
      corpus_path = os.path.join(data_base_path, corpus_name)
      domain_path = os.path.join(corpus_path, domain)
      if not os.path.exists(domain_path):
          os.system(
              f"wget -e robots=off --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains {domain} --no-parent -P {corpus_path} {url}"
          )
      return domain_path
  
  
  def load_documents_from_directory(
      directory_path: str,
      suffix_filter: str | None,
      limit: int | None = None,
  ) -> list[Document]:
      UnstructuredReader = download_loader("UnstructuredReader")
      reader = UnstructuredReader()
      all_files_gen = Path(directory_path).rglob("*")
      all_files = [f.resolve() for f in all_files_gen]
      if suffix_filter is not None:
          all_files = [f for f in all_files if f.suffix.lower() == suffix_filter]
      if limit is not None:
          all_files = all_files[:limit]
  
      docs = []
      for idx, f in tqdm(enumerate(all_files), desc="Loading documents"):
          loaded_docs = reader.load_data(file=f, split_documents=True)
          loaded_doc = Document(
              text="\n\n".join([d.get_content() for d in loaded_docs]),
              metadata={"path": str(f)},
          )
          docs.append(loaded_doc)
  
      return docs
  
  
  def get_agents_base_path(
      data_base_path: str,
      corpus_name: str,
  ) -> str:
      return os.path.join(data_base_path, corpus_name, "agents")
  
  
  def get_agent_path(
      data_base_path: str,
      corpus_name: str,
      file_base: str,
  ) -> str:
      return os.path.join(get_agents_base_path(data_base_path, corpus_name), file_base)
  
  
  @dataclass
  class AgentPaths:
      data_base_path: str
      corpus_name: str
      file_base: str
      agent_path: str
      vector_idx_path: str
      summary_idx_path: str
      summary_file_path: str
  
  
  def get_agent_paths(
      data_base_path: str,
      corpus_name: str,
      file_base: str,
  ) -> AgentPaths:
      agent_path = get_agent_path(data_base_path, corpus_name, file_base)
      vector_idx_path = os.path.join(agent_path, "vector_idx")
      summary_idx_path = os.path.join(agent_path, "summary_idx")
      summary_file_path = os.path.join(agent_path, "summary.pkl")
      paths = AgentPaths(
          data_base_path=data_base_path,
          corpus_name=corpus_name,
          file_base=file_base,
          agent_path=agent_path,
          vector_idx_path=vector_idx_path,
          summary_idx_path=summary_idx_path,
          summary_file_path=summary_file_path,
      )
      return paths
  
  
  async def load_document_agent(
      agent_paths: AgentPaths,
      service_context: ServiceContext,
  ) -> tuple[OpenAIAgent, str]:
      vector_index = load_index_from_storage(
          StorageContext.from_defaults(persist_dir=agent_paths.vector_idx_path),
          service_context=service_context,
      )
  
      summary_index = load_index_from_storage(
          StorageContext.from_defaults(persist_dir=agent_paths.summary_idx_path),
          service_context=service_context,
      )
      summary = pickle.load(open(agent_paths.summary_file_path, "rb"))
  
      # Create query engines for the vector and summary indices
      vector_query_engine = vector_index.as_query_engine()
      summary_query_engine = summary_index.as_query_engine(response_mode="tree_summarize")
  
      query_engine_tools = [
          QueryEngineTool(
              query_engine=vector_query_engine,
              metadata=ToolMetadata(
                  name=f"vector_tool_{agent_paths.file_base}",
                  description="Useful for questions related to specific facts",
              ),
          ),
          QueryEngineTool(
              query_engine=summary_query_engine,
              metadata=ToolMetadata(
                  name=f"summary_tool_{agent_paths.file_base}",
                  description="Useful for summarization questions",
              ),
          ),
      ]
  
      function_llm = OpenAI(
          model="gpt-4",
          api_key=os.getenv("OPENAI_API_KEY"),
      )
      agent = OpenAIAgent.from_tools(
          query_engine_tools,
          llm=function_llm,
          verbose=True,
          system_prompt=f"""\
  
  You are a specialized agent designed to answer queries about the `{file_base}` part of the {corpus_name} docs.
  You must ALWAYS use at least one of the tools provided when answering a question; do NOT rely on prior knowledge.\
  """,
      )
      return agent, summary
  
  
  async def create_document_agent(
      nodes: Sequence[BaseNode],
      agent_paths: AgentPaths,
      service_context: ServiceContext,
  ) -> tuple[OpenAIAgent, str]:
      # Create the vector index
      Path(agent_paths.vector_idx_path).mkdir(parents=True, exist_ok=True)
      vector_index = VectorStoreIndex(nodes, service_context=service_context)
      vector_index.storage_context.persist(persist_dir=agent_paths.vector_idx_path)
  
      # Create the summary index
      Path(agent_paths.summary_idx_path).mkdir(parents=True, exist_ok=True)
      summary_index = SummaryIndex(nodes, service_context=service_context)
      summary_index.storage_context.persist(persist_dir=agent_paths.summary_idx_path)
  
      # Create the summary
      summary_query_engine = summary_index.as_query_engine(response_mode="tree_summarize")
      summary = str(
          await summary_query_engine.aquery(
              "Extract a concise 1-2 line summary of this document"
          )
      )
      pickle.dump(summary, open(agent_paths.summary_file_path, "wb"))
  
      return await load_document_agent(
          agent_paths=agent_paths,
          service_context=service_context,
      )
  
  
  async def create_document_agents(
      docs: list[Document],
      data_base_path: str,
      corpus_name: str,
      service_context: ServiceContext,
  ) -> tuple[dict, dict]:
      node_parser = SentenceSplitter()
  
      document_agents = {}
      extra_info = {}
  
      for doc in tqdm(docs, desc="Creating document agents"):
          # ID will be base + parent
          file_path = Path(doc.metadata["path"])
          file_base = str(file_path.parent.stem) + "_" + str(file_path.stem)
          file_base = file_base.replace(".", "_")
  
          agent_paths = get_agent_paths(
              data_base_path=data_base_path,
              corpus_name=corpus_name,
              file_base=file_base,
          )
  
          if os.path.exists(agent_paths.agent_path):
              agent, summary = await load_document_agent(
                  agent_paths=agent_paths,
                  service_context=service_context,
              )
          else:
              nodes = node_parser.get_nodes_from_documents([doc])
              agent, summary = await create_document_agent(
                  nodes=nodes,
                  agent_paths=agent_paths,
                  service_context=service_context,
              )
  
          document_agents[file_base] = agent
          extra_info[file_base] = {"summary": summary, "nodes": nodes}
  
      return document_agents, extra_info
  
  
  async def create_multidoc_agent(
      url: str,
      corpus_name: str,
  ) -> None:
      data_base_path = os.getenv("DATA_BASE_PATH", "./data")
  
      llm = OpenAI(
          model_name="gpt-4-0613",
          api_key=os.getenv("OPENAI_API_KEY"),
      )
      service_context = ServiceContext.from_defaults(llm=llm)
  
      #
  
      corpus_path = download_website(
          url=url,
          corpus_name=corpus_name,
          data_base_path=data_base_path,
      )
  
      docs = load_documents_from_directory(
          directory_path=corpus_path,
          suffix_filter=".html",
          # limit=10,
      )
  
      document_agents, extra_info = await create_document_agents(
          docs=docs,
          data_base_path=data_base_path,
          corpus_name=corpus_name,
          service_context=service_context,
      )
  
      all_tools = []
      for file_base, agent in document_agents.items():
          summary = extra_info[file_base]["summary"]
          doc_tool = QueryEngineTool(
              query_engine=agent,
              metadata=ToolMetadata(
                  name=f"tool_{file_base}",
                  description=summary,
              ),
          )
          all_tools.append(doc_tool)
  
      tool_mapping = SimpleToolNodeMapping.from_objects(all_tools)
      obj_index = ObjectIndex.from_objects(
          all_tools,
          tool_mapping,
          VectorStoreIndex,
      )
  
      vector_node_retriever = obj_index.as_node_retriever(similarity_top_k=10)
  
      custom_node_retriever = CustomRetriever(vector_node_retriever)
  
      custom_obj_retriever = CustomObjectRetriever(
          custom_node_retriever,
          tool_mapping,
          all_tools,
          llm=llm,
      )
  
      top_agent = FnRetrieverOpenAIAgent.from_retriever(
          custom_obj_retriever,
          system_prompt=""" \
          You are an agent designed to answer queries about the documentation.
          Please always use the tools provided to answer a question. Do not rely on prior knowledge.\
  
          """,
          llm=llm,
          verbose=True,
      )
      return top_agent
  
  
  #
  
  
  # Store agents in a dictionary
  agents = {}
  
  
  # Load agents from the JSON file when the server starts
  async def load_agents():
      try:
          data_base_path = os.getenv("DATA_BASE_PATH", "./data")
          agent_registry_file = os.path.join(data_base_path, "agents.json")
          with open(agent_registry_file, "r") as f:
              agents_registry = json.load(f)
              for corpus_name, url in agents_registry.items():
                  agents[corpus_name] = await create_multidoc_agent(url, corpus_name)
      except FileNotFoundError:
          pass  # It's okay if the file doesn't exist
  
  
  def save_agent(
      corpus_name: str,
      url: str,
  ):
      data_base_path = os.getenv("DATA_BASE_PATH", "./data")
      agent_registry = os.path.join(data_base_path, "agents.json")
      try:
          with open(agent_registry, "r") as f:
              data = json.load(f)
      except FileNotFoundError:
          data = {}
      data.update({corpus_name: url})
      with open(agent_registry, "w") as f:
          json.dump(data, f)
  
  
  #
  
  
  @asynccontextmanager
  async def lifespan(app: FastAPI):
      await load_agents()  # Call the function when the server starts
      yield
  
  
  app = FastAPI(lifespan=lifespan)
  app.add_middleware(
      CORSMiddleware,
      allow_origins=["*"],  # Replace "*" with the appropriate origins
      allow_credentials=True,
      allow_methods=["*"],
      allow_headers=["*"],
  )
  
  #
  
  
  @app.post("/agent/")
  async def create_agent(
      url: str,
      corpus_name: str,
  ) -> Response:
      agent = await create_multidoc_agent(url, corpus_name)
      agents[corpus_name] = agent
      save_agent(corpus_name=corpus_name, url=url)
      response = Response(status_code=201)
      response.headers["Location"] = f"/agent/{corpus_name}"
      return response
  
  
  @app.post("/agent/{corpus_name}/query")
  async def query_agent(
      corpus_name: str,
      query: str,
  ) -> str:
      agent = agents.get(corpus_name)
      if agent is None:
          return Response(status_code=404)
      response = await agent.aquery(query)
      return response.response
  
  
  #
  
  # url = "https://docs.llamaindex.ai/en/latest/"
  # corpus_name = "llamaindex_docs"
  
apis: llama_index.agent.FnRetrieverOpenAIAgent.from_retriever llama_index.tools.ToolMetadata llama_index.query_engine.SubQuestionQueryEngine.from_defaults llama_index.ServiceContext.from_defaults llama_index.StorageContext.from_defaults llama_index.VectorStoreIndex llama_index.objects.SimpleToolNodeMapping.from_objects llama_index.download_loader llama_index.agent.OpenAIAgent.from_tools llama_index.objects.ObjectIndex.from_objects llama_index.node_parser.SentenceSplitter llama_index.SummaryIndex
extract_api: [((3825, 3838), 'dotenv.load_dotenv', 'load_dotenv', ([], {}), '()\n', (3836, 3838), False, 'from dotenv import load_dotenv\n'), ((15763, 15789), 'fastapi.FastAPI', 'FastAPI', ([], {'lifespan': 'lifespan'}), '(lifespan=lifespan)\n', (15770, 15789), False, 'from fastapi import FastAPI, Response\n'), ((5877, 5918), 'os.path.join', 'os.path.join', (['data_base_path', 'corpus_name'], {}), '(data_base_path, corpus_name)\n', (5889, 5918), False, 'import os\n'), ((5937, 5970), 'os.path.join', 'os.path.join', (['corpus_path', 'domain'], {}), '(corpus_path, domain)\n', (5949, 5970), False, 'import os\n'), ((6426, 6463), 'llama_index.download_loader', 'download_loader', (['"""UnstructuredReader"""'], {}), "('UnstructuredReader')\n", (6441, 6463), False, 'from llama_index import download_loader\n'), ((7232, 7283), 'os.path.join', 'os.path.join', (['data_base_path', 'corpus_name', '"""agents"""'], {}), "(data_base_path, corpus_name, 'agents')\n", (7244, 7283), False, 'import os\n'), ((7863, 7901), 'os.path.join', 'os.path.join', (['agent_path', '"""vector_idx"""'], {}), "(agent_path, 'vector_idx')\n", (7875, 7901), False, 'import os\n'), ((7925, 7964), 'os.path.join', 'os.path.join', (['agent_path', '"""summary_idx"""'], {}), "(agent_path, 'summary_idx')\n", (7937, 7964), False, 'import os\n'), ((7989, 8028), 'os.path.join', 'os.path.join', (['agent_path', '"""summary.pkl"""'], {}), "(agent_path, 'summary.pkl')\n", (8001, 8028), False, 'import os\n'), ((9767, 10103), 'llama_index.agent.OpenAIAgent.from_tools', 'OpenAIAgent.from_tools', (['query_engine_tools'], {'llm': 'function_llm', 'verbose': '(True)', 'system_prompt': 'f"""\nYou are a specialized agent designed to answer queries about the `{file_base}` part of the {corpus_name} docs.\nYou must ALWAYS use at least one of the tools provided when answering a question; do NOT rely on prior knowledge."""'}), '(query_engine_tools, llm=function_llm, verbose=True,\n    system_prompt=\n    f"""\nYou are a specialized agent designed to answer queries about the `{file_base}` part of the {corpus_name} docs.\nYou must ALWAYS use at least one of the tools provided when answering a question; do NOT rely on prior knowledge."""\n    )\n', (9789, 10103), False, 'from llama_index.agent import OpenAIAgent\n'), ((10443, 10499), 'llama_index.VectorStoreIndex', 'VectorStoreIndex', (['nodes'], {'service_context': 'service_context'}), '(nodes, service_context=service_context)\n', (10459, 10499), False, 'from llama_index import VectorStoreIndex\n'), ((10708, 10760), 'llama_index.SummaryIndex', 'SummaryIndex', (['nodes'], {'service_context': 'service_context'}), '(nodes, service_context=service_context)\n', (10720, 10760), False, 'from llama_index import VectorStoreIndex, SummaryIndex\n'), ((11479, 11497), 'llama_index.node_parser.SentenceSplitter', 'SentenceSplitter', ([], {}), '()\n', (11495, 11497), False, 'from llama_index.node_parser import SentenceSplitter\n'), ((11560, 11603), 'tqdm.tqdm', 'tqdm', (['docs'], {'desc': '"""Creating document agents"""'}), "(docs, desc='Creating document agents')\n", (11564, 11603), False, 'from tqdm import tqdm\n'), ((12710, 12747), 'os.getenv', 'os.getenv', (['"""DATA_BASE_PATH"""', '"""./data"""'], {}), "('DATA_BASE_PATH', './data')\n", (12719, 12747), False, 'import os\n'), ((12873, 12910), 'llama_index.ServiceContext.from_defaults', 'ServiceContext.from_defaults', ([], {'llm': 'llm'}), '(llm=llm)\n', (12901, 12910), False, 'from llama_index import ServiceContext\n'), ((13775, 13820), 'llama_index.objects.SimpleToolNodeMapping.from_objects', 'SimpleToolNodeMapping.from_objects', (['all_tools'], {}), '(all_tools)\n', (13809, 13820), False, 'from llama_index.objects import ObjectIndex, SimpleToolNodeMapping, ObjectRetriever\n'), ((13837, 13904), 'llama_index.objects.ObjectIndex.from_objects', 'ObjectIndex.from_objects', (['all_tools', 'tool_mapping', 'VectorStoreIndex'], {}), '(all_tools, tool_mapping, VectorStoreIndex)\n', (13861, 13904), False, 'from llama_index.objects import ObjectIndex, SimpleToolNodeMapping, ObjectRetriever\n'), ((14245, 14544), 'llama_index.agent.FnRetrieverOpenAIAgent.from_retriever', 'FnRetrieverOpenAIAgent.from_retriever', (['custom_obj_retriever'], {'system_prompt': '"""         You are an agent designed to answer queries about the documentation.\n        Please always use the tools provided to answer a question. Do not rely on prior knowledge.\n        """', 'llm': 'llm', 'verbose': '(True)'}), '(custom_obj_retriever, system_prompt=\n    """         You are an agent designed to answer queries about the documentation.\n        Please always use the tools provided to answer a question. Do not rely on prior knowledge.\n        """\n    , llm=llm, verbose=True)\n', (14282, 14544), False, 'from llama_index.agent import FnRetrieverOpenAIAgent, ReActAgent\n'), ((15275, 15312), 'os.getenv', 'os.getenv', (['"""DATA_BASE_PATH"""', '"""./data"""'], {}), "('DATA_BASE_PATH', './data')\n", (15284, 15312), False, 'import os\n'), ((15334, 15377), 'os.path.join', 'os.path.join', (['data_base_path', '"""agents.json"""'], {}), "(data_base_path, 'agents.json')\n", (15346, 15377), False, 'import os\n'), ((16234, 16259), 'fastapi.Response', 'Response', ([], {'status_code': '(201)'}), '(status_code=201)\n', (16242, 16259), False, 'from fastapi import FastAPI, Response\n'), ((4972, 5015), 'llama_index.ServiceContext.from_defaults', 'ServiceContext.from_defaults', ([], {'llm': 'self._llm'}), '(llm=self._llm)\n', (5000, 5015), False, 'from llama_index import ServiceContext\n'), ((5046, 5145), 'llama_index.query_engine.SubQuestionQueryEngine.from_defaults', 'SubQuestionQueryEngine.from_defaults', ([], {'query_engine_tools': 'tools', 'service_context': 'sub_question_sc'}), '(query_engine_tools=tools,\n    service_context=sub_question_sc)\n', (5082, 5145), False, 'from llama_index.query_engine import SubQuestionQueryEngine\n'), ((5838, 5851), 'urllib.parse.urlparse', 'urlparse', (['url'], {}), '(url)\n', (5846, 5851), False, 'from urllib.parse import urlparse\n'), ((5982, 6009), 'os.path.exists', 'os.path.exists', (['domain_path'], {}), '(domain_path)\n', (5996, 6009), False, 'import os\n'), ((6019, 6221), 'os.system', 'os.system', (['f"""wget -e robots=off --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains {domain} --no-parent -P {corpus_path} {url}"""'], {}), "(\n    f'wget -e robots=off --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains {domain} --no-parent -P {corpus_path} {url}'\n    )\n", (6028, 6221), False, 'import os\n'), ((8518, 8587), 'llama_index.StorageContext.from_defaults', 'StorageContext.from_defaults', ([], {'persist_dir': 'agent_paths.vector_idx_path'}), '(persist_dir=agent_paths.vector_idx_path)\n', (8546, 8587), False, 'from llama_index import load_index_from_storage, StorageContext\n'), ((8690, 8760), 'llama_index.StorageContext.from_defaults', 'StorageContext.from_defaults', ([], {'persist_dir': 'agent_paths.summary_idx_path'}), '(persist_dir=agent_paths.summary_idx_path)\n', (8718, 8760), False, 'from llama_index import load_index_from_storage, StorageContext\n'), ((11660, 11686), 'pathlib.Path', 'Path', (["doc.metadata['path']"], {}), "(doc.metadata['path'])\n", (11664, 11686), False, 'from pathlib import Path\n'), ((11985, 12023), 'os.path.exists', 'os.path.exists', (['agent_paths.agent_path'], {}), '(agent_paths.agent_path)\n', (11999, 12023), False, 'import os\n'), ((14765, 14802), 'os.getenv', 'os.getenv', (['"""DATA_BASE_PATH"""', '"""./data"""'], {}), "('DATA_BASE_PATH', './data')\n", (14774, 14802), False, 'import os\n'), ((14833, 14876), 'os.path.join', 'os.path.join', (['data_base_path', '"""agents.json"""'], {}), "(data_base_path, 'agents.json')\n", (14845, 14876), False, 'import os\n'), ((15597, 15615), 'json.dump', 'json.dump', (['data', 'f'], {}), '(data, f)\n', (15606, 15615), False, 'import json\n'), ((16525, 16550), 'fastapi.Response', 'Response', ([], {'status_code': '(404)'}), '(status_code=404)\n', (16533, 16550), False, 'from fastapi import FastAPI, Response\n'), ((6518, 6538), 'pathlib.Path', 'Path', (['directory_path'], {}), '(directory_path)\n', (6522, 6538), False, 'from pathlib import Path\n'), ((9720, 9747), 'os.getenv', 'os.getenv', (['"""OPENAI_API_KEY"""'], {}), "('OPENAI_API_KEY')\n", (9729, 9747), False, 'import os\n'), ((10355, 10388), 'pathlib.Path', 'Path', (['agent_paths.vector_idx_path'], {}), '(agent_paths.vector_idx_path)\n', (10359, 10388), False, 'from pathlib import Path\n'), ((10618, 10652), 'pathlib.Path', 'Path', (['agent_paths.summary_idx_path'], {}), '(agent_paths.summary_idx_path)\n', (10622, 10652), False, 'from pathlib import Path\n'), ((12816, 12843), 'os.getenv', 'os.getenv', (['"""OPENAI_API_KEY"""'], {}), "('OPENAI_API_KEY')\n", (12825, 12843), False, 'import os\n'), ((14957, 14969), 'json.load', 'json.load', (['f'], {}), '(f)\n', (14966, 14969), False, 'import json\n'), ((15451, 15463), 'json.load', 'json.load', (['f'], {}), '(f)\n', (15460, 15463), False, 'import json\n'), ((5562, 5633), 'llama_index.tools.ToolMetadata', 'ToolMetadata', ([], {'name': '"""compare_tool"""', 'description': 'sub_question_description'}), "(name='compare_tool', description=sub_question_description)\n", (5574, 5633), False, 'from llama_index.tools import QueryEngineTool, ToolMetadata\n'), ((9207, 9331), 'llama_index.tools.ToolMetadata', 'ToolMetadata', ([], {'name': 'f"""vector_tool_{agent_paths.file_base}"""', 'description': '"""Useful for questions related to specific facts"""'}), "(name=f'vector_tool_{agent_paths.file_base}', description=\n    'Useful for questions related to specific facts')\n", (9219, 9331), False, 'from llama_index.tools import QueryEngineTool, ToolMetadata\n'), ((9479, 9592), 'llama_index.tools.ToolMetadata', 'ToolMetadata', ([], {'name': 'f"""summary_tool_{agent_paths.file_base}"""', 'description': '"""Useful for summarization questions"""'}), "(name=f'summary_tool_{agent_paths.file_base}', description=\n    'Useful for summarization questions')\n", (9491, 9592), False, 'from llama_index.tools import QueryEngineTool, ToolMetadata\n'), ((13602, 13661), 'llama_index.tools.ToolMetadata', 'ToolMetadata', ([], {'name': 'f"""tool_{file_base}"""', 'description': 'summary'}), "(name=f'tool_{file_base}', description=summary)\n", (13614, 13661), False, 'from llama_index.tools import QueryEngineTool, ToolMetadata\n'), ((4092, 4119), 'os.getenv', 'os.getenv', (['"""COHERE_API_KEY"""'], {}), "('COHERE_API_KEY')\n", (4101, 4119), False, 'import os\n'), ((4735, 4762), 'os.getenv', 'os.getenv', (['"""OPENAI_API_KEY"""'], {}), "('OPENAI_API_KEY')\n", (4744, 4762), False, 'import os\n')]