Skip to content

Commit 2bde393

Browse files
committed
Upgrade all examples to MAF 1.0.0
Mechanical fixes across 102 English + Spanish example files: - model_id= → model= in all OpenAIChatClient constructors - Message(text=...) → Message(contents=[...]) - BaseContextProvider → ContextProvider - BaseHistoryProvider → HistoryProvider Additional fix for history provider examples: - Removed tools from agent_history_redis.py and agent_history_sqlite.py to work around Responses API duplicate item ID issue with history providers (microsoft/agent-framework#3295) Added manual test plan to AGENTS.md. All examples verified with live LLM calls against Azure OpenAI. Ran pre-commit (ruff lint + format).
1 parent 51760e4 commit 2bde393

94 files changed

Lines changed: 3814 additions & 3522 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/prompts/update_translations.prompt.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ description: Use this prompt to update the Spanish translations in the repo.
44
model: GPT-5.2 (copilot)
55
---
66

7-
Update the Spanish translations in the repo according to the guidelines in AGENTS.md. Ensure there are spanish equivalents of each english example. Make sure to keep the translations consistent with the original content and maintain the technical accuracy of the code.
7+
Update the Spanish translations in the repo according to the guidelines in AGENTS.md. Ensure there are spanish equivalents of each english example. Make sure to keep the translations consistent with the original content and maintain the technical accuracy of the code.

AGENTS.md

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The agent-framework GitHub repo is here:
66
https://github.com/microsoft/agent-framework
77
It contains both Python and .NET agent framework code, but we are only using the Python packages in this repo.
88

9-
MAF is changing rapidly still, so we sometimes need to check the repo changelog and issues to see if there are any breaking changes that might affect our code.
9+
MAF is changing rapidly still, so we sometimes need to check the repo changelog and issues to see if there are any breaking changes that might affect our code.
1010
The Python changelog is here:
1111
https://github.com/microsoft/agent-framework/blob/main/python/CHANGELOG.md
1212

@@ -92,3 +92,94 @@ def _on_response_with_body(self, request, response):
9292

9393
HttpLoggingPolicy.on_response = _on_response_with_body
9494
```
95+
96+
## Manual test plan
97+
98+
After upgrading dependencies or making changes across examples, use this plan to verify everything works. Run each example with `uv run python examples/<file>.py`.
99+
100+
### No extra setup (Azure OpenAI only)
101+
102+
These work with just `API_HOST=azure` and the standard `.env` from `azd up`:
103+
104+
| Examples | Notes |
105+
|----------|-------|
106+
| `agent_basic.py` | Interactive chat loop |
107+
| `agent_tool.py`, `agent_tools.py` | Tool calling |
108+
| `agent_session.py` | Session persistence |
109+
| `agent_with_subagent.py`, `agent_without_subagent.py` | Sub-agent patterns |
110+
| `agent_supervisor.py` | Supervisor pattern |
111+
| `agent_middleware.py` | Middleware pipeline |
112+
| `agent_summarization.py` | Summarization middleware |
113+
| `agent_tool_approval.py` | Tool approval |
114+
| `workflow_agents.py`, `workflow_agents_sequential.py`, `workflow_agents_concurrent.py`, `workflow_agents_streaming.py` | Basic workflows |
115+
| `workflow_conditional.py`, `workflow_conditional_state.py`, `workflow_conditional_state_isolated.py`, `workflow_conditional_structured.py` | Conditional workflows |
116+
| `workflow_switch_case.py` | Switch/case workflow |
117+
| `workflow_converge.py`, `workflow_fan_out_fan_in_edges.py` | Converge / fan-out patterns |
118+
| `workflow_aggregator_ranked.py`, `workflow_aggregator_structured.py`, `workflow_aggregator_summary.py`, `workflow_aggregator_voting.py` | Aggregator workflows |
119+
| `workflow_multi_selection_edge_group.py` | Multi-selection edges |
120+
| `workflow_handoffbuilder.py`, `workflow_handoffbuilder_rules.py` | Handoff builder |
121+
| `workflow_hitl_handoff.py`, `workflow_hitl_requests.py`, `workflow_hitl_requests_structured.py`, `workflow_hitl_tool_approval.py` | HITL workflows |
122+
| `workflow_hitl_checkpoint.py` | HITL with file-based checkpoints |
123+
| `agent_knowledge_sqlite.py` | SQLite knowledge provider |
124+
| `agent_history_sqlite.py` | SQLite history provider (no tools — see [agent-framework#3295](https://github.com/microsoft/agent-framework/issues/3295)) |
125+
| `agent_memory_mem0.py` | Mem0 memory provider |
126+
127+
### Requires Redis (dev container)
128+
129+
Redis runs automatically in the dev container at `redis://redis:6379`.
130+
131+
| Examples | Notes |
132+
|----------|-------|
133+
| `agent_history_redis.py` | Redis history provider (no tools — see [agent-framework#3295](https://github.com/microsoft/agent-framework/issues/3295)) |
134+
| `agent_memory_redis.py` | Redis memory provider |
135+
136+
### Requires PostgreSQL (dev container)
137+
138+
PostgreSQL runs automatically in the dev container at `postgresql://admin:LocalPasswordOnly@db:5432/postgres`.
139+
140+
| Examples | Notes |
141+
|----------|-------|
142+
| `agent_knowledge_pg.py` | PG + pgvector knowledge |
143+
| `agent_knowledge_pg_rewrite.py` | PG knowledge with query rewrite |
144+
| `agent_knowledge_postgres.py` | PG knowledge (alternative) |
145+
| `workflow_hitl_checkpoint_pg.py` | HITL with PG-backed checkpoints |
146+
147+
### Requires Azure AI Search
148+
149+
Needs `AZURE_SEARCH_ENDPOINT` and `AZURE_SEARCH_KNOWLEDGE_BASE_NAME` in `.env`.
150+
151+
| Examples | Notes |
152+
|----------|-------|
153+
| `agent_knowledge_aisearch.py` | Azure AI Search knowledge base (agentic mode) |
154+
155+
### Requires MCP server
156+
157+
Start the MCP server first: `uv run python examples/mcp_server.py`
158+
159+
| Examples | Notes |
160+
|----------|-------|
161+
| `agent_mcp_local.py` | Local MCP server (stdio) |
162+
| `agent_mcp_remote.py` | Remote MCP server (SSE) |
163+
164+
### Requires OTel / Aspire
165+
166+
| Examples | Notes |
167+
|----------|-------|
168+
| `agent_otel_aspire.py` | Aspire dashboard (runs in dev container at `http://aspire-dashboard:18888`) |
169+
| `agent_otel_appinsights.py` | Needs `APPLICATIONINSIGHTS_CONNECTION_STRING` in `.env` |
170+
171+
### Slow-running examples (⏱ 2–10 minutes)
172+
173+
These take significantly longer than other examples:
174+
175+
| Examples | Notes |
176+
|----------|-------|
177+
| `agent_evaluation.py` | Runs agent + evaluators inline. ~2–3 min. |
178+
| `agent_evaluation_generate.py` | Generates eval data JSONL. ~2 min. |
179+
| `agent_evaluation_batch.py` | Batch evaluators on JSONL. ~3–5 min. Needs `eval_data.jsonl` from `agent_evaluation_generate.py`. |
180+
| `agent_redteam.py` | Red team attack simulation. ~5–10 min. |
181+
| `workflow_magenticone.py` | Multi-agent MagenticOne orchestration. ~2–5 min. |
182+
183+
### Spanish examples
184+
185+
Spanish files under `examples/spanish/` mirror the English examples exactly (same code, translated strings). After changes, spot-check 3–5 Spanish files to confirm they run correctly.

examples/agent_evaluation.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,7 @@ async def main():
298298

299299
intent_result = intent_evaluator(query=eval_query, response=eval_response, tool_definitions=tool_definitions)
300300
completeness_result = completeness_evaluator(response=response.text, ground_truth=ground_truth)
301-
adherence_result = adherence_evaluator(
302-
query=eval_query, response=eval_response, tool_definitions=tool_definitions
303-
)
301+
adherence_result = adherence_evaluator(query=eval_query, response=eval_response, tool_definitions=tool_definitions)
304302
tool_accuracy_result = tool_accuracy_evaluator(
305303
query=eval_query, response=eval_response, tool_definitions=tool_definitions
306304
)

examples/agent_evaluation_batch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import os
1414
from pathlib import Path
1515

16+
import rich
1617
from azure.ai.evaluation import (
1718
AzureOpenAIModelConfiguration,
1819
IntentResolutionEvaluator,
@@ -23,7 +24,6 @@
2324
evaluate,
2425
)
2526
from dotenv import load_dotenv
26-
import rich
2727
from rich.logging import RichHandler
2828
from rich.table import Table
2929

examples/agent_evaluation_generate.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
from agent_framework import Agent, tool
1818
from agent_framework.openai import OpenAIChatClient
19-
from azure.ai.evaluation import AzureOpenAIModelConfiguration, OpenAIModelConfiguration
2019
from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider
2120
from dotenv import load_dotenv
2221
from pydantic import Field

examples/agent_history_redis.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ async def main() -> None:
9999
except Exception as e:
100100
logger.error(f"Cannot connect to Redis at {REDIS_URL}: {e}")
101101
logger.error(
102-
"Ensure Redis is running (e.g. via the dev container"
103-
" or 'docker run -p 6379:6379 redis:7-alpine')."
102+
"Ensure Redis is running (e.g. via the dev container" " or 'docker run -p 6379:6379 redis:7-alpine')."
104103
)
105104
return
106105
finally:

examples/agent_knowledge_aisearch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
context_providers=[search_provider],
107107
)
108108

109+
109110
async def main() -> None:
110111
"""Demonstrate Azure AI Search RAG in a multi-turn conversation."""
111112
async with search_provider:

examples/agent_knowledge_pg.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,14 @@
3232
from typing import Any
3333

3434
import psycopg
35-
from openai import OpenAI
36-
from pgvector.psycopg import register_vector
37-
3835
from agent_framework import Agent, AgentSession, ContextProvider, Message, SessionContext, SupportsAgentRun
3936
from agent_framework.openai import OpenAIChatClient
4037
from azure.identity import DefaultAzureCredential as SyncDefaultAzureCredential
4138
from azure.identity import get_bearer_token_provider as sync_get_bearer_token_provider
4239
from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider
4340
from dotenv import load_dotenv
41+
from openai import OpenAI
42+
from pgvector.psycopg import register_vector
4443
from rich import print
4544
from rich.logging import RichHandler
4645

@@ -63,7 +62,9 @@
6362
async_token_provider = get_bearer_token_provider(async_credential, "https://cognitiveservices.azure.com/.default")
6463
# Sync credential for the OpenAI SDK embed client
6564
sync_credential = SyncDefaultAzureCredential()
66-
sync_token_provider = sync_get_bearer_token_provider(sync_credential, "https://cognitiveservices.azure.com/.default")
65+
sync_token_provider = sync_get_bearer_token_provider(
66+
sync_credential, "https://cognitiveservices.azure.com/.default"
67+
)
6768
chat_client = OpenAIChatClient(
6869
base_url=f"{os.environ['AZURE_OPENAI_ENDPOINT']}/openai/v1/",
6970
api_key=async_token_provider,
@@ -196,9 +197,7 @@ def create_knowledge_db(conn: psycopg.Connection) -> None:
196197
"""
197198
)
198199
# GIN index for full-text search on name + description
199-
conn.execute(
200-
"CREATE INDEX ON products USING GIN (to_tsvector('english', name || ' ' || description))"
201-
)
200+
conn.execute("CREATE INDEX ON products USING GIN (to_tsvector('english', name || ' ' || description))")
202201

203202
logger.info("[📚 Knowledge] Generating embeddings for %d products...", len(PRODUCTS))
204203
for product in PRODUCTS:

examples/agent_knowledge_pg_rewrite.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,14 @@
3636
from typing import Any
3737

3838
import psycopg
39-
from openai import OpenAI
40-
from pgvector.psycopg import register_vector
41-
4239
from agent_framework import Agent, AgentSession, ContextProvider, Message, SessionContext, SupportsAgentRun
4340
from agent_framework.openai import OpenAIChatClient
4441
from azure.identity import DefaultAzureCredential as SyncDefaultAzureCredential
4542
from azure.identity import get_bearer_token_provider as sync_get_bearer_token_provider
4643
from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider
4744
from dotenv import load_dotenv
45+
from openai import OpenAI
46+
from pgvector.psycopg import register_vector
4847
from rich import print
4948
from rich.logging import RichHandler
5049

@@ -65,7 +64,9 @@
6564
async_credential = DefaultAzureCredential()
6665
async_token_provider = get_bearer_token_provider(async_credential, "https://cognitiveservices.azure.com/.default")
6766
sync_credential = SyncDefaultAzureCredential()
68-
sync_token_provider = sync_get_bearer_token_provider(sync_credential, "https://cognitiveservices.azure.com/.default")
67+
sync_token_provider = sync_get_bearer_token_provider(
68+
sync_credential, "https://cognitiveservices.azure.com/.default"
69+
)
6970
chat_client = OpenAIChatClient(
7071
base_url=f"{os.environ['AZURE_OPENAI_ENDPOINT']}/openai/v1/",
7172
api_key=async_token_provider,
@@ -197,9 +198,7 @@ def create_knowledge_db(conn: psycopg.Connection) -> None:
197198
)
198199
"""
199200
)
200-
conn.execute(
201-
"CREATE INDEX ON products USING GIN (to_tsvector('english', name || ' ' || description))"
202-
)
201+
conn.execute("CREATE INDEX ON products USING GIN (to_tsvector('english', name || ' ' || description))")
203202

204203
logger.info("[📚 Knowledge] Generating embeddings for %d products...", len(PRODUCTS))
205204
for product in PRODUCTS:
@@ -290,9 +289,7 @@ async def _rewrite_query(self, conversation_messages: list[Message]) -> str:
290289
A concise, self-contained search query.
291290
"""
292291
# Format conversation for the rewriter
293-
conversation_text = "\n".join(
294-
f"{msg.role}: {msg.text}" for msg in conversation_messages if msg.text
295-
)
292+
conversation_text = "\n".join(f"{msg.role}: {msg.text}" for msg in conversation_messages if msg.text)
296293

297294
rewrite_messages = [
298295
Message(role="system", contents=[QUERY_REWRITE_PROMPT]),

examples/agent_knowledge_postgres.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,14 @@
3232
from typing import Any
3333

3434
import psycopg
35-
from openai import OpenAI
36-
from pgvector.psycopg import register_vector
37-
3835
from agent_framework import Agent, AgentSession, ContextProvider, Message, SessionContext, SupportsAgentRun
3936
from agent_framework.openai import OpenAIChatClient
4037
from azure.identity import DefaultAzureCredential as SyncDefaultAzureCredential
4138
from azure.identity import get_bearer_token_provider as sync_get_bearer_token_provider
4239
from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider
4340
from dotenv import load_dotenv
41+
from openai import OpenAI
42+
from pgvector.psycopg import register_vector
4443
from rich import print
4544
from rich.logging import RichHandler
4645

@@ -63,7 +62,9 @@
6362
async_token_provider = get_bearer_token_provider(async_credential, "https://cognitiveservices.azure.com/.default")
6463
# Sync credential for the OpenAI SDK embed client
6564
sync_credential = SyncDefaultAzureCredential()
66-
sync_token_provider = sync_get_bearer_token_provider(sync_credential, "https://cognitiveservices.azure.com/.default")
65+
sync_token_provider = sync_get_bearer_token_provider(
66+
sync_credential, "https://cognitiveservices.azure.com/.default"
67+
)
6768
chat_client = OpenAIChatClient(
6869
base_url=f"{os.environ['AZURE_OPENAI_ENDPOINT']}/openai/v1/",
6970
api_key=async_token_provider,
@@ -196,9 +197,7 @@ def create_knowledge_db(conn: psycopg.Connection) -> None:
196197
"""
197198
)
198199
# GIN index for full-text search on name + description
199-
conn.execute(
200-
"CREATE INDEX ON products USING GIN (to_tsvector('english', name || ' ' || description))"
201-
)
200+
conn.execute("CREATE INDEX ON products USING GIN (to_tsvector('english', name || ' ' || description))")
202201

203202
logger.info("[📚 Knowledge] Generating embeddings for %d products...", len(PRODUCTS))
204203
for product in PRODUCTS:
@@ -297,7 +296,9 @@ async def before_run(
297296
state: dict[str, Any],
298297
) -> None:
299298
"""Search the knowledge base with the user's latest message and inject results."""
300-
user_text = next((msg.text for msg in reversed(context.input_messages) if msg.role == "user" and msg.text), None)
299+
user_text = next(
300+
(msg.text for msg in reversed(context.input_messages) if msg.role == "user" and msg.text), None
301+
)
301302
if not user_text:
302303
return
303304

0 commit comments

Comments
 (0)