Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ An intelligent AI agent framework written in Python, designed to facilitate seam
- Configurable via environment variables and JSON configuration files

## Architecture
The project follows a component-based architecture where the AI Agent orchestrates interactions between users, language models, local tools, and MCP servers.

For a detailed view of the architecture including sequence diagrams, component descriptions, and workflow, see [Architecture Documentation](docs/architecture.md).

The codebase follows a modular structure under `src/`:

```
Expand Down
38 changes: 17 additions & 21 deletions src/chat.py → demo/1-chat.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
from utils import set_debug
set_debug(True)

from dotenv import load_dotenv
load_dotenv()

from utils import chatutil, graceful_exit, mainloop
from datetime import date

from utils import chatutil, graceful_exit, mainloop, pretty_print
from utils.azureopenai.chat import Chat

# Initialize the Chat client
chat = Chat.create()

# Define enhanced system role with instructions on using all available tools
system_role = """
system_role = f"""
You are a helpful assistant.
Your Name is Agent Smith.

Use your knowledge to provide comprehensive assistance.
Synthesize and cite your sources correctly.
Whenever you are not sure about something, have a look at the tools available to you.
You can use them to get information or perform tasks.

You have to provide the most up-to-date information.
Synthesize and cite your sources correctly, but keep responses concise.

Today is {date.today().strftime("%d %B %Y")}.
"""

messages = [{"role": "system", "content": system_role}]
Expand All @@ -22,32 +32,18 @@
@graceful_exit
@chatutil("Chat")
async def run_conversation(user_prompt: str) -> str:
"""Run a conversation with the user.

Args:
user_prompt: The user's input prompt.

Returns:
The assistant's response as a string.
"""
messages.append({"role": "user", "content": user_prompt})
response = await chat.send_messages(messages)

# Extract content from response, handling possible errors and edge cases

content = ""
if response:
if isinstance(response, dict) and "choices" in response:
choices = response.get("choices", [])
if choices and len(choices) > 0:
message = choices[0].get("message", {})
content = message.get("content", "")

# Print final response
hr = "\n" + "-" * 50 + "\n"
print(hr, "Response:", hr)
print(response, hr)

return content

pretty_print(" Result ", content)

if __name__ == "__main__":
import asyncio
Expand Down
32 changes: 32 additions & 0 deletions demo/2-tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from utils import pretty_print
from libs.search.service import Service

service = Service.create()
query = "Current chancellor of Germany?"
pretty_print("Query", query)

results = service.search(query, 5)
pretty_print("Results", results)

### FUNC
# {
# "type": "function",
# "function": {
# "name": "google_search",
# "description": "Search the web for relevant information.",
# "parameters": {
# "type": "object",
# "properties": {
# "query": {
# "type": "string",
# "description": "The search query to use"
# },
# "num_results": {
# "type": "number",
# "description": "Number of results to return (default: 5, max: 10)"
# }
# },
# "required": ["query"]
# }
# }
# }
66 changes: 66 additions & 0 deletions demo/3-chat-with-tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from utils import set_debug
set_debug(True)

from dotenv import load_dotenv
load_dotenv()

from datetime import date

from utils import chatutil, graceful_exit, mainloop, pretty_print
from utils.azureopenai.chat import Chat
from utils.azureopenai.client import Client

from tools.write_file import WriteFile
from tools.google_search import GoogleSearch

tools = [
GoogleSearch("google_search"),
WriteFile("write_file"),
]
chat = Chat.create(tools)

# Define enhanced system role with instructions on using all available tools
system_role = f"""
You are a helpful assistant.
Your Name is Agent Smith.

Whenever you are not sure about something, have a look at the tools available to you.
You can use them to get information or perform tasks.

You have to provide the most up-to-date information.
Synthesize and cite your sources correctly, but keep responses concise.

Today is {date.today().strftime("%d %B %Y")}.
"""

messages = [{"role": "system", "content": system_role}]

@mainloop
@graceful_exit
@chatutil("Chat-With-Tools")
async def run_conversation(user_prompt: str) -> str:
messages.append({"role": "user", "content": user_prompt})
response = await chat.send_messages(messages)
choices = response.get("choices", [])

assistant_message = choices[0].get("message", {})
messages.append(assistant_message)

# Handle the case where tool_calls might be missing or not a list
while assistant_message.get("tool_calls"):
await chat.process_tool_calls(assistant_message, messages.append)

response = await chat.send_messages(messages)
if not (response and response.get("choices", None)):
break

assistant_message = response.get("choices", [{}])[0].get("message", {})
messages.append(assistant_message)

result = assistant_message.get("content", "")

pretty_print(" Result ", result)

if __name__ == "__main__":
import asyncio
asyncio.run(run_conversation())
81 changes: 81 additions & 0 deletions demo/4-chat-with-tools-and-mcp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from utils import set_debug
set_debug(True)

from dotenv import load_dotenv
load_dotenv()

import os
import asyncio
from datetime import date

from utils import chatutil, graceful_exit, mainloop, pretty_print
from utils.azureopenai.chat import Chat

from tools.write_file import WriteFile
from tools.google_search import GoogleSearch

from utils.mcpclient.sessions_manager import MCPSessionManager

session_manager = MCPSessionManager()

tools = [
GoogleSearch("google_search"),
WriteFile("write_file"),
]
chat = Chat.create(tools)

# Define enhanced system role with instructions on using all available tools
system_role = f"""
You are a helpful assistant.
Your Name is Agent Smith.

Whenever you are not sure about something, have a look at the tools available to you.
You can use them to get information or perform tasks.

You have to provide the most up-to-date information.
Synthesize and cite your sources correctly, but keep responses concise.

Today is {date.today().strftime("%d %B %Y")}.
"""

messages = [{"role": "system", "content": system_role}]

@graceful_exit
@chatutil("Chat-With-Tools-And-MCP")
async def run_conversation(user_prompt: str) -> str:
messages.append({"role": "user", "content": user_prompt})
response = await chat.send_messages(messages)
choices = response.get("choices", [])

assistant_message = choices[0].get("message", {})
messages.append(assistant_message)

# Handle the case where tool_calls might be missing or not a list
while assistant_message.get("tool_calls"):
await chat.process_tool_calls(assistant_message, messages.append)

response = await chat.send_messages(messages)
if not (response and response.get("choices", None)):
break

assistant_message = response.get("choices", [{}])[0].get("message", {})
messages.append(assistant_message)

result = assistant_message.get("content", "")

pretty_print(" Result ", result)

if __name__ == "__main__":
@mainloop
@graceful_exit
async def agent_task():
await run_conversation()

async def main():
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../config', 'mcp-demo.json')
await session_manager.discovery(path)
for tool in session_manager.tools:
chat.add_tool(tool)

await agent_task()
asyncio.run(main())
114 changes: 114 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# AI Agent Architecture

This document describes the architecture and workflow of the AI Agent application, specifically focusing on the chat-with-tools-and-mcp functionality.

## Sequence Diagram

```mermaid
sequenceDiagram
participant User
participant Agent as AI Agent
participant Azure as GPT-4.1
participant Tools as Local Tools
participant MCP as MCP Server
participant ExternalServices as External Services

%% Initialization Phase
Note over Agent: Initialization
Agent->>Azure: Initialize Client
Agent->>Tools: Initialize Local Tools
Agent->>MCP: Initialize MCP Server
MCP-->>Agent: Return Available Tools

User->>Agent: Send query

%% Query Processing Phase
Note over Agent: Query Processing
Agent->>Azure: Send User Query to Model

%% Decision for Tool Usage
loop Model decides to use tools
Azure-->>Agent: Request Tool Call

%% Tool Execution Phase
Note over Agent: Tool Execution
%% Decision for Tool Usage
alt Local Tool
Agent->>Tools: Use Tool (e.g., google_search)
Tools<<->>ExternalServices: Call External Service (e.g., Google Search API)
Tools-->>Agent: Return Tool Results
else MCP Server Tool
Agent->>MCP: Use Tool (e.g., get_ice_cream_recommendation)
MCP<<->>ExternalServices: Call External Service (e.g. Database)
MCP-->>Agent: Return Tool Results
end

Agent->>Azure: Send Tool Results to Model
end

%% Model generates response
Note over Agent: Response Generation
Azure-->>Agent: Generate Response
Agent-->>User: Return Response to User
```

## Components

1. **User**: Initiates interaction by sending queries to the AI Agent.

2. **AI Agent**: The main application that orchestrates the entire workflow:
- Initializes the Azure OpenAI client
- Discovers and initializes available tools (both local and MCP-based)
- Processes user queries
- Routes tool calls to appropriate services
- Returns final responses to the user

3. **Azure OpenAI Service (GPT-4.1)**: Provides the language model capabilities:
- Processes natural language queries
- Determines when and which tools to call
- Generates final responses based on user queries and tool results

4. **Local Tools**: Built-in tools available to the agent:
- google_search: Searches the web for information
- list_files: Lists files in a directory
- read_file: Reads content from files
- web_fetch: Fetches content from web pages
- write_file: Writes content to files

5. **MCP Server**: Model Context Protocol server that provides additional tools:
- get_ice_cream_recommendation: Provides ice cream flavor recommendations
- Additional tools that may be available depending on server configuration

6. **External Services**: Third-party services called by tools:
- Search engines (for google_search)
- File systems (for file operations)
- Web services (for web_fetch)
- Databases (for MCP tools)
- Other APIs as needed

## Workflow Description

1. **Initialization Phase**:
- The AI Agent initializes connections to Azure OpenAI Service
- Local tools are registered and prepared for use
- The MCP Server connection is established
- Available MCP tools are discovered and registered with the Agent

2. **Query Processing**:
- The user sends a natural language query to the AI Agent
- The Agent passes this query to the Azure OpenAI model (GPT-4.1)
- The model analyzes the query to determine the appropriate response strategy

3. **Tool Selection and Execution**:
- If the model determines tools are needed, it requests specific tool calls
- The Agent evaluates whether the requested tool is local or MCP-based:
- For local tools: The Agent executes the tool directly, which may interact with external services
- For MCP tools: The Agent forwards the request to the MCP Server, which handles execution
- Tool execution results are collected and formatted by the Agent

4. **Response Generation**:
- Tool results are sent back to the Azure OpenAI model
- The model integrates these results with its knowledge to generate a comprehensive response
- The Agent formats and returns the final response to the user

This workflow enables the AI Agent to leverage both built-in capabilities and external tools to provide rich, contextual responses to user queries while maintaining a clean separation of concerns between components.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ cachetools==5.5.2
certifi==2025.4.26
charset-normalizer==3.4.2
click==8.1.8
colorama==0.4.6
coverage==7.8.0
dill==0.4.0
fastapi==0.115.12
Expand Down
Loading