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
42 changes: 42 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Python 3",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:1-3.12",

// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers-extra/features/uv:1": {}
},

// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
"settings": {},
"extensions": [
"streetsidesoftware.code-spell-checker"
]
}
},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [9000],

// Use 'portsAttributes' to set default properties for specific forwarded ports.
// More info: https://containers.dev/implementors/json_reference/#port-attributes
"portsAttributes": {
"9000": {
"label": "Hello Remote World",
"onAutoForward": "notify"
}
},

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip3 install -r requirements.txt"

Copilot AI Sep 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The postCreateCommand references a requirements.txt file, but this PR introduces pyproject.toml for dependency management with UV. This command should be updated to use UV for dependency installation, such as 'uv sync' or removed if not needed.

Suggested change
"postCreateCommand": "pip3 install -r requirements.txt"
"postCreateCommand": "uv sync"

Copilot uses AI. Check for mistakes.

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
216 changes: 216 additions & 0 deletions SETUP_UV.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
![alt text](image-1.png)
# Microsoft AI Agentic Workshop Setup

This document describes how to setup and run your AI Agents for the workshop if you are using UV as your python manager.

## Setup & Installation

### 1. Clone the Repository

Open VS Code terminal

```bash
git clone <repo_url> # from folder where you want clone to reside
```
### 2. Install Python dependencies

With uv, packages are managed through pyproject.toml in the subfolders. Instead of activating a virtual environment, you can use `uv run <python_filename.py>

### 3. Deploy LLM model using Azure AI Foundry

1. Login to ai.azure.com. Create account if you don't already have access to an account.
2. Create project, use new hub is none exists. This will setup a hub, project container, AI services, Storage account and Key Vault
3. Use API Key, Azure OpenAI Service endpoint and Project connection string and add to .env file (next step)
4. On project page, go to Models + endpoints -> Deploy model -> Deploy base model -> gpt-4.1
5. Select deployment type (Standard, Global Standard etc.) and region if desired
6. Customize deployment details to reduce tokens per minute to 10K, disable dynamic quote

### 4. Set up your environment variables and select the agent to run

Rename `.env.sample` to `.env` and fill in all required fields:

```bash
############################################
# Azure OpenAI – chat model configuration #
############################################
# Replace with your model-deployment endpoint in Azure AI Foundry
AZURE_OPENAI_ENDPOINT="https://YOUR-OPENAI-SERVICE-ENDPOINT.openai.azure.com"

# Replace with your Foundry project’s API key
AZURE_OPENAI_API_KEY="YOUR-OPENAI-API-KEY"

# Connection-string that identifies your Foundry project / workspace. Only needed if you're using Azure Agent Service
AZURE_AI_AGENT_PROJECT_CONNECTION_STRING="YOUR-OPENAI-PROJECT-CONNECTION-STRING"

# Model deployment & API version
AZURE_OPENAI_CHAT_DEPLOYMENT="gpt-4.1"
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME="gpt-4.1"
AZURE_OPENAI_API_VERSION="2025-01-01-preview"
OPENAI_MODEL_NAME="gpt-4.1-2025-04-14" #only applicable for Autogen

############################################
# Local URLs for backend & MCP server #
############################################
BACKEND_URL="http://localhost:7000"
MCP_SERVER_URI="http://localhost:8000/mcp"

############################################

############################################
# Agent module to be executed #
############################################
# AGENT_MODULE="agents.autogen.multi_agent.reflection_agent"
# AGENT_MODULE="agents.autogen.single_agent.loop_agent"
# AGENT_MODULE="agents.autogen.multi_agent.collaborative_multi_agent_round_robin"
# AGENT_MODULE="agents.autogen.multi_agent.collaborative_multi_agent_selector_group"
# AGENT_MODULE="agents.autogen.multi_agent.handoff_multi_agent_domain"
# AGENT_MODULE="agents.semantic_kernel.multi_agent.collaborative_multi_agent"
# AGENT_MODULE="agents.semantic_kernel.multi_agent.a2a.collaborative_multi_agent"
AGENT_MODULE="agents.autogen.single_agent.loop_agent"

# -----------------------------------------------------------
# If you are experimenting with Logistics-A2A, uncomment:
# LOGISTIC_MCP_SERVER_URI="http://localhost:8100/sse"
# LOGISTICS_A2A_URL="http://localhost:9100"
# -----------------------------------------------------------


#############################################################
# Cosmos DB – state persistence settings #
#############################################################
# Endpoint for your Cosmos DB account (SQL API)
COSMOSDB_ENDPOINT="https://YOUR-COSMOS-ACCOUNT.documents.azure.com:443/"

# --------- Choose ONE authentication method --------------
# (1) Account key
#COSMOSDB_KEY="YOUR-COSMOS-ACCOUNT-KEY"

# (2) Azure AD service-principal (preferred in production)
#AAD_CLIENT_ID="00000000-0000-0000-0000-000000000000"
#AAD_CLIENT_SECRET="YOUR-AAD-CLIENT-SECRET"
#AAD_TENANT_ID="11111111-1111-1111-1111-111111111111"
# -----------------------------------------------------------

# Logical (application) tenant for data isolation
# Leave as "default" unless you partition data by customer / org
DATA_TENANT_ID="default"

# Database & container names (created automatically if not present)
COSMOSDB_DB_NAME="ai_state_db"
COSMOSDB_CONTAINER_NAME="state_store"
```

**Note:**
#### Choosing a State Store

- **Do nothing** ➜ the workshop uses an in-memory Python `dict` (fast, but data is lost when the process exits).
- **Fill in the Cosmos variables** ➜ the app automatically switches to an Azure Cosmos DB container with a hierarchical partition-key (`/tenant_id + /id`) so chat history survives restarts and scales across instances.

> If neither `COSMOSDB_KEY` nor the AAD credential set is provided, the code silently falls back to the in-memory store.
> **Important:**
> If you choose Cosmos DB and use Azure AD service-principal authentication, you must grant the service principal a custom role for data plane (read/write) access in Cosmos DB.
> See: [Grant data plane access using custom roles in Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/how-to-grant-data-plane-access?tabs=custom-definition%2Ccsharp&pivots=azure-interface-cli)
>
> Without this role, the application will not be able to access or persist chat history in Cosmos DB using Azure AD authentication.

#### Make sure your Azure resources are configured to use the correct model deployment names, endpoints, and API versions.

---

### 5. Run MCP Server

Navigate to ```agentic_ai/backend_services``` folder, and in terminal window with virtual environment activated, run MCP server

Copilot AI Sep 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references 'agentic_ai/backend_services' folder, but based on the file structure shown in this PR, the MCP service is located in the 'mcp' folder at the project root. This path should be corrected to 'mcp' folder.

Suggested change
Navigate to ```agentic_ai/backend_services``` folder, and in terminal window with virtual environment activated, run MCP server
Navigate to the ```mcp``` folder at the project root, and in a terminal window with virtual environment activated, run the MCP server

Copilot uses AI. Check for mistakes.

```bash
uv run mcp_service.py
# Keep this terminal open; open another terminal for the next step.

```

### 6. Run application
Navigate to ```agentic_ai/applications```

The common backend application runs the agent selected in the .env file and connects to the frontend UI.

### Option 1: Run Both Backend and Frontend Together

```bash
bash run_application.sh

Copilot AI Sep 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references 'run_application.sh' but the actual script created in this PR is named 'run_applications_uv.sh'. The documentation should be updated to reference the correct script name.

Suggested change
bash run_application.sh
bash run_applications_uv.sh

Copilot uses AI. Check for mistakes.
```
This script will start the FastAPI backend (`backend.py`) and the Streamlit frontend (`frontend.py`) simultaneously.

- The backend will listen on [http://localhost:7000](http://localhost:7000).
- The Streamlit user interface will open (usually at [http://localhost:8501](http://localhost:8501)).

### Option 2: Run Backend and Frontend Separately

### 1. Start the FastAPI Backend

```bash
uv run backend.py
# Keep this terminal open; open another terminal for the frontend.
```
The backend will be available at `http://localhost:7000/chat`.

### 2. Start the Streamlit Frontend

```bash
uv run streamlit run frontend.py
```
Navigate to the address Streamlit provides (typically http://localhost:8501) to use the chat interface.
Streamlit should popup a chat window for the Agent in a new Edge tab.

If you successfully completed all the steps, setup is complete and your agent should be running now !

## How It Works

1. **Web UI (Streamlit):**
Users input messages and interact with the assistant. A unique session ID is generated for each chat session.

2. **Backend (FastAPI):**
Receives user prompts, manages the session and in-memory chat history, and retrieves or creates an agent according to the environment setting.

3. **Agent (specified by AGENT_MODULE):**
Processes the input using Azure OpenAI and optional MCP tools. The agent may operate in single, multi-agent, or collaborative modes, depending on configuration.

4. **Chat History:**
Conversation history is stored per session and can be displayed in the frontend or reset as needed.

---

## FastAPI Endpoints

- `POST /chat`
Send a JSON payload with `{ "session_id": ..., "prompt": ... }`. Returns the assistant’s response.

- `POST /reset_session`
Send a payload `{ "session_id": ... }` to clear the conversation history for that session.

- `GET /history/{session_id}`
Fetches all previous messages for a given session.

---

## Notes & Best Practices

- The current session store uses an in-memory Python dictionary; for production deployments, substitute this with a persistent store such as Redis or a database.
- Ensure secrets in your `.env` file (like API keys) are never committed to version control.
- The MCP server and Azure endpoint URLs must be accessible from the backend.
- To experiment with different agent behaviors, adjust the `AGENT_MODULE` in `.env`.

---

## Credits

- **Microsoft Azure OpenAI Service**
- **MCP Project**
- **AutoGen**


---
## Acknowledgments

- Microsoft Azure OpenAI Service
- MCP Project
- AutoGen
- SDP CSA & SE Team - James Nguyen, Anil Dwarkanath, Nicole Serafino, Claire Rehfuss, Patrick O'Malley, Kirby Repko, Heena Ugale, Aditya Agrawal
2 changes: 1 addition & 1 deletion agentic_ai/applications/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ OPENAI_MODEL_NAME="gpt-4.1-2025-04-14" #this is need for Autogen setting only.
BACKEND_URL="http://localhost:7000"
# If MCP is fronted by APIM, point to the APIM gateway SSE endpoint
MCP_SERVER_URI="https://YOUR-APIM-GATEWAY.azure-api.net/mcp/sse"
# For local (no APIM) dev, use: http://localhost:8000/sse
# For local (no APIM) dev, use: http://localhost:8000/mcp

############################################
# APIM / AAD settings #
Expand Down
1 change: 1 addition & 0 deletions agentic_ai/applications/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
File renamed without changes.
31 changes: 31 additions & 0 deletions agentic_ai/applications/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[project]
name = "applications"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"a2a-sdk>=0.3.7",
"autogen-agentchat==0.7.1",
"autogen-ext[mcp]==0.7.1",
"azure-cosmos==4.9.0",
"chainlit==1.3.2",
"faker==26.0.0",
"fastapi==0.115.12",
"fastmcp==2.7.1",
Comment on lines +14 to +15

Copilot AI Sep 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FastAPI and fastmcp versions in the applications service differ from those in the MCP service (FastAPI 0.116.1, fastmcp 2.12.0). These version mismatches could cause integration issues between the services. Consider standardizing these dependency versions across both services.

Suggested change
"fastapi==0.115.12",
"fastmcp==2.7.1",
"fastapi==0.116.1",
"fastmcp==2.12.0",

Copilot uses AI. Check for mistakes.
"flasgger==0.9.7.1",
"flask==3.0.3",
"httpx==0.28.1",
"mcp==1.12.2",
"msal==1.31.0",
"openai==1.77.0",
"pydantic==2.11.4",
"pyjwt[crypto]==2.9.0",
"python-dotenv==1.1.0",
"requests==2.32.3",
"semantic-kernel==1.35.0",
"streamlit==1.45.0",
"tenacity==8.5.0",
"uvicorn>=0.25.0",
"websockets>=15.0.1",
]
Empty file modified agentic_ai/applications/run_application.sh
100644 → 100755
Empty file.
40 changes: 40 additions & 0 deletions agentic_ai/applications/run_applications_uv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash
# Determine project root
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")

# Set paths relative to project root
MCP_DIR="$PROJECT_ROOT/mcp"
APP_DIR="$PROJECT_ROOT/agentic_ai/applications"
OUTPUT_LOG="$PROJECT_ROOT/logs/output.log"
ERROR_LOG="$PROJECT_ROOT/logs/error.log"

mkdir -p "$PROJECT_ROOT/logs"

# Function to add timestamps and service prefixes
log_with_prefix() {
local service_name="$1"
awk -v service="$service_name" '{print "[" strftime("%Y-%m-%d %H:%M:%S") "] [" service "] " $0; fflush()}'
}

# Start MCP server
echo "Starting MCP server..."
cd "$MCP_DIR"
uv run mcp_service.py 2>&1 | log_with_prefix "MCP" >> $OUTPUT_LOG &
MCP_PID=$!

sleep 5

# Start backend
echo "Starting backend..."
cd "$APP_DIR"
uv run backend.py 2>&1 | log_with_prefix "BACKEND" >> $OUTPUT_LOG &
BACKEND_PID=$!

sleep 5
uv run streamlit run frontend.py 2>&1 | log_with_prefix "FRONTEND" >> $OUTPUT_LOG &
FRONTEND_PID=$!

echo "MCP Server PID: $MCP_PID"
echo "Backend PID: $BACKEND_PID"
echo "Frontend PID: $FRONTEND_PID"
echo "Project root: $PROJECT_ROOT"
Loading