Skip to content

Commit 2cb78ea

Browse files
fix and unify devui samples (#5025)
1 parent cee0a45 commit 2cb78ea

28 files changed

Lines changed: 169 additions & 217 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Shared configuration for samples/02-agents/devui
2+
# Used by in_memory_mode.py, main.py, and as a fallback for discovered samples.
3+
# Run `az login` before starting Azure-backed samples.
4+
5+
# Microsoft Foundry samples
6+
FOUNDRY_PROJECT_ENDPOINT=https://your-project.services.ai.azure.com
7+
FOUNDRY_MODEL=gpt-4o
8+
9+
# Azure OpenAI workflow sample
10+
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
11+
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME=gpt-4o
12+
# Optional fallback env name also supported by workflow_with_agents/workflow.py:
13+
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o
14+
# Optional if you need to override the default API version:
15+
AZURE_OPENAI_API_VERSION=2024-10-21

python/samples/02-agents/devui/README.md

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,76 +16,124 @@ DevUI is a sample application that provides:
1616
1717
## Quick Start
1818

19-
### Option 1: In-Memory Mode (Simplest)
19+
### Option 1: In-Memory Mode (Programmatic Registration)
2020

21-
Run a single sample directly. This demonstrates how to wrap agents and workflows programmatically without needing a directory structure:
21+
Run a single sample directly. This demonstrates how to register agents and workflows in code without using DevUI's directory discovery.
22+
23+
This sample uses Azure AI Foundry. Before running it:
24+
25+
1. Copy `.env.example` in this folder to `.env`, or export the same values in your shell
26+
2. Set `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_MODEL`
27+
3. Run `az login`
28+
29+
Then start the sample:
2230

2331
```bash
2432
cd python/samples/02-agents/devui
2533
python in_memory_mode.py
2634
```
2735

28-
This opens your browser at http://localhost:8090 with pre-configured agents and a basic workflow.
36+
This opens your browser at http://localhost:8090 with two Foundry-backed agents and a simple text transformation workflow.
2937

30-
### Option 2: Directory Discovery
38+
### Option 2: Directory Discovery with Shared Root `.env`
3139

32-
Launch DevUI to discover all samples in this folder:
40+
Run the folder-level launcher to load `samples/02-agents/devui/.env` and then start DevUI with directory discovery for this folder:
3341

3442
```bash
3543
cd python/samples/02-agents/devui
36-
devui
44+
python main.py
3745
```
3846

39-
This starts the server at http://localhost:8080 with all agents and workflows available.
47+
This starts the server at http://localhost:8080 with all discoverable agents and workflows available. The root `.env` acts as shared fallback configuration for discovered samples.
48+
49+
### Option 3: Directory Discovery with the `devui` CLI
50+
51+
If you prefer the CLI directly, you can still launch DevUI from this folder:
52+
53+
```bash
54+
cd python/samples/02-agents/devui
55+
devui .
56+
```
57+
58+
DevUI discovery checks for a sample-specific `.env` first and then falls back to `.env` in `samples/02-agents/devui/`.
4059

4160
## Sample Structure
4261

43-
Each agent/workflow follows a strict structure required by DevUI's discovery system:
62+
DevUI discovers samples from Python packages that export either `agent` or `workflow`.
63+
64+
Typical agent layout:
4465

4566
```
4667
agent_name/
47-
├── __init__.py # Must export: agent = Agent(...)
68+
├── __init__.py # Must export: agent = ...
4869
├── agent.py # Agent implementation
49-
└── .env.example # Example environment variables
70+
└── .env.example # Optional example environment variables
71+
```
72+
73+
Typical workflow layout:
74+
75+
```
76+
workflow_name/
77+
├── __init__.py # Must export: workflow = ...
78+
├── workflow.py # Workflow implementation
79+
├── workflow.yaml # Optional declarative definition
80+
└── .env.example # Optional example environment variables
5081
```
5182

5283
## Available Samples
5384

5485
### Agents
5586

56-
| Sample | Description | Features | Required Environment Variables |
57-
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
58-
| [**weather_agent_azure/**](weather_agent_azure/) | Weather agent using Azure OpenAI with API key authentication | Azure OpenAI integration, function calling, mock weather tools | `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_DEPLOYMENT_NAME`, `AZURE_OPENAI_ENDPOINT` |
59-
| [**foundry_agent/**](foundry_agent/) | Weather agent using Azure AI Agent (Foundry) with Azure CLI authentication (run `az login` first) | Azure AI Agent integration, Azure CLI authentication, mock weather tools | `FOUNDRY_PROJECT_ENDPOINT`, `FOUNDRY_MODEL` |
87+
| Sample | What it demonstrates | Required keys / auth |
88+
| ------ | -------------------- | -------------------- |
89+
| [**agent_weather/**](agent_weather/) | A richer Foundry-backed weather agent that shows chat middleware, function middleware, tool calling, and an approval-required tool alongside auto-approved tools. | `FOUNDRY_PROJECT_ENDPOINT`, `FOUNDRY_MODEL`, plus Azure CLI auth via `az login` |
90+
| [**agent_foundry/**](agent_foundry/) | A minimal Foundry-backed weather agent with current weather and forecast tools. Use this when you want the smallest possible directory-discovered agent sample. | `FOUNDRY_PROJECT_ENDPOINT`, `FOUNDRY_MODEL`, plus Azure CLI auth via `az login` |
6091

6192
### Workflows
6293

63-
| Sample | Description | Features | Required Environment Variables |
64-
| -------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
65-
| [**declarative/**](declarative/) | Declarative YAML workflow with conditional branching | YAML-based workflow definition, conditional logic, no Python code required | None - uses mock data |
66-
| [**workflow_agents/**](workflow_agents/) | Content review workflow with agents as executors | Agents as workflow nodes, conditional routing based on structured outputs, quality-based paths (Writer -> Reviewer -> Editor/Publisher) | `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_DEPLOYMENT_NAME`, `AZURE_OPENAI_ENDPOINT` |
67-
| [**spam_workflow/**](spam_workflow/) | 5-step email spam detection workflow with branching logic | Sequential execution, conditional branching (spam vs. legitimate), multiple executors, mock spam detection | None - uses mock data |
68-
| [**fanout_workflow/**](fanout_workflow/) | Advanced data processing workflow with parallel execution | Fan-out/fan-in patterns, complex state management, multi-stage processing (validation -> transformation -> quality assurance) | None - uses mock data |
94+
| Sample | What it demonstrates | Required keys / auth |
95+
| ------ | -------------------- | -------------------- |
96+
| [**workflow_declarative/**](workflow_declarative/) | A YAML-defined workflow loaded through `WorkflowFactory`, with nested age-based branching and no model client code. | None |
97+
| [**workflow_with_agents/**](workflow_with_agents/) | A content review workflow that uses agents as executors and routes based on structured review output (`Writer -> Reviewer -> Editor/Publisher -> Summarizer`). | `AZURE_OPENAI_ENDPOINT`, plus `AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME` or `AZURE_OPENAI_DEPLOYMENT_NAME`; Azure CLI auth via `az login`; `AZURE_OPENAI_API_VERSION` is optional |
98+
| [**workflow_spam/**](workflow_spam/) | A multi-step spam detection workflow with human-in-the-loop approval, branching for spam vs. legitimate messages, and a final reporting step. | None |
99+
| [**workflow_fanout/**](workflow_fanout/) | A larger fan-out/fan-in data processing workflow with parallel validation, multiple transformations, QA, aggregation, and demo failure toggles. | None |
69100

70101
### Standalone Examples
71102

72-
| Sample | Description | Features |
73-
| ------------------------------------------ | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
74-
| [**in_memory_mode.py**](in_memory_mode.py) | Demonstrates programmatic entity registration without directory structure | In-memory agent and workflow registration, multiple entities served from a single file, includes basic workflow, simplest way to get started |
103+
| Sample | What it demonstrates | Required keys / auth |
104+
| ------ | -------------------- | -------------------- |
105+
| [**in_memory_mode.py**](in_memory_mode.py) | Registers multiple entities directly in Python: two Foundry-backed agents plus a simple workflow, all served from one file without directory discovery. | `FOUNDRY_PROJECT_ENDPOINT`, `FOUNDRY_MODEL`, plus Azure CLI auth via `az login` |
75106

76107
## Environment Variables
77108

78-
Each sample that requires API keys includes a `.env.example` file. To use:
109+
For samples that require external services:
110+
111+
1. Copy `.env.example` to `.env`
112+
2. Fill in the required values
113+
3. Run `az login` for samples that use Azure CLI authentication
79114

80-
1. Copy `.env.example` to `.env` in the same directory
81-
2. Fill in your actual API keys
82-
3. DevUI automatically loads `.env` files from entity directories
115+
Directory discovery checks `.env` files in this order:
116+
117+
1. The entity directory itself, for example `agent_weather/.env`
118+
2. The root DevUI samples folder, `samples/02-agents/devui/.env`
119+
120+
That means the root `.env.example` can hold shared defaults for multiple samples, while a sample-specific `.env` can override those values when needed.
121+
122+
`in_memory_mode.py` and `main.py` both load `.env` from `samples/02-agents/devui/`, so the root `.env.example` in this folder is the right starting point for both commands.
83123

84124
Alternatively, set environment variables globally:
85125

86126
```bash
87-
export OPENAI_API_KEY="your-key-here"
88-
export OPENAI_CHAT_MODEL="gpt-4o"
127+
# Foundry-backed samples
128+
export FOUNDRY_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com"
129+
export FOUNDRY_MODEL="gpt-4o"
130+
131+
# Azure OpenAI workflow_with_agents sample
132+
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
133+
export AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME="gpt-4o"
134+
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o"
135+
136+
az login
89137
```
90138

91139
## Using DevUI with Your Own Agents
@@ -145,7 +193,7 @@ curl http://localhost:8080/v1/entities
145193

146194
## Troubleshooting
147195

148-
**Missing API keys**: Check your `.env` files or environment variables.
196+
**Missing credentials or settings**: Check your `.env` files, confirm the required variables for the sample you are running, and make sure `az login` has completed for Azure-authenticated samples.
149197

150198
**Import errors**: Make sure you've installed the devui package:
151199

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Azure AI Foundry Configuration
2+
# Make sure to run 'az login' before starting devui
3+
4+
FOUNDRY_PROJECT_ENDPOINT=https://your-project.services.ai.azure.com
5+
FOUNDRY_MODEL=gpt-4o

python/samples/02-agents/devui/foundry_agent/__init__.py renamed to python/samples/02-agents/devui/agent_foundry/__init__.py

File renamed without changes.

python/samples/02-agents/devui/foundry_agent/agent.py renamed to python/samples/02-agents/devui/agent_foundry/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def get_forecast(
5353
name="FoundryWeatherAgent",
5454
client=FoundryChatClient(
5555
project_endpoint=os.environ.get("FOUNDRY_PROJECT_ENDPOINT"),
56-
model_model=os.environ.get("FOUNDRY_MODEL"),
56+
model=os.environ.get("FOUNDRY_MODEL"),
5757
credential=AzureCliCredential(),
5858
),
5959
instructions="""
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Azure AI Foundry Configuration
2+
# Make sure to run 'az login' before starting devui
3+
4+
FOUNDRY_PROJECT_ENDPOINT=https://your-project.services.ai.azure.com
5+
FOUNDRY_MODEL=gpt-4o

python/samples/02-agents/devui/weather_agent_azure/__init__.py renamed to python/samples/02-agents/devui/agent_weather/__init__.py

File renamed without changes.

python/samples/02-agents/devui/weather_agent_azure/agent.py renamed to python/samples/02-agents/devui/agent_weather/agent.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
)
2323
from agent_framework.foundry import FoundryChatClient
2424
from agent_framework_devui import register_cleanup
25+
from azure.identity.aio import AzureCliCredential
2526
from dotenv import load_dotenv
2627

2728
# Load environment variables from .env file
@@ -145,15 +146,17 @@ def send_email(
145146

146147
# Agent instance following Agent Framework conventions
147148
agent = Agent(
148-
name="AzureWeatherAgent",
149+
name="WeatherAgent",
149150
description="A helpful agent that provides weather information and forecasts",
150151
instructions="""
151152
You are a weather assistant. You can provide current weather information
152153
and forecasts for any location. Always be helpful and provide detailed
153154
weather information when asked.
154155
""",
155156
client=FoundryChatClient(
156-
api_key=os.environ.get("AZURE_OPENAI_API_KEY", ""),
157+
project_endpoint=os.environ.get("FOUNDRY_PROJECT_ENDPOINT"),
158+
model=os.environ.get("FOUNDRY_MODEL"),
159+
credential=AzureCliCredential(),
157160
),
158161
tools=[get_weather, get_forecast, send_email],
159162
middleware=[security_filter_middleware, atlantis_location_filter_middleware],
@@ -164,7 +167,7 @@ def send_email(
164167

165168

166169
def main():
167-
"""Launch the Azure weather agent in DevUI."""
170+
"""Launch the Weather Agent in DevUI."""
168171
import logging
169172

170173
from agent_framework.devui import serve
@@ -173,9 +176,9 @@ def main():
173176
logging.basicConfig(level=logging.INFO, format="%(message)s")
174177
logger = logging.getLogger(__name__)
175178

176-
logger.info("Starting Azure Weather Agent")
179+
logger.info("Starting Weather Agent")
177180
logger.info("Available at: http://localhost:8090")
178-
logger.info("Entity ID: agent_AzureWeatherAgent")
181+
logger.info("Entity ID: agent_WeatherAgent")
179182

180183
# Launch server with the agent
181184
serve(entities=[agent], port=8090, auto_open=True)

python/samples/02-agents/devui/azure_responses_agent/.env.example

Lines changed: 0 additions & 15 deletions
This file was deleted.

python/samples/02-agents/devui/azure_responses_agent/__init__.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)