Skip to content

Commit 496daca

Browse files
authored
Merge pull request #382 from MicrosoftDocs/main639105538579596060sync_temp
Repo sync for protected branch
2 parents 8326e34 + 9b12bc8 commit 496daca

66 files changed

Lines changed: 2432 additions & 953 deletions

Some content is hidden

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

agent-framework/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ Every docs page maps to sample files in both repos:
205205
| `agents/tools/local-mcp-tools.md` | `02-agents/tools/local_mcp_tools.py` | `02-agents/tools/LocalMcpTools.cs` |
206206
| `agents/tools/tool-approval.md` | `02-agents/tools/tool_approval.py` | `02-agents/tools/ToolApproval.cs` |
207207
| `agents/middleware/*.md` | `02-agents/middleware/<matching>.py` | `02-agents/middleware/<matching>.cs` |
208+
| `agents/providers/foundry-local.md` | `02-agents/providers/foundry/foundry_local_agent.py` | N/A |
208209
| `agents/providers/*.md` | `02-agents/providers/<matching>.py` | `02-agents/providers/<matching>.cs` |
209210
| `agents/conversations/*.md` | `02-agents/conversations/<matching>.py` | `02-agents/conversations/<matching>.cs` |
210211
| `workflows/<pattern>.md` | `03-workflows/<pattern>/<matching>.py` | `03-workflows/<pattern>/<matching>.cs` |

agent-framework/TOC.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ items:
4040
href: agents/observability.md
4141
- name: Agent Skills
4242
href: agents/skills.md
43+
- name: Agent Safety
44+
href: agents/safety.md
4345
- name: Tools
4446
items:
4547
- name: Overview
@@ -100,6 +102,8 @@ items:
100102
href: agents/providers/openai.md
101103
- name: Microsoft Foundry
102104
href: agents/providers/microsoft-foundry.md
105+
- name: Foundry Local
106+
href: agents/providers/foundry-local.md
103107
- name: Anthropic
104108
href: agents/providers/anthropic.md
105109
- name: Ollama
@@ -152,6 +156,16 @@ items:
152156
href: workflows/orchestrations/group-chat.md
153157
- name: Magentic
154158
href: workflows/orchestrations/magentic.md
159+
- name: Advanced
160+
items:
161+
- name: Agent Executor
162+
href: workflows/advanced/agent-executor.md
163+
- name: Execution Modes
164+
href: workflows/advanced/execution-modes.md
165+
- name: Resettable Executors
166+
href: workflows/advanced/resettable-executors.md
167+
- name: Sub-Workflows
168+
href: workflows/advanced/sub-workflows.md
155169
- name: Integrations
156170
items:
157171
- name: Overview

agent-framework/agents/agent-pipeline.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,12 @@ The `Agent` class accepts any client that implements `SupportsChatGetResponse`.
190190

191191
```python
192192
from agent_framework import Agent
193-
from agent_framework.azure import AzureOpenAIResponsesClient
193+
from agent_framework.foundry import FoundryChatClient
194194

195-
client = AzureOpenAIResponsesClient(
195+
client = FoundryChatClient(
196196
credential=credential,
197197
project_endpoint=endpoint,
198-
deployment_name=model,
198+
model=model,
199199
)
200200

201201
agent = Agent(client=client, instructions="You are helpful.")

agent-framework/agents/background-responses.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,12 @@ For non-streaming scenarios, when you initially run an agent with `background=Tr
172172
```python
173173
import asyncio
174174
from agent_framework import Agent
175-
from agent_framework.openai import OpenAIResponsesClient
175+
from agent_framework.openai import OpenAIChatClient
176176

177177
agent = Agent(
178178
name="researcher",
179179
instructions="You are a helpful research assistant.",
180-
client=OpenAIResponsesClient(model_id="o3"),
180+
client=OpenAIChatClient(model="o3"),
181181
)
182182

183183
session = agent.create_session()

agent-framework/agents/conversations/compaction.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Compaction solves these problems by selectively removing, collapsing, or summari
5959

6060
Compaction applies only to agents that manage their own conversation history in memory. Agents that rely on service-managed context or conversation state do not benefit from compaction because the service already handles context management. Examples of service-managed agents include:
6161

62-
- **Foundry Agents** — context is managed server-side by the Azure AI Foundry service.
62+
- **Foundry Agents** — context is managed server-side by the Microsoft Foundry service.
6363
- **Responses API with store enabled** (the default) — conversation state is stored and managed by the OpenAI service.
6464
- **Copilot Studio agents** — conversation context is maintained by the Copilot Studio service.
6565

@@ -650,7 +650,4 @@ compacted = await apply_compaction(
650650
## Next steps
651651

652652
> [!div class="nextstepaction"]
653-
> [Context Providers](context-providers.md)
654-
655-
> [!div class="nextstepaction"]
656-
> [Storage](storage.md)
653+
> [Middleware](../middleware/index.md)

agent-framework/agents/conversations/storage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,4 @@ resumed = AgentSession.from_dict(serialized)
361361
## Next steps
362362

363363
> [!div class="nextstepaction"]
364-
> [Running Agents](../running-agents.md)
364+
> [Compaction](./compaction.md)

agent-framework/agents/index.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ When using Foundry, Azure OpenAI, OpenAI services, or Anthropic services, you ha
101101
| [Azure OpenAI](/azure/ai-foundry/openai/overview) <sup>1</sup> | Azure OpenAI SDK <sup>2</sup> | [Azure.AI.OpenAI](https://www.nuget.org/packages/Azure.AI.OpenAI) | https://&lt;resource&gt;.openai.azure.com/ |
102102
| [Azure OpenAI](/azure/ai-foundry/openai/overview) <sup>1</sup> | OpenAI SDK | [OpenAI](https://www.nuget.org/packages/OpenAI) | https://&lt;resource&gt;.openai.azure.com/openai/v1/ |
103103
| OpenAI | OpenAI SDK | [OpenAI](https://www.nuget.org/packages/OpenAI) | No url required |
104-
| [Azure AI Foundry Anthropic](/azure/ai-foundry/foundry-models/how-to/use-foundry-models-claude) | Anthropic Foundry SDK | [Anthropic.Foundry](https://www.nuget.org/packages/Anthropic.Foundry) | Resource name required |
104+
| [Microsoft Foundry Anthropic](/azure/ai-foundry/foundry-models/how-to/use-foundry-models-claude) | Anthropic Foundry SDK | [Anthropic.Foundry](https://www.nuget.org/packages/Anthropic.Foundry) | Resource name required |
105105
| Anthropic | Anthropic SDK | [Anthropic](https://www.nuget.org/packages/Anthropic) | No url or resource name required |
106106

107107
1. [Upgrading from Azure OpenAI to Foundry](/azure/ai-foundry/how-to/upgrade-azure-openai)
@@ -169,7 +169,7 @@ AIAgent agent = await persistentAgentsClient.CreateAIAgentAsync(
169169
name: "Joker");
170170
```
171171

172-
### Using the Azure AI Foundry Anthropic SDK
172+
### Using the Foundry Anthropic SDK
173173

174174
The resource is the subdomain name / first name coming before '.services.ai.azure.com' in the endpoint Uri.
175175

@@ -217,29 +217,37 @@ To create one of these agents, simply construct an `Agent` using the chat client
217217
```python
218218
import os
219219
from agent_framework import Agent
220-
from agent_framework.azure import AzureOpenAIResponsesClient
220+
from agent_framework.foundry import FoundryChatClient
221221
from azure.identity.aio import DefaultAzureCredential
222222

223-
Agent(
224-
client=AzureOpenAIResponsesClient(credential=DefaultAzureCredential(), project_endpoint=os.getenv("AZURE_AI_PROJECT_ENDPOINT"), deployment_name=os.getenv("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME")),
225-
instructions="You are a helpful assistant"
226-
) as agent
223+
agent = Agent(
224+
client=FoundryChatClient(
225+
credential=DefaultAzureCredential(),
226+
project_endpoint=os.getenv("AZURE_AI_PROJECT_ENDPOINT"),
227+
model=os.getenv("AZURE_AI_MODEL_DEPLOYMENT_NAME"),
228+
),
229+
instructions="You are a helpful assistant",
230+
)
227231
response = await agent.run("Hello!")
228232
```
229233

230234
Alternatively, you can use the convenience method on the chat client:
231235

232236
```python
233-
from agent_framework.azure import AzureOpenAIResponsesClient
237+
from agent_framework.foundry import FoundryChatClient
234238
from azure.identity.aio import DefaultAzureCredential
235239

236-
agent = AzureOpenAIResponsesClient(credential=DefaultAzureCredential(), project_endpoint=os.getenv("AZURE_AI_PROJECT_ENDPOINT"), deployment_name=os.getenv("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME")).as_agent(
240+
agent = FoundryChatClient(
241+
credential=DefaultAzureCredential(),
242+
project_endpoint=os.getenv("AZURE_AI_PROJECT_ENDPOINT"),
243+
model=os.getenv("AZURE_AI_MODEL_DEPLOYMENT_NAME"),
244+
).as_agent(
237245
instructions="You are a helpful assistant"
238246
)
239247
```
240248

241249
> [!NOTE]
242-
> This example shows using the AzureOpenAIResponsesClient, but the same pattern applies to any chat client that implements `SupportsChatGetResponse`, see [providers overview](./providers/index.md) for more details on other clients.
250+
> This example shows using the FoundryChatClient, but the same pattern applies to any chat client that implements `SupportsChatGetResponse`, see [providers overview](./providers/index.md) for more details on other clients.
243251
244252
For detailed examples, see the agent-specific documentation sections below.
245253

@@ -293,17 +301,17 @@ You can provide function tools to agents for enhanced capabilities:
293301
import os
294302
from typing import Annotated
295303
from azure.identity.aio import DefaultAzureCredential
296-
from agent_framework.azure import AzureOpenAIResponsesClient
304+
from agent_framework.foundry import FoundryChatClient
297305

298306
def get_weather(location: Annotated[str, "The location to get the weather for."]) -> str:
299307
"""Get the weather for a given location."""
300308
return f"The weather in {location} is sunny with a high of 25°C."
301309

302310
async with DefaultAzureCredential() as credential:
303-
agent = AzureOpenAIResponsesClient(
311+
agent = FoundryChatClient(
304312
credential=credential,
305313
project_endpoint=os.getenv("AZURE_AI_PROJECT_ENDPOINT"),
306-
deployment_name=os.getenv("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"),
314+
model=os.getenv("AZURE_AI_MODEL_DEPLOYMENT_NAME"),
307315
).as_agent(
308316
instructions="You are a helpful weather assistant.",
309317
tools=get_weather,

agent-framework/agents/middleware/agent-vs-run-scope.md

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ When both are registered, agent-level middleware runs first (outermost), followe
2020

2121
:::zone pivot="programming-language-csharp"
2222

23-
In C#, middleware is registered on an agent using the builder pattern. Agent-level middleware is applied during agent construction, while run-level middleware can be provided via `AgentRunOptions`.
23+
In C#, middleware is registered on an agent using the builder pattern with `.AsBuilder().Use(...).Build()`. Agent-level middleware is applied during agent construction and persists across all runs. Run-level middleware uses the same pattern but builds a decorated agent inline before calling `RunAsync` or `RunStreamingAsync`.
2424

2525
### Agent-level middleware
2626

@@ -30,6 +30,7 @@ Agent-level middleware is registered at construction time and applies to every r
3030
using System;
3131
using System.Collections.Generic;
3232
using System.Linq;
33+
using System.Runtime.CompilerServices;
3334
using System.Threading;
3435
using System.Threading.Tasks;
3536
using Azure.AI.OpenAI;
@@ -50,6 +51,20 @@ async Task<AgentResponse> SecurityMiddleware(
5051
return response;
5152
}
5253

54+
async IAsyncEnumerable<AgentResponseUpdate> SecurityStreamingMiddleware(
55+
IEnumerable<ChatMessage> messages,
56+
AgentSession? session,
57+
AgentRunOptions? options,
58+
AIAgent innerAgent,
59+
[EnumeratorCancellation] CancellationToken cancellationToken)
60+
{
61+
Console.WriteLine("[Security] Validating streaming request...");
62+
await foreach (var update in innerAgent.RunStreamingAsync(messages, session, options, cancellationToken))
63+
{
64+
yield return update;
65+
}
66+
}
67+
5368
AIAgent baseAgent = new AzureOpenAIClient(
5469
new Uri("https://<myresource>.openai.azure.com"),
5570
new AzureCliCredential())
@@ -59,15 +74,15 @@ AIAgent baseAgent = new AzureOpenAIClient(
5974
// Register middleware at the agent level
6075
var agentWithMiddleware = baseAgent
6176
.AsBuilder()
62-
.Use(runFunc: SecurityMiddleware, runStreamingFunc: null)
77+
.Use(runFunc: SecurityMiddleware, runStreamingFunc: SecurityStreamingMiddleware)
6378
.Build();
6479

6580
Console.WriteLine(await agentWithMiddleware.RunAsync("What's the weather in Paris?"));
6681
```
6782

6883
### Run-level middleware
6984

70-
Run-level middleware is provided per request via `AgentRunOptions`:
85+
Run-level middleware uses the same builder pattern, applied inline for a specific invocation:
7186

7287
```csharp
7388
// Run-level middleware: applied to a specific run only
@@ -84,11 +99,31 @@ async Task<AgentResponse> DebugMiddleware(
8499
return response;
85100
}
86101

87-
// Pass run-level middleware via AgentRunOptions for this specific call
88-
var runOptions = new AgentRunOptions { RunMiddleware = DebugMiddleware };
89-
Console.WriteLine(await baseAgent.RunAsync("What's the weather in Tokyo?", options: runOptions));
102+
async IAsyncEnumerable<AgentResponseUpdate> DebugStreamingMiddleware(
103+
IEnumerable<ChatMessage> messages,
104+
AgentSession? session,
105+
AgentRunOptions? options,
106+
AIAgent innerAgent,
107+
[EnumeratorCancellation] CancellationToken cancellationToken)
108+
{
109+
Console.WriteLine($"[Debug] Input messages: {messages.Count()}");
110+
await foreach (var update in innerAgent.RunStreamingAsync(messages, session, options, cancellationToken))
111+
{
112+
yield return update;
113+
}
114+
}
115+
116+
// Apply run-level middleware by building a decorated agent inline for this specific call
117+
Console.WriteLine(await baseAgent
118+
.AsBuilder()
119+
.Use(runFunc: DebugMiddleware, runStreamingFunc: DebugStreamingMiddleware)
120+
.Build()
121+
.RunAsync("What's the weather in Tokyo?"));
90122
```
91123

124+
> [!TIP]
125+
> The `.AsBuilder().Use(...).Build()` pattern creates a lightweight wrapper around the original agent. You can chain multiple `.Use()` calls to compose several middleware for a single invocation.
126+
92127
:::zone-end
93128

94129
:::zone pivot="programming-language-python"

agent-framework/agents/middleware/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,4 +881,4 @@ if __name__ == "__main__":
881881
## Next steps
882882

883883
> [!div class="nextstepaction"]
884-
> [Agent Background Responses](../background-responses.md)
884+
> [Defining Middleware](./defining-middleware.md)

agent-framework/agents/middleware/result-overrides.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ from agent_framework import (
9494
ResponseStream,
9595
tool,
9696
)
97-
from agent_framework.openai import OpenAIResponsesClient
97+
from agent_framework.openai import OpenAIChatClient
9898
from pydantic import Field
9999

100100
"""
@@ -260,7 +260,7 @@ async def main() -> None:
260260

261261
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
262262
# authentication option.
263-
agent = OpenAIResponsesClient(
263+
agent = OpenAIChatClient(
264264
middleware=[validate_weather_middleware, weather_override_middleware],
265265
).as_agent(
266266
name="WeatherAgent",
@@ -316,7 +316,7 @@ from agent_framework import (
316316
ResponseStream,
317317
tool,
318318
)
319-
from agent_framework.openai import OpenAIResponsesClient
319+
from agent_framework.openai import OpenAIChatClient
320320
from pydantic import Field
321321

322322
"""
@@ -482,7 +482,7 @@ async def main() -> None:
482482

483483
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
484484
# authentication option.
485-
agent = OpenAIResponsesClient(
485+
agent = OpenAIChatClient(
486486
middleware=[validate_weather_middleware, weather_override_middleware],
487487
).as_agent(
488488
name="WeatherAgent",

0 commit comments

Comments
 (0)