ConversationBufferMemory returns empty string (and not a list) when empty, breaking agents with memory ("should be a list of base messages, got")
Labels: name: area: memory, name: area: agent, name: auto:bug

### System Info

LangChain==0.0.306
Python 3.10.12
(Ubuntu Linux 20.04.6)

### Who can help?

The `ConversationBufferMemory` returns an empty string instead of an empty list when there's nothing stored, which breaks the expectations of the `MessagesPlaceholder` used within the Conversational REACT agent.

Related: https://github.com/langchain-ai/langchain/issues/7365 (where it was commented that changing the loading logic in `ConversationBufferWindowMemory` could break other things).

A possible solution that seems safer (in light of the subsequent type-checking code) could be to default empty strings to empty lists in the `format_messages` method of the `MessagesPlaceholder`, i.e.:

```
class MessagesPlaceholder(BaseMessagePromptTemplate):

    ...

    def format_messages(self, **kwargs: Any) -> List[BaseMessage]:
        value = kwargs[self.variable_name]
        if not value:                       ## <-- ADDED CODE
            value = []                      ## <-- ADDED CODE
        if not isinstance(value, list):
            raise ValueError(...)
        for v in value:
            if not isinstance(v, BaseMessage):
                raise ValueError(...)
        return value

    ...
```

### Information

- [ ] The official example notebooks/scripts
- [X] My own modified scripts

### Related Components

- [ ] LLMs/Chat Models
- [ ] Embedding Models
- [ ] Prompts / Prompt Templates / Prompt Selectors
- [ ] Output Parsers
- [ ] Document Loaders
- [ ] Vector Stores / Retrievers
- [X] Memory
- [X] Agents / Agent Executors
- [ ] Tools / Toolkits
- [ ] Chains
- [ ] Callbacks/Tracing
- [ ] Async

### Reproduction

To reproduce the behaviour, make sure you have an OPENAI_API_KEY env var and run the following:

```
# pip install langchain openai
import os

from langchain.memory import ChatMessageHistory, ConversationBufferMemory
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent
from langchain.tools import BaseTool

conversational_memory = ConversationBufferMemory(
    memory_key="chat_history",
    chat_memory=ChatMessageHistory()
)

llm = ChatOpenAI(
    openai_api_key=os.environ['OPENAI_API_KEY'],
    temperature=0,
    model_name="gpt-4"
)

class MyTool(BaseTool):
    name = "yell_loud"
    description = "The tool to yell loud!!!"
    
    def _run(self, query, run_manager=None):
        """Use the tool."""
        return 'WAAAAH!'
    
    async def _arun(self, query, run_manager=None):
        """Use the tool asynchronously."""
        raise NotImplementedError("no async")


agent = initialize_agent(
    agent="chat-conversational-react-description",
    tools=[MyTool()],
    llm=llm,
    max_iterations=5,
    verbose=True,
    memory=conversational_memory,
    early_stopping_method='generate'
)

print(agent.run("Please yell very loud, thank you, and then report the result to me."))

# Will raise:
#       ValueError: variable chat_history should be a list of base messages, got 
# at location:
#       "langchain/prompts/chat.py", line 98, in format_messages
```

### Expected behavior

I would expect the script to not complain when the memory is empty and result in something like the following agent interaction (as I got from the modified `format_messages` tentatively suggested above):

```
$> python agent_script.py


> Entering new AgentExecutor chain...
'''json
{
    "action": "yell_loud",
    "action_input": "Please yell very loud, thank you"
}
'''
Observation: WAAAAH!
Thought:'''json
{
    "action": "Final Answer",
    "action_input": "The response to your last comment was a loud yell, as you requested."
}
'''

> Finished chain.
The response to your last comment was a loud yell, as you requested.
```