> ## Documentation Index
> Fetch the complete documentation index at: https://genai.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 2. Agent ReAct Chat

> Build structured chat agents capable of holding conversation history and using multiple tools

In this section, you will build an interactive structured chat agent using `create_structured_chat_agent` and integrate `ConversationBufferMemory` to maintain context over a multi-turn conversation.

## Objectives

1. Configure structured chat agents that accept multiple parameters and roles.
2. Integrate memory buffer contexts to enable conversational chat history.
3. Manage interactive shell input loops to query the bot.

## Implementation Plan

#### Goal

Create a conversational ReAct agent with access to Wikipedia and Time tools, preserving chat memory context across interactions in a conversational loop.

#### Sample Input

```python theme={null}
"User: Who was Albert Einstein?"
"User: What time is it?"
```

#### Sample Output

An interactive bot response answering the questions.

#### Plan

1. Define a tool function `search_wikipedia` that fetches summaries using the `wikipedia` Python package.
2. Initialize tools mapping `Time` and `Wikipedia` to their respective helper functions.
3. Pull the JSON structured chat prompt template `hwchase17/structured-chat-agent` from the hub.
4. Set up a `ConversationBufferMemory` object configured to return message objects under the key `chat_history`.
5. Create the structured chat agent using `create_structured_chat_agent` and construct an `AgentExecutor` with memory.
6. Populate the initial assistant instructions and build an interactive chat loop that registers user input and agent responses.

## Step-by-Step Implementation

### Step 1: Define Tools

We define functions for searching Wikipedia (limiting results to two sentences) and getting the current system time.

```python theme={null}
def get_current_time(*args, **kwargs):
    """Returns the current time in H:MM AM/PM format."""
    import datetime
    now = datetime.datetime.now()
    return now.strftime("%I:%M %p")

def search_wikipedia(query):
    """Searches Wikipedia and returns the summary of the first result."""
    from wikipedia import summary
    try:
        return summary(query, sentences=2)
    except:
        return "I couldn't find any information on that."

from langchain_core.tools import Tool

tools = [
    Tool(
        name="Time",
        func=get_current_time,
        description="Useful for when you need to know the current time.",
    ),
    Tool(
        name="Wikipedia",
        func=search_wikipedia,
        description="Useful for when you need to know information about a topic.",
    ),
]
```

### Step 2: Configure Memory and Structured Agent

We pull the prompt designed for structured chat models and initialize the conversation memory buffer.

```python theme={null}
from langchain import hub
from langchain.agents import create_structured_chat_agent
from langchain.memory import ConversationBufferMemory
from langchain.chat_models import init_chat_model

prompt = hub.pull("hwchase17/structured-chat-agent")
llm = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")

memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
agent = create_structured_chat_agent(llm=llm, tools=tools, prompt=prompt)
```

### Step 3: Initialize Executor and Loop

We wrap the agent in the executor, set system instructions, and handle the interaction loop.

```python theme={null}
from langchain.agents import AgentExecutor
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent,
    tools=tools,
    verbose=True,
    memory=memory,
    handle_parsing_errors=True,
)

initial_message = "You are an AI assistant that can provide helpful answers using available tools."
memory.chat_memory.add_message(SystemMessage(content=initial_message))

# Interactive chat loop snippet
# user_input = input("User: ")
# memory.chat_memory.add_message(HumanMessage(content=user_input))
# response = agent_executor.invoke({"input": user_input})
# memory.chat_memory.add_message(AIMessage(content=response["output"]))
```

## Complete Combined Code

Below is the complete, consolidated Python script uniting all of the steps above:

```python theme={null}
from dotenv import load_dotenv
from langchain import hub
from langchain.agents import AgentExecutor, create_structured_chat_agent
from langchain.memory import ConversationBufferMemory
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_core.tools import Tool
from langchain.chat_models import init_chat_model

# Load environment variables from .env file
load_dotenv()


# Define Tools
def get_current_time(*args, **kwargs):
    """Returns the current time in H:MM AM/PM format."""
    import datetime

    now = datetime.datetime.now()
    return now.strftime("%I:%M %p")


def search_wikipedia(query):
    """Searches Wikipedia and returns the summary of the first result."""
    from wikipedia import summary

    try:
        # Limit to two sentences for brevity
        return summary(query, sentences=2)
    except:
        return "I couldn't find any information on that."


# Define the tools that the agent can use
tools = [
    Tool(
        name="Time",
        func=get_current_time,
        description="Useful for when you need to know the current time.",
    ),
    Tool(
        name="Wikipedia",
        func=search_wikipedia,
        description="Useful for when you need to know information about a topic.",
    ),
]

# Load the correct JSON Chat Prompt from the hub
prompt = hub.pull("hwchase17/structured-chat-agent")

# Initialize a Groq model using core abstractions
llm = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")

# Create a structured Chat Agent with Conversation Buffer Memory
memory = ConversationBufferMemory(
    memory_key="chat_history", return_messages=True)

# create_structured_chat_agent initializes a chat agent designed to interact using a structured prompt and tools
agent = create_structured_chat_agent(llm=llm, tools=tools, prompt=prompt)

# AgentExecutor is responsible for managing the interaction between the user input, the agent, and the tools
agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent,
    tools=tools,
    verbose=True,
    memory=memory,  # Use the conversation memory to maintain context
    handle_parsing_errors=True,  # Handle any parsing errors gracefully
)

# Initial system message to set the context for the chat
initial_message = "You are an AI assistant that can provide helpful answers using available tools.\nIf you are unable to answer, you can use the following tools: Time and Wikipedia."
memory.chat_memory.add_message(SystemMessage(content=initial_message))

# Chat Loop to interact with the user
while True:
    user_input = input("User: ")
    if user_input.lower() == "exit":
        break

    # Add the user's message to the conversation memory
    memory.chat_memory.add_message(HumanMessage(content=user_input))

    # Invoke the agent with the user input and the current chat history
    response = agent_executor.invoke({"input": user_input})
    print("Bot:", response["output"])

    # Add the agent's response to the conversation memory
    memory.chat_memory.add_message(AIMessage(content=response["output"]))
```

## Practice & Exercises

To practice setting up chat agents with memory, open the interactive notebook:

<CardGroup cols={1}>
  <Card title="Practice & Exercises" icon="laptop-code">
    Practice initializing structured chat agents and managing ConversationBufferMemory.

    [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/GenAI%20With%20Python/public/notebooks/langchain/2_agent_react_chat.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/master/public/notebooks/langchain/2_agent_react_chat.ipynb) | <a href="/public/notebooks/langchain/2_agent_react_chat.ipynb" download>📥 Download</a>
  </Card>
</CardGroup>
