Issue[Bug]: OpenAIMultiFunctionsAgent stuck - 'tool_selection is not a valid tool'
Labels: name: bug

### Issue you'd like to raise.

Hi, 

I was trying to get `PythonREPL `or in this case `PythonAstREPL `to work with the `OpenAIMultiFunctionsAgent` reliably, because I came across the same problem as mentioned in this issue: https://github.com/hwchase17/langchain/issues/6364.

I applied the mentioned fix, which worked very well for fixing the REPL tool, but sadly it also broke the usage of any other tools. The agent repeatedly reports `tool_selection is not a valid tool, try another one.`

This is my code to create the agent and tools, as well as for applying the fix (i'm using chainlit for ui):

```
@cl.langchain_factory(use_async=False)
def factory():
    # Initialize the OpenAI language model
    model = llms[str(use_model)]
    llm = ChatOpenAI(
        temperature=0, 
        model=model,
        streaming=True, 
        client="openai",
        # callbacks=[cl.ChainlitCallbackHandler()]
    )

    # Initialize the SerpAPIWrapper for search functionality
    search = SerpAPIWrapper(search_engine="google")

    # Define a list of tools offered by the agent
    tools = [
        Tool(
            name="Search",
            func=search.run, 
            description="Useful when you need to answer questions about current events or if you have to search the web. You should ask targeted questions like for google."
        ),
        CustomPythonAstREPLTool(),
        WriteFileTool(),
        ReadFileTool(),
        CopyFileTool(),
        MoveFileTool(),
        DeleteFileTool(),
        FileSearchTool(),
        ListDirectoryTool(),
        ShellTool(),
        HumanInputRun(),
    ]

    memory = ConversationTokenBufferMemory(
        memory_key="memory", 
        return_messages=True,
        max_token_limit=2000,
        llm=llm
    )

    # needed for memory with openai functions agent
    agent_kwargs = {
        "extra_prompt_messages": [MessagesPlaceholder(variable_name="memory")],
    }

    prompt = OpenAIFunctionsAgent.create_prompt(
        extra_prompt_messages=[MessagesPlaceholder(variable_name="memory")],
    ),

    print("Prompt: ", prompt[0])

    cust_agent = CustomOpenAIMultiFunctionsAgent(
        tools=tools,
        llm=llm,
        prompt=prompt[0],
        # kwargs=agent_kwargs,
        # return_intermediate_steps=True,
    )

    mrkl = AgentExecutor.from_agent_and_tools(
        agent=cust_agent,
        tools=tools,
        memory=memory,
        # kwargs=agent_kwargs,
        # return_intermediate_steps=True,
    )

    return mrkl



# ----- Custom classes and functions ----- #

class CustomPythonAstREPLTool(PythonAstREPLTool):
    name = "python"
    description = (
        "A Python shell. Use this to execute python commands. "
        "The input must be an object as follows: "
        "{'__arg1': 'a valid python command.'} "
        "When using this tool, sometimes output is abbreviated - "
        "Make sure it does not look abbreviated before using it in your answer. "
        "Don't add comments to your python code."
    )

def _parse_ai_message(message: BaseMessage) -> Union[AgentAction, AgentFinish]:
    """Parse an AI message."""
    if not isinstance(message, AIMessage):
        raise TypeError(f"Expected an AI message got {type(message)}")

    function_call = message.additional_kwargs.get("function_call", {})

    if function_call:
        function_call = message.additional_kwargs["function_call"]
        function_name = function_call["name"]
        try:
            _tool_input = json.loads(function_call["arguments"])
        except JSONDecodeError:
            print(
                f"Could not parse tool input: {function_call} because "
                f"the `arguments` is not valid JSON."
            )
            _tool_input = function_call["arguments"]

        # HACK HACK HACK:
        # The code that encodes tool input into Open AI uses a special variable
        # name called `__arg1` to handle old style tools that do not expose a
        # schema and expect a single string argument as an input.
        # We unpack the argument here if it exists.
        # Open AI does not support passing in a JSON array as an argument.
        if "__arg1" in _tool_input:
            tool_input = _tool_input["__arg1"]
        else:
            tool_input = _tool_input

        content_msg = "responded: {content}\n" if message.content else "\n"

        return _FunctionsAgentAction(
            tool=function_name,
            tool_input=tool_input,
            log=f"\nInvoking: `{function_name}` with `{tool_input}`\n{content_msg}\n",
            message_log=[message],
        )

    return AgentFinish(return_values={"output": message.content}, log=message.content)

class CustomOpenAIMultiFunctionsAgent(OpenAIMultiFunctionsAgent):
    def plan(
        self,
        intermediate_steps: List[Tuple[AgentAction, str]],
        callbacks: Callbacks = None,
        **kwargs: Any,
    ) -> Union[AgentAction, AgentFinish]:
        """Given input, decided what to do.
        Args:
            intermediate_steps: Steps the LLM has taken to date, along with observations
            **kwargs: User inputs.
        Returns:
            Action specifying what tool to use.
        """
        user_input = kwargs["input"]
        agent_scratchpad = _format_intermediate_steps(intermediate_steps)
        memory = kwargs["memory"]
        prompt = self.prompt.format_prompt(
            input=user_input, agent_scratchpad=agent_scratchpad, memory=memory
        )
        messages = prompt.to_messages()
        predicted_message = self.llm.predict_messages(
            messages, functions=self.functions, callbacks=callbacks
        )
        agent_decision = _parse_ai_message(predicted_message)
        return agent_decision
```


And these are the console outputs with `langchain.debug = true`:

```
Prompt:  input_variables=['memory', 'agent_scratchpad', 'input'] output_parser=None partial_variables={} 
messages=[SystemMessage(content='You are a helpful AI assistant.', additional_kwargs={}), MessagesPlaceholder(variable_name='memory'), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], output_parser=None, partial_variables={}, template='{input}', template_format='f-string', validate_template=True), additional_kwargs={}), MessagesPlaceholder(variable_name='agent_scratchpad')]
[chain/start] [1:chain:AgentExecutor] Entering Chain run with input:
{
  "input": "write a text file to my desktop",
  "memory": []
}
[llm/start] [1:chain:AgentExecutor > 2:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: You are a helpful AI assistant.\nHuman: write a text file to my desktop"
  ]
}
[llm/end] [1:chain:AgentExecutor > 2:llm:ChatOpenAI] [3.00s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "",
        "generation_info": null,
        "message": {
          "content": "",
          "additional_kwargs": {
            "function_call": {
              "name": "tool_selection",
              "arguments": "{\n  \"actions\": [\n    {\n      \"action_name\": \"write_file\",\n      \"action\": {\n        \"file_path\": \"~/Desktop/my_file.txt\",\n        \"text\": \"This is the content of my file.\"\n      }\n    }\n  ]\n}"
            }
          },
          "example": false
        }
      }
    ]
  ],
  "llm_output": null,
  "run": null
}
[tool/start] [1:chain:AgentExecutor > 3:tool:invalid_tool] Entering Tool run with input:
"tool_selection"
[tool/end] [1:chain:AgentExecutor > 3:tool:invalid_tool] [0.0ms] Exiting Tool run with output:
"tool_selection is not a valid tool, try another one."
[llm/start] [1:chain:AgentExecutor > 4:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: You are a helpful AI assistant.\nHuman: write a text file to my desktop\nAI: {'name': 'tool_selection', 'arguments': '{\\n  \"actions\": [\\n    {\\n      \"action_name\": \"write_file\",\\n      \"action\": {\\n        \"file_path\": \"~/Desktop/my_file.txt\",\\n        \"text\": \"This is the content of my file.\"\\n      }\\n    }\\n  ]\\n}'}\nFunction: tool_selection is not a valid tool, try another one."
  ]
}
[llm/end] [1:chain:AgentExecutor > 4:llm:ChatOpenAI] [2.42s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "",
        "generation_info": null,
        "message": {
          "content": "",
          "additional_kwargs": {
            "function_call": {
              "name": "tool_selection",
              "arguments": "{\n  \"actions\": [\n    {\n      \"action_name\": \"write_file\",\n      \"action\": {\n        \"file_path\": \"~/Desktop/my_file.txt\",\n        \"text\": \"This is the content of my file.\"\n      }\n    }\n  ]\n}"
            }
          },
          "example": false
        }
      }
    ]
  ],
  "llm_output": null,
  "run": null
}
[tool/start] [1:chain:AgentExecutor > 5:tool:invalid_tool] Entering Tool run with input:
"tool_selection"
[tool/end] [1:chain:AgentExecutor > 5:tool:invalid_tool] [0.0ms] Exiting Tool run with output:
"tool_selection is not a valid tool, try another one."
[llm/start] [1:chain:AgentExecutor > 6:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: You are a helpful AI assistant.\nHuman: write a text file to my desktop\nAI: {'name': 'tool_selection', 'arguments': '{\\n  \"actions\": [\\n    {\\n      \"action_name\": \"write_file\",\\n      \"action\": {\\n        \"file_path\": \"~/Desktop/my_file.txt\",\\n        \"text\": \"This is the content of my file.\"\\n      }\\n    }\\n  ]\\n}'}\nFunction: tool_selection is not a valid tool, try another one.\nAI: {'name': 'tool_selection', 'arguments': '{\\n  \"actions\": [\\n    {\\n      \"action_name\": \"write_file\",\\n      \"action\": {\\n        \"file_path\": \"~/Desktop/my_file.txt\",\\n        \"text\": \"This is the content of my file.\"\\n      }\\n    }\\n  ]\\n}'}\nFunction: tool_selection is not a valid tool, try another one."
  ]
}
[llm/end] [1:chain:AgentExecutor > 6:llm:ChatOpenAI] [2.35s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "",
        "generation_info": null,
        "message": {
          "content": "",
          "additional_kwargs": {
            "function_call": {
              "name": "tool_selection",
              "arguments": "{\n  \"actions\": [\n    {\n      \"action_name\": \"write_file\",\n      \"action\": {\n        \"file_path\": \"~/Desktop/my_file.txt\",\n        \"text\": \"This is the content of my file.\"\n      }\n    }\n  ]\n}"
            }
          },
          "example": false
        }
      }
    ]
  ],
  "llm_output": null,
  "run": null
}
2023-06-27 11:07:24 - Error in ChainlitCallbackHandler.on_tool_start callback: Task stopped by user       
[chain/error] [1:chain:AgentExecutor] [7.86s] Chain run errored with error:
"InterruptedError('Task stopped by user')"

```


Langchain Plus run: https://www.langchain.plus/public/b6c08e7e-bdb0-4792-a291-545e055ad966/r


### Suggestion:

_No response_