code: # -*- coding: utf-8 -*-
  import os
  import re
  import sys
  sys.path.append('.')
  sys.path.append('..')
  from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
  from langchain.prompts import StringPromptTemplate
  from langchain import OpenAI, GoogleSearchAPIWrapper, LLMChain
  from typing import List, Union, Callable
  from langchain.schema import AgentAction, AgentFinish
  from langchain.vectorstores import FAISS
  from langchain.embeddings import OpenAIEmbeddings
  from langchain.schema import Document
  from utils.configs import configs
  
  os.environ["GOOGLE_CSE_ID"] = configs['tools']['google_cse_id']
  os.environ["GOOGLE_API_KEY"] = configs['tools']['google_api_key']
  os.environ["OPENAI_API_KEY"] = configs['openai_api_key']
  
  
  # Set up the base template
  template = """Answer the following questions as best you can, but speaking as a pirate might speak. You have access to the following tools:
  
  {tools}
  
  Use the following format:
  
  Question: the input question you must answer
  Thought: you should always think about what to do
  Action: the action to take, should be one of [{tool_names}]
  Action Input: the input to the action
  Observation: the result of the action
  ... (this Thought/Action/Action Input/Observation can repeat N times)
  Thought: I now know the final answer
  Final Answer: the final answer to the original input question
  
  Begin! Remember to speak as a pirate when giving your final answer. Use lots of "Arg"s
  
  Question: {input}
  {agent_scratchpad}"""
  
  
  def fake_func(inp: str) -> str:
      return "foo"
  
  
  def get_tools(query):
      docs = retriever.get_relevant_documents(query)
      return [ALL_TOOLS[d.metadata["index"]] for d in docs]
  
  
  # Set up a prompt template
  class CustomPromptTemplate(StringPromptTemplate):
      # The template to use
      template: str
      ############## NEW ######################
      # The list of tools available
      tools_getter: Callable
  
      def format(self, **kwargs) -> str:
          # Get the intermediate steps (AgentAction, Observation tuples)
          # Format them in a particular way
          intermediate_steps = kwargs.pop("intermediate_steps")
          thoughts = ""
          for action, observation in intermediate_steps:
              thoughts += action.log
              thoughts += f"\nObservation: {observation}\nThought: "
          # Set the agent_scratchpad variable to that value
          kwargs["agent_scratchpad"] = thoughts
          ############## NEW ######################
          tools = self.tools_getter(kwargs["input"])
          # Create a tools variable from the list of tools provided
          kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in tools])
          # Create a list of tool names for the tools provided
          kwargs["tool_names"] = ", ".join([tool.name for tool in tools])
          print(self.template.format(**kwargs))
          return self.template.format(**kwargs)
  
  
  class CustomOutputParser(AgentOutputParser):
  
      def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
          # Check if agent should finish
          if "Final Answer:" in llm_output:
              return AgentFinish(
                  # Return values is generally always a dictionary with a single `output` key
                  # It is not recommended to try anything else at the moment :)
                  return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
                  log=llm_output,
              )
          # Parse out the action and action input
          regex = r"Action: (.*?)[\n]*Action Input:[\s]*(.*)"
          match = re.search(regex, llm_output, re.DOTALL)
          if not match:
              raise ValueError(f"Could not parse LLM output: `{llm_output}`")
          action = match.group(1).strip()
          action_input = match.group(2)
          # Return the action and action input
          return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)
  
  
  if __name__ == '__main__':
      # Define which tools the agent can use to answer user queries
      search = GoogleSearchAPIWrapper()
  
      search_tool = Tool(
          name="Search",
          func=search.run,
          description="useful for when you need to answer questions about current events"
      )
      fake_tools = [
          Tool(
              name=f"foo-{i}",
              func=fake_func,
              description=f"a silly function that you can use to get more information about the number {i}"
          )
          for i in range(99)
      ]
  
      ALL_TOOLS = [search_tool] + fake_tools
  
      # tools retrieval
      tool_lib = configs['demo_agents']['tool_faiss_index']
      if os.path.exists(tool_lib):
          vector_store = FAISS.load_local(tool_lib, OpenAIEmbeddings())
      else:
          docs = [Document(page_content=t.description, metadata={"index": i}) for i, t in enumerate(ALL_TOOLS)]
          vector_store = FAISS.from_documents(docs, OpenAIEmbeddings())
          vector_store.save_local(tool_lib)
      retriever = vector_store.as_retriever()
  
      prompt = CustomPromptTemplate(
          template=template,
          tools_getter=get_tools,
          # This omits the `agent_scratchpad`, `tools`, and `tool_names` variables because those are generated dynamically
          # This includes the `intermediate_steps` variable because that is needed
          input_variables=["input", "intermediate_steps"]
      )
  
      output_parser = CustomOutputParser()
  
      model_name = configs['model_name']
      llm = OpenAI(model_name=model_name, temperature=0)
      # LLM chain consisting of the LLM and a prompt
      llm_chain = LLMChain(llm=llm, prompt=prompt)
  
      query = "What's the weather in SF?"
      tools = get_tools(query)
      tool_names = [tool.name for tool in tools]
      agent = LLMSingleActionAgent(
          llm_chain=llm_chain,
          output_parser=output_parser,
          stop=["\nObservation:"],
          allowed_tools=tool_names
      )
  
      agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True)
  
      agent_executor.run(query)
  
  
apis: langchain.agents.AgentExecutor.from_agent_and_tools langchain.GoogleSearchAPIWrapper langchain.schema.Document langchain.embeddings.OpenAIEmbeddings langchain.agents.LLMSingleActionAgent langchain.LLMChain langchain.OpenAI langchain.agents.Tool
extract_api: [((55, 75), 'sys.path.append', 'sys.path.append', (['"""."""'], {}), "('.')\n", (70, 75), False, 'import sys\n'), ((76, 97), 'sys.path.append', 'sys.path.append', (['""".."""'], {}), "('..')\n", (91, 97), False, 'import sys\n'), ((4014, 4038), 'langchain.GoogleSearchAPIWrapper', 'GoogleSearchAPIWrapper', ([], {}), '()\n', (4036, 4038), False, 'from langchain import OpenAI, GoogleSearchAPIWrapper, LLMChain\n'), ((4058, 4180), 'langchain.agents.Tool', 'Tool', ([], {'name': '"""Search"""', 'func': 'search.run', 'description': '"""useful for when you need to answer questions about current events"""'}), "(name='Search', func=search.run, description=\n    'useful for when you need to answer questions about current events')\n", (4062, 4180), False, 'from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser\n'), ((4577, 4601), 'os.path.exists', 'os.path.exists', (['tool_lib'], {}), '(tool_lib)\n', (4591, 4601), False, 'import os\n'), ((5400, 5444), 'langchain.OpenAI', 'OpenAI', ([], {'model_name': 'model_name', 'temperature': '(0)'}), '(model_name=model_name, temperature=0)\n', (5406, 5444), False, 'from langchain import OpenAI, GoogleSearchAPIWrapper, LLMChain\n'), ((5512, 5544), 'langchain.LLMChain', 'LLMChain', ([], {'llm': 'llm', 'prompt': 'prompt'}), '(llm=llm, prompt=prompt)\n', (5520, 5544), False, 'from langchain import OpenAI, GoogleSearchAPIWrapper, LLMChain\n'), ((5674, 5800), 'langchain.agents.LLMSingleActionAgent', 'LLMSingleActionAgent', ([], {'llm_chain': 'llm_chain', 'output_parser': 'output_parser', 'stop': "['\\nObservation:']", 'allowed_tools': 'tool_names'}), "(llm_chain=llm_chain, output_parser=output_parser, stop\n    =['\\nObservation:'], allowed_tools=tool_names)\n", (5694, 5800), False, 'from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser\n'), ((5856, 5930), 'langchain.agents.AgentExecutor.from_agent_and_tools', 'AgentExecutor.from_agent_and_tools', ([], {'agent': 'agent', 'tools': 'tools', 'verbose': '(True)'}), '(agent=agent, tools=tools, verbose=True)\n', (5890, 5930), False, 'from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser\n'), ((3542, 3581), 're.search', 're.search', (['regex', 'llm_output', 're.DOTALL'], {}), '(regex, llm_output, re.DOTALL)\n', (3551, 3581), False, 'import re\n'), ((4233, 4375), 'langchain.agents.Tool', 'Tool', ([], {'name': 'f"""foo-{i}"""', 'func': 'fake_func', 'description': 'f"""a silly function that you can use to get more information about the number {i}"""'}), "(name=f'foo-{i}', func=fake_func, description=\n    f'a silly function that you can use to get more information about the number {i}'\n    )\n", (4237, 4375), False, 'from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser\n'), ((4653, 4671), 'langchain.embeddings.OpenAIEmbeddings', 'OpenAIEmbeddings', ([], {}), '()\n', (4669, 4671), False, 'from langchain.embeddings import OpenAIEmbeddings\n'), ((4699, 4758), 'langchain.schema.Document', 'Document', ([], {'page_content': 't.description', 'metadata': "{'index': i}"}), "(page_content=t.description, metadata={'index': i})\n", (4707, 4758), False, 'from langchain.schema import Document\n'), ((4843, 4861), 'langchain.embeddings.OpenAIEmbeddings', 'OpenAIEmbeddings', ([], {}), '()\n', (4859, 4861), False, 'from langchain.embeddings import OpenAIEmbeddings\n')]