chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create, use, and clean up a FoundryAgent backed by a server-side
// versioned agent in Microsoft Foundry. It demonstrates the full lifecycle:
// create agent version -> wrap as FoundryAgent -> run -> delete.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI.Foundry;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
const string JokerName = "JokerAgent";
// Create the AIProjectClient to manage server-side agents.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a server-side agent version using the native SDK.
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
JokerName,
new ProjectsAgentVersionCreationOptions(
new DeclarativeAgentDefinition(model: deploymentName)
{
Instructions = "You are good at telling jokes.",
}));
// Wrap the agent version as a FoundryAgent using the AsAIAgent extension.
FoundryAgent agent = aiProjectClient.AsAIAgent(agentVersion);
// Once you have the agent, you can invoke it like any other AIAgent.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
// Cleanup: deletes the agent and all its versions.
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
@@ -0,0 +1,24 @@
# Agent Step 00 - FoundryAgent Lifecycle
This sample demonstrates the full lifecycle of a `FoundryAgent` backed by a server-side versioned agent in Microsoft Foundry: create → run → delete.
## Prerequisites
- A Microsoft Foundry project endpoint
- A model deployment name (defaults to `gpt-5.4-mini`)
- An authenticated Azure identity (for example, sign in with `az login`)
## Environment Variables
| Variable | Description | Required |
| --- | --- | --- |
| `FOUNDRY_PROJECT_ENDPOINT` | Microsoft Foundry project endpoint | Yes |
| `FOUNDRY_MODEL` | Model deployment name | No (defaults to `gpt-5.4-mini`) |
## Running the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step00_FoundryAgentLifecycle
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create and run a basic agent with AIProjectClient.AsAIAgent(...).
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIAgent agent =
new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(model: deploymentName, instructions: "You are good at telling jokes.", name: "JokerAgent");
// Once you have the agent, you can invoke it like any other AIAgent.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
@@ -0,0 +1,56 @@
# Creating and Running a Basic Agent with the Responses API
This sample demonstrates how to create and run a basic AI agent using the `ChatClientAgent`, which uses the Microsoft Foundry Responses API directly without creating server-side agent definitions.
## What this sample demonstrates
- Creating a `ChatClientAgent` with instructions and a model
- Running a simple single-turn conversation
- No server-side agent creation or cleanup required
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
**Note**: This sample uses `DefaultAzureCredential`. `az login` is the easiest local development path, but Visual Studio, VS Code, and managed identity credentials also work when available.
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
Navigate to the Foundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step01_Basics
```
## Alternative: Composable approach
You can also create the same agent by composing the underlying `IChatClient` directly. This gives you full control over the chat client pipeline:
```csharp
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = new ChatClientAgent(
chatClient: aiProjectClient.GetProjectOpenAIClient().GetProjectResponsesClient().AsIChatClient(deploymentName),
instructions: "You are good at telling jokes.",
name: "JokerAgent");
```
This approach is useful when you need to customize the chat client pipeline or swap providers (e.g., Anthropic, OpenAI) while keeping the same agent code.
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to create a multi-turn conversation agent using sessions.
// Context is preserved across multiple runs via response ID chaining in the session.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(deploymentName, instructions: "You are good at telling jokes.", name: "JokerAgent");
// Create a session to maintain context across multiple runs.
AgentSession session = await agent.CreateSessionAsync();
// First turn
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// Second turn — the agent remembers the first turn via the session.
Console.WriteLine(await agent.RunAsync("Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", session));
@@ -0,0 +1,37 @@
# Multi-turn Conversation
This sample demonstrates how to implement multi-turn conversations where context is preserved across multiple agent runs using sessions and response ID chaining.
## What this sample demonstrates
- Creating an agent with instructions
- Using sessions to maintain conversation context across multiple runs
- Response ID chaining for multi-turn conversations
- No server-side conversation creation required
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
**Note**: This sample uses `DefaultAzureCredential`. `az login` is the easiest local development path, but Visual Studio, VS Code, and managed identity credentials also work when available.
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
Navigate to the Foundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step02.1_MultiturnConversation
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use server-side conversations with a FoundryAgent.
// Server-side conversations persist on the Foundry service and are visible in the Foundry Project UI.
// Use this when you need conversation history to be stored and accessible server-side.
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
ChatClientAgent agent = aiProjectClient
.AsAIAgent(deploymentName, instructions: "You are good at telling jokes.", name: "JokerAgent");
ProjectConversationsClient conversationsClient = aiProjectClient
.GetProjectOpenAIClient()
.GetProjectConversationsClient();
ProjectConversation conversation = (await conversationsClient.CreateProjectConversationAsync().ConfigureAwait(false)).Value;
// CreateConversationSessionAsync creates a server-side ProjectConversation
// that persists on the Foundry service and is visible in the Foundry Project UI.
AgentSession session = await agent.CreateSessionAsync(conversation.Id);
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
Console.WriteLine(await agent.RunAsync("Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", session));
// Streaming with server-side conversation context.
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("Tell me another joke, but about a ninja this time.", session))
{
Console.Write(update);
}
Console.WriteLine();
@@ -0,0 +1,37 @@
# Multi-turn Conversation with Server-Side Conversations
This sample demonstrates how to use server-side conversations with a `FoundryAgent`. Server-side conversations persist on the Foundry service and are visible in the Foundry Project UI, making them ideal when you need conversation history to be stored and accessible server-side.
## What this sample demonstrates
- Creating a `FoundryAgent` with instructions
- Using `CreateConversationSessionAsync` to create a server-side `ProjectConversation`
- Multi-turn conversations with both text and streaming output
- Server-side conversation persistence visible in the Foundry Project UI
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
**Note**: This sample uses `DefaultAzureCredential`. `az login` is the easiest local development path, but Visual Studio, VS Code, and managed identity credentials also work when available.
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
Navigate to the Foundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step02.2_MultiturnWithServerConversations
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use function tools.
using System.ComponentModel;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
// Define the function tool.
AITool tool = AIFunctionFactory.Create(GetWeather);
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with function tools.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant that can get weather information.",
name: "WeatherAssistant",
tools: [tool]);
// Non-streaming agent interaction with function tools.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", session));
// Streaming agent interaction with function tools.
session = await agent.CreateSessionAsync();
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("What is the weather like in Amsterdam?", session))
{
Console.Write(update);
}
@@ -0,0 +1,38 @@
# Using Function Tools with the Responses API
This sample demonstrates how to use function tools with the `ChatClientAgent`, allowing the agent to call custom functions to retrieve information.
## What this sample demonstrates
- Creating function tools using `AIFunctionFactory`
- Passing function tools to a `ChatClientAgent`
- Running agents with function tools (text output)
- Running agents with function tools (streaming output)
- No server-side agent creation or cleanup required
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
**Note**: This sample uses `DefaultAzureCredential`. `az login` is the easiest local development path, but Visual Studio, VS Code, and managed identity credentials also work when available.
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
Navigate to the Foundry sample directory and run:
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step03_UsingFunctionTools
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use an agent with function tools that require a human in the loop for approvals.
using System.ComponentModel;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
ApprovalRequiredAIFunction approvalTool = new(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)));
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant that can get weather information.",
name: "WeatherAssistant",
tools: [approvalTool]);
// Call the agent with approval-required function tools.
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("What is the weather like in Amsterdam?", session);
// Check if there are any approval requests.
List<ToolApprovalRequestContent> approvalRequests = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
while (approvalRequests.Count > 0)
{
// Ask the user to approve each function call request.
List<ChatMessage> userInputMessages = approvalRequests
.ConvertAll(functionApprovalRequest =>
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);
});
response = await agent.RunAsync(userInputMessages, session);
approvalRequests = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
}
Console.WriteLine($"\nAgent: {response}");
@@ -0,0 +1,31 @@
# Using Function Tools with Approvals via the Responses API
This sample demonstrates how to use function tools that require human-in-the-loop approval before execution.
## What this sample demonstrates
- Creating function tools that require approval using `ApprovalRequiredAIFunction`
- Handling approval requests from the agent
- Passing approval responses back to the agent
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step04_UsingFunctionToolsWithApprovals
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,71 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to configure an agent to produce structured output.
using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Serialization;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using SampleApp;
#pragma warning disable CA5399
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
{
Name = "StructuredOutputAssistant",
ChatOptions = new()
{
ModelId = deploymentName,
Instructions = "You are a helpful assistant that extracts structured information about people.",
ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.ForJsonSchema<PersonInfo>()
}
});
// Set PersonInfo as the type parameter of RunAsync method to specify the expected structured output.
AgentResponse<PersonInfo> response = await agent.RunAsync<PersonInfo>("Please provide information about John Smith, who is a 35-year-old software engineer.");
// Access the structured output via the Result property of the agent response.
Console.WriteLine("Assistant Output:");
Console.WriteLine($"Name: {response.Result.Name}");
Console.WriteLine($"Age: {response.Result.Age}");
Console.WriteLine($"Occupation: {response.Result.Occupation}");
// Invoke the agent with streaming support, then deserialize the assembled response.
IAsyncEnumerable<AgentResponseUpdate> updates = agent.RunStreamingAsync("Please provide information about Jane Doe, who is a 28-year-old data scientist.");
PersonInfo personInfo = JsonSerializer.Deserialize<PersonInfo>((await updates.ToAgentResponseAsync()).Text, JsonSerializerOptions.Web)
?? throw new InvalidOperationException("Failed to deserialize the streamed response into PersonInfo.");
Console.WriteLine("\nStreaming Assistant Output:");
Console.WriteLine($"Name: {personInfo.Name}");
Console.WriteLine($"Age: {personInfo.Age}");
Console.WriteLine($"Occupation: {personInfo.Occupation}");
namespace SampleApp
{
/// <summary>
/// Represents information about a person.
/// </summary>
[Description("Information about a person including their name, age, and occupation")]
public class PersonInfo
{
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("age")]
public int? Age { get; set; }
[JsonPropertyName("occupation")]
public string? Occupation { get; set; }
}
}
@@ -0,0 +1,30 @@
# Structured Output with the Responses API
This sample demonstrates how to configure an agent to produce structured output using JSON schema.
## What this sample demonstrates
- Using `RunAsync<T>()` to get typed structured output from the agent
- Deserializing streamed responses into structured types
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step05_StructuredOutput
```
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to persist and resume conversations.
using System.Text.Json;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
// Start a new session for the agent conversation.
AgentSession session = await agent.CreateSessionAsync();
// Run the agent with a new session.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// Serialize the session state to a JsonElement, so it can be stored for later use.
JsonElement serializedSession = await agent.SerializeSessionAsync(session);
// Save the serialized session to a temporary file (for demonstration purposes).
string tempFilePath = Path.GetTempFileName();
await File.WriteAllTextAsync(tempFilePath, JsonSerializer.Serialize(serializedSession));
// Load the serialized session from the temporary file (for demonstration purposes).
JsonElement reloadedSerializedSession = JsonElement.Parse(await File.ReadAllTextAsync(tempFilePath))!;
// Deserialize the session state after loading from storage.
AgentSession resumedSession = await agent.DeserializeSessionAsync(reloadedSerializedSession);
// Run the agent again with the resumed session.
Console.WriteLine(await agent.RunAsync("Now tell the same joke in the voice of a pirate, and add some emojis to the joke.", resumedSession));
@@ -0,0 +1,31 @@
# Persisted Conversations with the Responses API
This sample demonstrates how to persist and resume agent conversations using session serialization.
## What this sample demonstrates
- Serializing agent sessions to JSON for persistence
- Saving and loading sessions from disk
- Resuming conversations with preserved context
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step06_PersistedConversations
```
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" />
<PackageReference Include="OpenTelemetry" />
<PackageReference Include="OpenTelemetry.Exporter.Console" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to add OpenTelemetry observability to an agent.
using Azure.AI.Projects;
using Azure.Identity;
using Azure.Monitor.OpenTelemetry.Exporter;
using Microsoft.Agents.AI;
using OpenTelemetry;
using OpenTelemetry.Trace;
string? applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// Create TracerProvider with console exporter.
string sourceName = Guid.NewGuid().ToString("N");
TracerProviderBuilder tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
.AddConsoleExporter();
if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
{
tracerProviderBuilder.AddAzureMonitorTraceExporter(options => options.ConnectionString = applicationInsightsConnectionString);
}
using var tracerProvider = tracerProviderBuilder.Build();
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient
.AsAIAgent(
deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent")
.AsBuilder()
.UseOpenTelemetry(sourceName: sourceName)
.Build();
// Invoke the agent and output the text result.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// Invoke the agent with streaming support.
session = await agent.CreateSessionAsync();
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("Tell me a joke about a pirate.", session))
{
Console.Write(update);
}
Console.WriteLine();
@@ -0,0 +1,32 @@
# Observability with the Responses API
This sample demonstrates how to add OpenTelemetry observability to an agent using console and Azure Monitor exporters.
## What this sample demonstrates
- Configuring OpenTelemetry tracing with console exporter
- Optional Azure Application Insights integration
- Using `.AsBuilder().UseOpenTelemetry()` to add telemetry to the agent
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
$env:APPLICATIONINSIGHTS_CONNECTION_STRING="..." # Optional
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step07_Observability
```
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);CA1812</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,83 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use dependency injection to register a AIAgent and use it from a hosted service.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SampleApp;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
// Create a host builder that we will register services with and then run.
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Add the AI agent to the service collection.
builder.Services.AddSingleton(agent);
// Add a sample service that will use the agent to respond to user input.
builder.Services.AddHostedService<SampleService>();
// Build and run the host.
using IHost host = builder.Build();
await host.RunAsync().ConfigureAwait(false);
namespace SampleApp
{
/// <summary>
/// A sample service that uses an AI agent to respond to user input.
/// </summary>
internal sealed class SampleService(AIAgent agent, IHostApplicationLifetime appLifetime) : IHostedService
{
private AgentSession? _session;
public async Task StartAsync(CancellationToken cancellationToken)
{
this._session = await agent.CreateSessionAsync(cancellationToken);
_ = this.RunAsync(appLifetime.ApplicationStopping);
}
public async Task RunAsync(CancellationToken cancellationToken)
{
await Task.Delay(100, cancellationToken);
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("\nAgent: Ask me to tell you a joke about a specific topic. To exit just press Ctrl+C or enter without any input.\n");
Console.Write("> ");
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
appLifetime.StopApplication();
break;
}
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(input, this._session, cancellationToken: cancellationToken))
{
Console.Write(update);
}
Console.WriteLine();
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("\nShutting down...");
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,31 @@
# Dependency Injection with the Responses API
This sample demonstrates how to register a `ChatClientAgent` in a dependency injection container and use it from a hosted service.
## What this sample demonstrates
- Registering `ChatClientAgent` as an `AIAgent` in the service collection
- Using the agent from a `IHostedService` with an interactive chat loop
- Streaming responses in a hosted service context
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step08_DependencyInjection
```
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use MCP client tools with an agent.
// It connects to the Microsoft Learn MCP server via HTTP and uses its tools.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// Connect to the Microsoft Learn MCP server via HTTP (Streamable HTTP transport).
Console.WriteLine("Connecting to MCP server at https://learn.microsoft.com/api/mcp ...");
await using McpClient mcpClient = await McpClient.CreateAsync(new HttpClientTransport(new()
{
Endpoint = new Uri("https://learn.microsoft.com/api/mcp"),
Name = "Microsoft Learn MCP",
}));
// Retrieve the list of tools available on the MCP server.
IList<McpClientTool> mcpTools = await mcpClient.ListToolsAsync();
Console.WriteLine($"MCP tools available: {string.Join(", ", mcpTools.Select(t => t.Name))}");
List<AITool> agentTools = [.. mcpTools.Cast<AITool>()];
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant that can help with Microsoft documentation questions. Use the Microsoft Learn MCP tool to search for documentation. In the output, indicate which tool you used if any.",
name: "DocsAgent",
tools: agentTools);
Console.WriteLine($"Agent '{agent.Name}' created. Asking a question...\n");
const string Prompt = "How does one create an Azure storage account using az cli?";
Console.WriteLine($"User: {Prompt}\n");
Console.WriteLine($"Agent: {await agent.RunAsync(Prompt)}");
@@ -0,0 +1,30 @@
# Using MCP Client as Tools with the Responses API
This sample shows how to use MCP (Model Context Protocol) client tools with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Connecting to an MCP server via HTTP client transport
- Retrieving MCP tools and passing them to a `ChatClientAgent`
- Using MCP tools for agent interactions without server-side agent creation
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
- Node.js installed (for npx/MCP server)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="assets\walkway.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use image multi-modality with an agent.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful agent that can analyze images.",
name: "VisionAgent");
ChatMessage message = new(ChatRole.User, [
new TextContent("What do you see in this image?"),
await DataContent.LoadFromAsync("assets/walkway.jpg"),
]);
AgentSession session = await agent.CreateSessionAsync();
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(message, session))
{
Console.Write(update);
}
Console.WriteLine();
@@ -0,0 +1,31 @@
# Using Images with the Responses API
This sample demonstrates how to use image multi-modality with an agent.
## What this sample demonstrates
- Loading images using `DataContent.LoadFromAsync`
- Sending images alongside text to the agent
- Streaming the agent's image analysis response
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and a vision-capable model deployment (e.g., `gpt-5.4-mini`)
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step10_UsingImages
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use one agent as a function tool for another agent.
using System.ComponentModel;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AITool weatherTool = AIFunctionFactory.Create(GetWeather);
AIAgent weatherAgent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You answer questions about the weather.",
name: "WeatherAgent",
tools: [weatherTool]);
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a helpful assistant who responds in French.",
name: "MainAgent",
tools: [weatherAgent.AsAIFunction()]);
// Invoke the agent and output the text result.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", session));
@@ -0,0 +1,31 @@
# Agent as a Function Tool with the Responses API
This sample demonstrates how to use one agent as a function tool for another agent.
## What this sample demonstrates
- Creating a specialized agent (weather) with function tools
- Exposing an agent as a function tool using `.AsAIFunction()`
- Composing agents where one agent delegates to another
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step11_AsFunctionTool
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,208 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows multiple middleware layers working together with a ChatClientAgent:
// agent run (PII filtering and guardrails),
// function invocation (logging and result overrides), and human-in-the-loop
// approval workflows for sensitive function calls.
using System.ComponentModel;
using System.Text.RegularExpressions;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
[Description("The current datetime offset.")]
static string GetDateTime()
=> DateTimeOffset.Now.ToString();
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AITool dateTimeTool = AIFunctionFactory.Create(GetDateTime, name: nameof(GetDateTime));
AITool getWeatherTool = AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather));
AIAgent originalAgent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are an AI assistant that helps people find information.",
name: "InformationAssistant",
tools: [getWeatherTool, dateTimeTool]);
// Adding middleware to the agent level
AIAgent middlewareEnabledAgent = originalAgent
.AsBuilder()
.Use(FunctionCallMiddleware)
.Use(FunctionCallOverrideWeather)
.Use(PIIMiddleware, null)
.Use(GuardrailMiddleware, null)
.Build();
AgentSession session = await middlewareEnabledAgent.CreateSessionAsync();
Console.WriteLine("\n\n=== Example 1: Wording Guardrail ===");
AgentResponse guardRailedResponse = await middlewareEnabledAgent.RunAsync("Tell me something harmful.");
Console.WriteLine($"Guard railed response: {guardRailedResponse}");
Console.WriteLine("\n\n=== Example 2: PII detection ===");
AgentResponse piiResponse = await middlewareEnabledAgent.RunAsync("My name is John Doe, call me at 123-456-7890 or email me at john@something.com");
Console.WriteLine($"Pii filtered response: {piiResponse}");
Console.WriteLine("\n\n=== Example 3: Agent function middleware ===");
AgentResponse functionCallResponse = await middlewareEnabledAgent.RunAsync("What's the current time and the weather in Seattle?", session);
Console.WriteLine($"Function calling response: {functionCallResponse}");
// Special per-request middleware agent.
Console.WriteLine("\n\n=== Example 4: Middleware with human in the loop function approval ===");
AIAgent humanInTheLoopAgent = aiProjectClient.AsAIAgent(deploymentName,
instructions: "You are a Human in the loop testing AI assistant that helps people find information.",
name: "HumanInTheLoopAgent",
tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)))]);
AgentResponse response = await humanInTheLoopAgent
.AsBuilder()
.Use(ConsolePromptingApprovalMiddleware, null)
.Build()
.RunAsync("What's the current time and the weather in Seattle?");
Console.WriteLine($"HumanInTheLoopAgent agent middleware response: {response}");
// Function invocation middleware that logs before and after function calls.
async ValueTask<object?> FunctionCallMiddleware(AIAgent agent, FunctionInvocationContext context, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next, CancellationToken cancellationToken)
{
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 1 Pre-Invoke");
var result = await next(context, cancellationToken);
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 1 Post-Invoke");
return result;
}
// Function invocation middleware that overrides the result of the GetWeather function.
async ValueTask<object?> FunctionCallOverrideWeather(AIAgent agent, FunctionInvocationContext context, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next, CancellationToken cancellationToken)
{
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 2 Pre-Invoke");
var result = await next(context, cancellationToken);
if (context.Function.Name == nameof(GetWeather))
{
result = "The weather is sunny with a high of 25°C.";
}
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 2 Post-Invoke");
return result;
}
// This middleware redacts PII information from input and output messages.
async Task<AgentResponse> PIIMiddleware(IEnumerable<ChatMessage> messages, AgentSession? session, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
{
var filteredMessages = FilterMessages(messages);
Console.WriteLine("Pii Middleware - Filtered Messages Pre-Run");
var agentResponse = await innerAgent.RunAsync(filteredMessages, session, options, cancellationToken).ConfigureAwait(false);
agentResponse.Messages = FilterMessages(agentResponse.Messages);
Console.WriteLine("Pii Middleware - Filtered Messages Post-Run");
return agentResponse;
static IList<ChatMessage> FilterMessages(IEnumerable<ChatMessage> messages)
{
return messages.Select(m => new ChatMessage(m.Role, FilterPii(m.Text))).ToList();
}
static string FilterPii(string content)
{
Regex[] piiPatterns = [
MyRegex(),
EmailRegex(),
FullNameRegex()
];
foreach (var pattern in piiPatterns)
{
content = pattern.Replace(content, "[REDACTED: PII]");
}
return content;
}
}
// This middleware enforces guardrails by redacting certain keywords from input and output messages.
async Task<AgentResponse> GuardrailMiddleware(IEnumerable<ChatMessage> messages, AgentSession? session, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
{
var filteredMessages = FilterMessages(messages);
Console.WriteLine("Guardrail Middleware - Filtered messages Pre-Run");
var agentResponse = await innerAgent.RunAsync(filteredMessages, session, options, cancellationToken);
agentResponse.Messages = FilterMessages(agentResponse.Messages);
Console.WriteLine("Guardrail Middleware - Filtered messages Post-Run");
return agentResponse;
List<ChatMessage> FilterMessages(IEnumerable<ChatMessage> messages)
{
return messages.Select(m => new ChatMessage(m.Role, FilterContent(m.Text))).ToList();
}
static string FilterContent(string content)
{
foreach (var keyword in new[] { "harmful", "illegal", "violence" })
{
if (content.Contains(keyword, StringComparison.OrdinalIgnoreCase))
{
return "[REDACTED: Forbidden content]";
}
}
return content;
}
}
// This middleware handles Human in the loop console interaction for any user approval required during function calling.
async Task<AgentResponse> ConsolePromptingApprovalMiddleware(IEnumerable<ChatMessage> messages, AgentSession? session, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
{
AgentResponse agentResponse = await innerAgent.RunAsync(messages, session, options, cancellationToken);
List<ToolApprovalRequestContent> approvalRequests = agentResponse.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
while (approvalRequests.Count > 0)
{
agentResponse.Messages = approvalRequests
.ConvertAll(functionApprovalRequest =>
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);
});
agentResponse = await innerAgent.RunAsync(agentResponse.Messages, session, options, cancellationToken);
approvalRequests = agentResponse.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().ToList();
}
return agentResponse;
}
internal partial class Program
{
[GeneratedRegex(@"\b\d{3}-\d{3}-\d{4}\b", RegexOptions.Compiled)]
private static partial Regex MyRegex();
[GeneratedRegex(@"\b[\w\.-]+@[\w\.-]+\.\w+\b", RegexOptions.Compiled)]
private static partial Regex EmailRegex();
[GeneratedRegex(@"\b[A-Z][a-z]+\s[A-Z][a-z]+\b", RegexOptions.Compiled)]
private static partial Regex FullNameRegex();
}
@@ -0,0 +1,32 @@
# Middleware with the Responses API
This sample demonstrates multiple middleware layers working together: PII filtering, guardrails, function invocation logging, and human-in-the-loop approval.
## What this sample demonstrates
- Agent-level run middleware (PII filtering, guardrail enforcement)
- Function-level middleware (logging, result overrides)
- Human-in-the-loop approval workflows for sensitive function calls
- Using `.AsBuilder().Use()` to compose middleware
- No server-side agent creation or cleanup required
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step12_Middleware
```
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);CA1812</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,153 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use plugins with an AI agent. Plugin classes can
// depend on other services that need to be injected. In this sample, the
// AgentPlugin class uses the WeatherProvider and CurrentTimeProvider classes
// to get weather and current time information. Both services are registered
// in the service collection and injected into the plugin.
// Plugin classes may have many methods, but only some are intended to be used
// as AI functions. The AsAITools method of the plugin class shows how to specify
// which methods should be exposed to the AI agent.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using SampleApp;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
const string AssistantInstructions = "You are a helpful assistant that helps people find information.";
const string AssistantName = "PluginAssistant";
// Create a service collection to hold the agent plugin and its dependencies.
ServiceCollection services = new();
services.AddSingleton<WeatherProvider>();
services.AddSingleton<CurrentTimeProvider>();
services.AddSingleton<AgentPlugin>(); // The plugin depends on WeatherProvider and CurrentTimeProvider registered above.
IServiceProvider serviceProvider = services.BuildServiceProvider();
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a ChatClientAgent with the options-based constructor to pass services.
AIAgent agent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
{
Name = AssistantName,
ChatOptions = new() { ModelId = deploymentName, Instructions = AssistantInstructions, Tools = serviceProvider.GetRequiredService<AgentPlugin>().AsAITools().ToList() }
},
services: serviceProvider);
// Invoke the agent and output the text result.
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me current time and weather in Seattle.", session));
namespace SampleApp
{
/// <summary>
/// The agent plugin that provides weather and current time information.
/// </summary>
internal sealed class AgentPlugin
{
private readonly WeatherProvider _weatherProvider;
/// <summary>
/// Initializes a new instance of the <see cref="AgentPlugin"/> class.
/// </summary>
/// <param name="weatherProvider">The weather provider to get weather information.</param>
public AgentPlugin(WeatherProvider weatherProvider)
{
this._weatherProvider = weatherProvider;
}
/// <summary>
/// Gets the weather information for the specified location.
/// </summary>
/// <remarks>
/// This method demonstrates how to use the dependency that was injected into the plugin class.
/// </remarks>
/// <param name="location">The location to get the weather for.</param>
/// <returns>The weather information for the specified location.</returns>
public string GetWeather(string location)
{
return this._weatherProvider.GetWeather(location);
}
/// <summary>
/// Gets the current date and time for the specified location.
/// </summary>
/// <remarks>
/// This method demonstrates how to resolve a dependency using the service provider passed to the method.
/// </remarks>
/// <param name="sp">The service provider to resolve the <see cref="CurrentTimeProvider"/>.</param>
/// <param name="location">The location to get the current time for.</param>
/// <returns>The current date and time as a <see cref="DateTimeOffset"/>.</returns>
public DateTimeOffset GetCurrentTime(IServiceProvider sp, string location)
{
CurrentTimeProvider currentTimeProvider = sp.GetRequiredService<CurrentTimeProvider>();
return currentTimeProvider.GetCurrentTime(location);
}
/// <summary>
/// Returns the functions provided by this plugin.
/// </summary>
/// <remarks>
/// In real world scenarios, a class may have many methods and only a subset of them may be intended to be exposed as AI functions.
/// This method demonstrates how to explicitly specify which methods should be exposed to the AI agent.
/// </remarks>
/// <returns>The functions provided by this plugin.</returns>
public IEnumerable<AITool> AsAITools()
{
yield return AIFunctionFactory.Create(this.GetWeather);
yield return AIFunctionFactory.Create(this.GetCurrentTime);
}
}
internal sealed class WeatherProvider
{
private readonly string _weatherSummary = "cloudy with a high of 15°C";
/// <summary>
/// The weather provider that returns weather information.
/// </summary>
/// <summary>
/// Gets the weather information for the specified location.
/// </summary>
/// <remarks>
/// The weather information is hardcoded for demonstration purposes.
/// In a real application, this could call a weather API to get actual weather data.
/// </remarks>
/// <param name="location">The location to get the weather for.</param>
/// <returns>The weather information for the specified location.</returns>
public string GetWeather(string location)
{
return $"The weather in {location} is {this._weatherSummary}.";
}
}
internal sealed class CurrentTimeProvider
{
private readonly TimeProvider _timeProvider = TimeProvider.System;
/// <summary>
/// Provides the current date and time.
/// </summary>
/// <remarks>
/// This class returns the current date and time using the system's clock.
/// </remarks>
/// <summary>
/// Gets the current date and time.
/// </summary>
/// <param name="location">The location to get the current time for (not used in this implementation).</param>
/// <returns>The current date and time as a <see cref="DateTimeOffset"/>.</returns>
public DateTimeOffset GetCurrentTime(string location)
{
return this._timeProvider.GetLocalNow();
}
}
}
@@ -0,0 +1,30 @@
# Using Plugins with the Responses API
This sample shows how to use plugins with a `ChatClientAgent` using the Responses API directly, with dependency injection for plugin services.
## What this sample demonstrates
- Creating plugin classes with injected dependencies
- Registering services and building a service provider
- Passing `services` to the `ChatClientAgent` via the options-based constructor
- Using `AIFunctionFactory` to expose plugin methods as AI tools
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,90 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Code Interpreter Tool with AIProjectClient.AsAIAgent(...).
using System.Text;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Assistants;
using OpenAI.Responses;
const string AgentInstructions = "You are a personal math tutor. When asked a math question, write and run code using the python tool to answer the question.";
const string AgentName = "CoderAgent-RAPI";
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// The easiest way to add the hosted code interpreter is as follows:
/*
AIAgent agent = aiProjectClient.AsAIAgent(
deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: [new HostedCodeInterpreterTool() { Inputs = [] }]);
*/
// However, by default the reponses API does not return the output items from the hosted code interpreter tool.
// This is generally fine but for this sample we want to explicitly request those in the response generation configuration.
AIAgent agent = aiProjectClient
.GetProjectOpenAIClient()
.GetProjectResponsesClient()
.AsIChatClient(deploymentName)
.AsBuilder()
.ConfigureOptions(x =>
{
var previousFactory = x.RawRepresentationFactory;
x.RawRepresentationFactory = state =>
{
var responseOptions = previousFactory?.Invoke(state) as CreateResponseOptions ?? new CreateResponseOptions();
// Ensure that the response includes tool output items from the hosted code interpreter
responseOptions.IncludedProperties.Add(IncludedResponseProperty.CodeInterpreterCallOutputs);
return responseOptions;
};
})
.Build()
.AsAIAgent(
instructions: AgentInstructions,
name: AgentName,
tools: [new HostedCodeInterpreterTool() { Inputs = [] }]);
AgentResponse response = await agent.RunAsync("I need to solve the equation sin(x) + x^2 = 42");
// Get the CodeInterpreterToolCallContent
CodeInterpreterToolCallContent? toolCallContent = response.Messages.SelectMany(m => m.Contents).OfType<CodeInterpreterToolCallContent>().FirstOrDefault();
if (toolCallContent?.Inputs is not null)
{
DataContent? codeInput = toolCallContent.Inputs.OfType<DataContent>().FirstOrDefault();
if (codeInput?.HasTopLevelMediaType("text") ?? false)
{
Console.WriteLine($"Code Input: {Encoding.UTF8.GetString(codeInput.Data.ToArray()) ?? "Not available"}");
}
}
// Get the CodeInterpreterToolResultContent
CodeInterpreterToolResultContent? toolResultContent = response.Messages.SelectMany(m => m.Contents).OfType<CodeInterpreterToolResultContent>().FirstOrDefault();
if (toolResultContent?.Outputs is not null && toolResultContent.Outputs.OfType<TextContent>().FirstOrDefault() is { } resultOutput)
{
Console.WriteLine($"Code Tool Result: {resultOutput.Text}");
}
// Getting any annotations generated by the tool
foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(C => C.Annotations ?? []))
{
if (annotation.RawRepresentation is TextAnnotationUpdate citationAnnotation)
{
Console.WriteLine($$"""
File Id: {{citationAnnotation.OutputFileId}}
Text to Replace: {{citationAnnotation.TextToReplace}}
Filename: {{Path.GetFileName(citationAnnotation.TextToReplace)}}
""");
}
}
@@ -0,0 +1,29 @@
# Code Interpreter with the Responses API
This sample shows how to use the Code Interpreter tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Using `HostedCodeInterpreterTool` with `ChatClientAgent`
- Extracting code input and output from agent responses
- Handling code interpreter annotations and file citations
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);OPENAICUA001;MEAI001</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Assets\cua_browser_search.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Assets\cua_search_results.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Assets\cua_search_typed.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

@@ -0,0 +1,93 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.AI;
using OpenAI.Responses;
namespace Demo.ComputerUse;
/// <summary>
/// Enum for tracking the state of the simulated web search flow.
/// </summary>
internal enum SearchState
{
Initial, // Browser search page
Typed, // Text entered in search box
PressedEnter // Enter key pressed, transitioning to results
}
internal static class ComputerUseUtil
{
internal static async Task<Dictionary<string, string>> UploadScreenshotAssetsAsync(IHostedFileClient fileClient)
{
string assetsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets");
(string key, string fileName)[] files =
[
("browser_search", "cua_browser_search.jpg"),
("search_typed", "cua_search_typed.jpg"),
("search_results", "cua_search_results.jpg")
];
Dictionary<string, string> screenshots = [];
foreach (var (key, fileName) in files)
{
HostedFileContent result = await fileClient.UploadAsync(
Path.Combine(assetsDir, fileName), new HostedFileClientOptions() { Purpose = "assistants" });
screenshots[key] = result.FileId;
}
return screenshots;
}
internal static async Task EnsureDeleteScreenshotAssetsAsync(IHostedFileClient fileClient, Dictionary<string, string> screenshots)
{
foreach (var (_, fileId) in screenshots)
{
try
{
await fileClient.DeleteAsync(fileId);
}
catch
{
}
}
}
/// <summary>
/// Simulates executing a computer action by advancing the state
/// and returning the screenshot file ID for the new state.
/// </summary>
internal static async Task<(SearchState State, string FileId)> GetScreenshotAsync(
ComputerCallAction action,
SearchState currentState,
Dictionary<string, string> screenshots)
{
if (action.Kind == ComputerCallActionKind.Wait)
{
await Task.Delay(TimeSpan.FromSeconds(5));
}
SearchState nextState = action.Kind switch
{
ComputerCallActionKind.Click when currentState == SearchState.Typed => SearchState.PressedEnter,
ComputerCallActionKind.Type when action.TypeText is not null => SearchState.Typed,
ComputerCallActionKind.KeyPress when IsEnterKey(action) => SearchState.PressedEnter,
_ => currentState
};
string imageKey = nextState switch
{
SearchState.PressedEnter => "search_results",
SearchState.Typed => "search_typed",
_ => "browser_search"
};
return (nextState, screenshots[imageKey]);
}
private static bool IsEnterKey(ComputerCallAction action) =>
action.KeyPressKeyCodes is not null &&
(action.KeyPressKeyCodes.Contains("Return", StringComparer.OrdinalIgnoreCase) ||
action.KeyPressKeyCodes.Contains("Enter", StringComparer.OrdinalIgnoreCase));
}
@@ -0,0 +1,112 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use the Computer Use tool with AIProjectClient.AsAIAgent(...).
using Azure.AI.Projects;
using Azure.Identity;
using Demo.ComputerUse;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_COMPUTER_USE_DEPLOYMENT_NAME") ?? "computer-use-preview";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient projectClient = new(new Uri(endpoint), new DefaultAzureCredential());
using IHostedFileClient fileClient = projectClient.GetProjectOpenAIClient().AsIHostedFileClient();
AIAgent agent = projectClient.AsAIAgent(
model: deploymentName,
name: "ComputerAgent",
instructions: "You are a computer automation assistant.",
tools: [FoundryAITool.CreateComputerTool(ComputerToolEnvironment.Browser, 1026, 769)]);
Dictionary<string, string> screenshots = [];
try
{
// Upload pre-captured screenshots that simulate browser state transitions.
screenshots = await ComputerUseUtil.UploadScreenshotAssetsAsync(fileClient);
// Enable auto-truncation for the Responses API.
ChatClientAgentRunOptions runOptions = new()
{
ChatOptions = new ChatOptions
{
RawRepresentationFactory = (_) => new CreateResponseOptions() { TruncationMode = ResponseTruncationMode.Auto },
}
};
// Send the initial request with a screenshot of the browser.
ChatMessage message = new(ChatRole.User, [
new TextContent("Search for 'OpenAI news'. Type it and submit. Once you see results, the task is complete."),
new AIContent() { RawRepresentation = ResponseContentPart.CreateInputImagePart(imageFileId: screenshots["browser_search"], imageDetailLevel: ResponseImageDetailLevel.High) }
]);
Console.WriteLine("Starting computer use session...");
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync(message, session: session, options: runOptions);
SearchState currentState = SearchState.Initial;
for (int i = 0; i < 10; i++)
{
// Find the next computer call action.
ComputerCallResponseItem? computerCall = response.Messages
.SelectMany(m => m.Contents)
.Select(c => c.RawRepresentation as ComputerCallResponseItem)
.FirstOrDefault(item => item is not null);
if (computerCall is null)
{
if (currentState == SearchState.PressedEnter)
{
Console.WriteLine("No more computer actions. Done.");
Console.WriteLine(response);
break;
}
// Check if the agent is asking for confirmation to proceed, and if so, respond affirmatively.
TextContent? textContent = response.Messages
.Where(m => m.Role == ChatRole.Assistant)
.SelectMany(m => m.Contents.OfType<TextContent>())
.FirstOrDefault();
if (textContent?.Text is { } text && (
text.Contains("Would you like me") ||
text.Contains("Should I") ||
text.Contains("proceed") ||
text.Contains('?')))
{
response = await agent.RunAsync("Please proceed.", session, runOptions);
continue;
}
break;
}
Console.WriteLine($"[{i + 1}] Action: {computerCall!.Action.Kind}");
// Simulate the action and get the resulting screenshot.
(currentState, string fileId) = await ComputerUseUtil.GetScreenshotAsync(computerCall.Action, currentState, screenshots);
// Send the screenshot back as the computer call output.
AIContent callOutput = new()
{
RawRepresentation = new ComputerCallOutputResponseItem(
computerCall.CallId,
output: ComputerCallOutput.CreateScreenshotOutput(screenshotImageFileId: fileId))
};
response = await agent.RunAsync([new ChatMessage(ChatRole.User, [callOutput])], session: session, options: runOptions);
}
}
finally
{
await ComputerUseUtil.EnsureDeleteScreenshotAssetsAsync(fileClient, screenshots);
}
@@ -0,0 +1,56 @@
# Computer Use with the Responses API
This sample shows how to use the Computer Use tool with `AIProjectClient.AsAIAgent(...)`.
## What this sample demonstrates
- Using `FoundryAITool.CreateComputerTool()` to add computer use capabilities
- Processing computer call actions (click, type, key press)
- Managing the computer use interaction loop with screenshots
For more information, see [Use the computer tool](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/tools/computer-use?pivots=csharp).
## How the simulation works
In a real computer use scenario, the model controls a virtual keyboard and mouse to interact with a live browser — typing text, clicking buttons, and pressing keys. The host application captures a screenshot after each action and sends it back to the model so it can decide what to do next.
**This sample does not connect to a real browser.** Instead, it intercepts the model's actions and returns pre-captured screenshots as if the actions were actually performed. No real typing, clicking, or key presses happen — the sample fakes the environment so you can explore the computer use protocol without any browser automation setup.
### State transitions
The model receives a screenshot as input, analyzes it, and responds with a computer action as output. The sample maps each action to a new state and returns the corresponding screenshot:
| Step | Model Action | What Happens | Screenshot Sent Back to Model |
|------|-----------------|-------------------------------------------|--------------------------------------------------------------|
| 1 | | Session starts with the user prompt | `cua_browser_search.jpg` — empty search page |
| 2 | Click | Model clicks the search box to focus it | `cua_browser_search.jpg` — same page |
| 3 | Type | Model types the search query into the box | `cua_search_typed.jpg` — search text visible in the box |
| 3a | *(text response)* | Model may ask for confirmation instead of acting | `cua_search_typed.jpg` — same page |
| 4 | KeyPress Enter | Model presses Enter to submit the search | `cua_search_results.jpg` — search results page |
### Interaction loop
1. The user prompt and the initial screenshot (`cua_browser_search.jpg` — an empty search page) are sent to the model as input.
2. The model analyzes the screenshot and responds with a computer action (e.g., click on the search box to focus it, then type search text, then press Enter).
3. The sample intercepts the action, advances the state, and sends back the next pre-captured screenshot as if the action was performed on a real browser.
4. Steps 23 repeat until the model stops requesting actions or the iteration limit is reached.
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:AZURE_AI_COMPUTER_USE_DEPLOYMENT_NAME="computer-use-preview"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use File Search Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Assistants;
using OpenAI.Files;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
const string AgentInstructions = "You are a helpful assistant that can search through uploaded files to answer questions.";
// We need the AIProjectClient to upload files and create vector stores.
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
var projectOpenAIClient = aiProjectClient.GetProjectOpenAIClient();
var filesClient = projectOpenAIClient.GetProjectFilesClient();
var vectorStoresClient = projectOpenAIClient.GetProjectVectorStoresClient();
// 1. Create a temp file with test content and upload it.
string searchFilePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + "_lookup.txt");
File.WriteAllText(
path: searchFilePath,
contents: """
Employee Directory:
- Alice Johnson, 28 years old, Software Engineer, Engineering Department
- Bob Smith, 35 years old, Sales Manager, Sales Department
- Carol Williams, 42 years old, HR Director, Human Resources Department
- David Brown, 31 years old, Customer Support Lead, Support Department
"""
);
Console.WriteLine($"Uploading file: {searchFilePath}");
OpenAIFile uploadedFile = filesClient.UploadFile(
filePath: searchFilePath,
purpose: FileUploadPurpose.Assistants
);
Console.WriteLine($"Uploaded file, file ID: {uploadedFile.Id}");
// 2. Create a vector store with the uploaded file.
var vectorStoreResult = await vectorStoresClient.CreateVectorStoreAsync(
options: new() { FileIds = { uploadedFile.Id }, Name = "EmployeeDirectory_VectorStore" }
);
string vectorStoreId = vectorStoreResult.Value.Id;
Console.WriteLine($"Created vector store, vector store ID: {vectorStoreId}");
// Create a AIAgent with HostedFileSearchTool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "FileSearchAgent-RAPI",
tools: [new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreId)] }]);
// Run the agent
Console.WriteLine("\n--- Running File Search Agent ---");
AgentResponse response = await agent.RunAsync("Who is the youngest employee?");
Console.WriteLine($"Response: {response}");
// Getting any file citation annotations generated by the tool
foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(c => c.Annotations ?? []))
{
if (annotation.RawRepresentation is TextAnnotationUpdate citationAnnotation)
{
Console.WriteLine($$"""
File Citation:
File Id: {{citationAnnotation.OutputFileId}}
Text to Replace: {{citationAnnotation.TextToReplace}}
""");
}
}
// Cleanup file resources.
Console.WriteLine("\n--- Cleanup ---");
await vectorStoresClient.DeleteVectorStoreAsync(vectorStoreId);
await filesClient.DeleteFileAsync(uploadedFile.Id);
File.Delete(searchFilePath);
Console.WriteLine("Cleanup completed successfully.");
@@ -0,0 +1,30 @@
# File Search with the Responses API
This sample shows how to use the File Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Uploading files and creating vector stores via `AIProjectClient`
- Using `HostedFileSearchTool` with `ChatClientAgent`
- Handling file citation annotations in agent responses
- Cleaning up file resources after use
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,98 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use OpenAPI Tools with AI Agents.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
using Microsoft.Extensions.AI;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
const string AgentInstructions = "You are a helpful assistant that can retrieve the latest currency exchange rates using the Frankfurter API. Always call the API to get live data rather than guessing.";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AITool openApiTool = FoundryAITool.CreateOpenApiTool(CreateOpenAPIFunctionDefinition());
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "OpenAPIToolsAgent",
tools: [openApiTool]);
// Run the agent with a question about EUR exchange rates
Console.WriteLine(await agent.RunAsync("What is the latest EUR exchange rate against the US Dollar (USD) and British Pound (GBP)?"));
OpenApiFunctionDefinition CreateOpenAPIFunctionDefinition()
{
// OpenAPI spec for Frankfurter — a free, no-auth exchange rate API backed by ECB data.
// See https://www.frankfurter.dev/ for documentation.
const string FrankfurterOpenApiSpec = """
{
"openapi": "3.1.0",
"info": {
"title": "Frankfurter Exchange Rate API",
"description": "Free currency exchange rates from the European Central Bank",
"version": "v1"
},
"servers": [
{
"url": "https://api.frankfurter.dev/v1"
}
],
"paths": {
"/latest": {
"get": {
"description": "Get the latest exchange rates for a given base currency",
"operationId": "GetLatestExchangeRates",
"parameters": [
{
"name": "from",
"in": "query",
"description": "Base currency code (e.g. EUR, USD, GBP). Defaults to EUR.",
"required": false,
"schema": {
"type": "string"
}
},
{
"name": "to",
"in": "query",
"description": "Comma-separated list of target currency codes (e.g. USD,GBP,JPY).",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Latest exchange rates",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
}
}
}
}
}
""";
return new(
"get_exchange_rates",
BinaryData.FromString(FrankfurterOpenApiSpec),
new OpenAPIAnonymousAuthenticationDetails())
{
Description = "Get live currency exchange rates from the European Central Bank via Frankfurter"
};
}
@@ -0,0 +1,30 @@
# OpenAPI Tools with the Responses API
This sample shows how to use OpenAPI tools with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Defining an OpenAPI specification inline
- Creating an `OpenAPIFunctionDefinition` for the Frankfurter exchange rate API
- Using `FoundryAITool.CreateOpenApiTool()` with `ChatClientAgent`
- Server-side execution of OpenAPI tool calls
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Bing Custom Search Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
string connectionId = Environment.GetEnvironmentVariable("AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID") ?? throw new InvalidOperationException("AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID is not set.");
string instanceName = Environment.GetEnvironmentVariable("AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME") ?? throw new InvalidOperationException("AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME is not set.");
const string AgentInstructions = """
You are a helpful agent that can use Bing Custom Search tools to assist users.
Use the available Bing Custom Search tools to answer questions and perform tasks.
""";
// Bing Custom Search tool parameters
BingCustomSearchToolOptions bingCustomSearchToolParameters = new([
new BingCustomSearchConfiguration(connectionId, instanceName)
]);
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with Bing Custom Search tool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "BingCustomSearchAgent-RAPI",
tools: [FoundryAITool.CreateBingCustomSearchTool(bingCustomSearchToolParameters)]);
Console.WriteLine($"Created agent: {agent.Name}");
// Run the agent with a search query
AgentResponse response = await agent.RunAsync("Search for the latest news about Microsoft AI");
Console.WriteLine("\n=== Agent Response ===");
foreach (var message in response.Messages)
{
Console.WriteLine(message.Text);
}
@@ -0,0 +1,37 @@
# Bing Custom Search with the Responses API
This sample shows how to use the Bing Custom Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `BingCustomSearchToolParameters` with connection ID and instance name
- Using `FoundryAITool.CreateBingCustomSearchTool()` with `ChatClientAgent`
- Processing search results from agent responses
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
- Bing Custom Search resource configured with a connection ID
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
$env:AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID="your-connection-id" # The full ARM resource URI, e.g., "/subscriptions/.../connections/your-bing-connection"
$env:AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME="your-instance-name" # The Bing Custom Search configuration name (from Azure portal)
```
### Finding the connection ID and instance name
- **Connection ID** (`AZURE_AI_CUSTOM_SEARCH_CONNECTION_ID`): The full ARM resource URI including the `/projects/<name>/connections/<connection-name>` segment. Find the connection name in your Foundry project under **Management center****Connected resources**.
- **Instance Name** (`AZURE_AI_CUSTOM_SEARCH_INSTANCE_NAME`): The **configuration name** from your Bing Custom Search resource (Azure portal → your Bing Custom Search resource → **Configurations**). This is _not_ the Azure resource name or the connection name — it's the name of the specific search configuration that defines which domains/sites to search against.
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use SharePoint Grounding Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
string sharepointConnectionId = Environment.GetEnvironmentVariable("SHAREPOINT_PROJECT_CONNECTION_ID") ?? throw new InvalidOperationException("SHAREPOINT_PROJECT_CONNECTION_ID is not set.");
const string AgentInstructions = """
You are a helpful agent that can use SharePoint tools to assist users.
Use the available SharePoint tools to answer questions and perform tasks.
""";
// Create SharePoint tool options with project connection
var sharepointOptions = new SharePointGroundingToolOptions();
sharepointOptions.ProjectConnections.Add(new ToolProjectConnection(sharepointConnectionId));
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with SharePoint tool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "SharePointAgent-RAPI",
tools: [FoundryAITool.CreateSharepointTool(sharepointOptions)]);
Console.WriteLine($"Created agent: {agent.Name}");
AgentResponse response = await agent.RunAsync("List the documents available in SharePoint");
// Display the response
Console.WriteLine("\n=== Agent Response ===");
Console.WriteLine(response);
// Display grounding annotations if any
foreach (var message in response.Messages)
{
foreach (var content in message.Contents)
{
if (content.Annotations is not null)
{
foreach (var annotation in content.Annotations)
{
Console.WriteLine($"Annotation: {annotation}");
}
}
}
}
@@ -0,0 +1,31 @@
# SharePoint Grounding with the Responses API
This sample shows how to use the SharePoint Grounding tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `SharePointGroundingToolOptions` with project connections
- Using `FoundryAITool.CreateSharepointTool()` with `ChatClientAgent`
- Displaying grounding annotations from agent responses
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
- SharePoint connection configured in your Microsoft Foundry project
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
$env:SHAREPOINT_PROJECT_CONNECTION_ID="your-sharepoint-connection-id" # The full ARM resource URI, e.g., "/subscriptions/.../connections/SharepointTestTool"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Microsoft Fabric Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
string fabricConnectionId = Environment.GetEnvironmentVariable("FABRIC_PROJECT_CONNECTION_ID") ?? throw new InvalidOperationException("FABRIC_PROJECT_CONNECTION_ID is not set.");
const string AgentInstructions = "You are a helpful assistant with access to Microsoft Fabric data. Answer questions based on data available through your Fabric connection.";
// Configure Microsoft Fabric tool options with project connection
var fabricToolOptions = new FabricDataAgentToolOptions();
fabricToolOptions.ProjectConnections.Add(new ToolProjectConnection(fabricConnectionId));
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with Microsoft Fabric tool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: "FabricAgent-RAPI",
tools: [FoundryAITool.CreateMicrosoftFabricTool(fabricToolOptions)]);
Console.WriteLine($"Created agent: {agent.Name}");
// Run the agent with a sample query
AgentResponse response = await agent.RunAsync("What data is available in the connected Fabric workspace?");
Console.WriteLine("\n=== Agent Response ===");
foreach (var message in response.Messages)
{
Console.WriteLine(message.Text);
}
@@ -0,0 +1,31 @@
# Microsoft Fabric with the Responses API
This sample shows how to use the Microsoft Fabric tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `FabricDataAgentToolOptions` with project connections
- Using `FoundryAITool.CreateMicrosoftFabricTool()` with `ChatClientAgent`
- Querying data available through a Fabric connection
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
- Microsoft Fabric connection configured in your Microsoft Foundry project
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
$env:FABRIC_PROJECT_CONNECTION_ID="your-fabric-connection-id" # The full ARM resource URI, e.g., "/subscriptions/.../connections/FabricTestTool"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use the Web Search Tool with a ChatClientAgent.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
const string AgentInstructions = "You are a helpful assistant that can search the web to find current information and answer questions accurately.";
const string AgentName = "WebSearchAgent-RAPI";
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with HostedWebSearchTool.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: [new HostedWebSearchTool()]);
AgentResponse response = await agent.RunAsync("What's the weather today in Seattle?");
// Get the text response
Console.WriteLine($"Response: {response.Text}");
// Getting any annotations/citations generated by the web search tool
foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(c => c.Annotations ?? []))
{
Console.WriteLine($"Annotation: {annotation}");
if (annotation.RawRepresentation is UriCitationMessageAnnotation urlCitation)
{
Console.WriteLine($$"""
Title: {{urlCitation.Title}}
URL: {{urlCitation.Uri}}
""");
}
}
@@ -0,0 +1,29 @@
# Web Search with the Responses API
This sample shows how to use the Web Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Using `HostedWebSearchTool` with `ChatClientAgent`
- Processing web search citations and annotations
- Extracting URL citation details (title, URL) from responses
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,132 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use the Memory Search Tool with AI Agents.
// The Memory Search Tool enables agents to recall information from previous conversations,
// supporting user profile persistence and chat summaries across sessions.
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.AI.Projects.Memory;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
string embeddingModelName = Environment.GetEnvironmentVariable("AZURE_AI_EMBEDDING_DEPLOYMENT_NAME") ?? "text-embedding-ada-002";
string memoryStoreName = Environment.GetEnvironmentVariable("AZURE_AI_MEMORY_STORE_ID") ?? $"foundry-memory-sample-{Guid.NewGuid():N}";
const string AgentInstructions = """
You are a helpful assistant that remembers past conversations.
Use the memory search tool to recall relevant information from previous interactions.
When a user shares personal details or preferences, remember them for future conversations.
""";
const string AgentName = "MemorySearchAgent";
string userScope = $"user_{Environment.MachineName}";
MemorySearchPreviewTool memorySearchTool = new(memoryStoreName, userScope) { UpdateDelayInSecs = 0 };
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create agent using the RAPI path with the MemorySearch tool
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: [FoundryAITool.FromResponseTool(memorySearchTool)]);
// Ensure the memory store exists and has memories to retrieve.
await EnsureMemoryStoreAsync();
try
{
Console.WriteLine("Agent created with Memory Search tool. Starting conversation...\n");
// The agent uses the memory search tool to recall stored information.
Console.WriteLine("User: What's my name and what programming language do I prefer?");
AgentResponse response = await agent.RunAsync("What's my name and what programming language do I prefer?");
Console.WriteLine($"Agent: {response.Messages.LastOrDefault()?.Text}\n");
// Inspect memory search results if available in raw response items.
foreach (var message in response.Messages)
{
if (message.RawRepresentation is MemorySearchToolCall memorySearchResult)
{
Console.WriteLine($"Memory Search Status: {memorySearchResult.Status}");
Console.WriteLine($"Memory Search Results Count: {memorySearchResult.Memories.Count}");
foreach (var memoryItem in memorySearchResult.Memories)
{
Console.WriteLine($" - Memory ID: {memoryItem.MemoryId}");
Console.WriteLine($" Scope: {memoryItem.Scope}");
Console.WriteLine($" Content: {memoryItem.Content}");
Console.WriteLine($" Updated: {memoryItem.UpdatedAt}");
}
}
}
}
finally
{
// Cleanup: Delete the memory store (no server-side agent to clean up in RAPI path).
Console.WriteLine("\nCleaning up...");
await aiProjectClient.MemoryStores.DeleteMemoryStoreAsync(memoryStoreName);
Console.WriteLine("Memory store deleted.");
}
// Helpers — kept at the bottom so the main agent flow above stays clean.
async Task EnsureMemoryStoreAsync()
{
Console.WriteLine($"Creating memory store '{memoryStoreName}'...");
try
{
await aiProjectClient.MemoryStores.GetMemoryStoreAsync(memoryStoreName);
Console.WriteLine("Memory store already exists.");
}
catch (System.ClientModel.ClientResultException ex) when (ex.Status == 404)
{
MemoryStoreDefaultDefinition definition = new(deploymentName, embeddingModelName);
await aiProjectClient.MemoryStores.CreateMemoryStoreAsync(memoryStoreName, definition, "Sample memory store for Memory Search demo");
Console.WriteLine("Memory store created.");
}
// Explicitly add memories from a simulated prior conversation.
Console.WriteLine("Storing memories from a prior conversation...");
MemoryUpdateOptions memoryOptions = new(userScope) { UpdateDelay = 0 };
memoryOptions.Items.Add(ResponseItem.CreateUserMessageItem("My name is Alice and I prefer C#."));
MemoryUpdateResult updateResult = await aiProjectClient.MemoryStores.WaitForMemoriesUpdateAsync(
memoryStoreName: memoryStoreName,
options: memoryOptions,
pollingInterval: 500);
if (updateResult.Status == MemoryStoreUpdateStatus.Failed)
{
throw new InvalidOperationException($"Memory update failed: {updateResult.ErrorDetails}");
}
Console.WriteLine($"Memory update completed (status: {updateResult.Status}).");
// Quick verification that memories are searchable.
Console.WriteLine("Verifying stored memories...");
MemorySearchOptions searchOptions = new(userScope)
{
Items = { ResponseItem.CreateUserMessageItem("What are Alice's preferences?") }
};
MemoryStoreSearchResponse searchResult = await aiProjectClient.MemoryStores.SearchMemoriesAsync(
memoryStoreName: memoryStoreName,
options: searchOptions);
foreach (var memory in searchResult.Memories)
{
Console.WriteLine($" - {memory.MemoryItem.Content}");
}
Console.WriteLine();
}
@@ -0,0 +1,32 @@
# Memory Search with the Responses API
This sample demonstrates how to use the Memory Search tool with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Configuring `MemorySearchPreviewTool` with a memory store and user scope
- Using memory search for cross-conversation recall
- Inspecting `MemorySearchToolCallResponseItem` results
- User profile persistence across conversations
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
- A memory store created beforehand via Azure Portal or Python SDK
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
$env:AZURE_AI_MEMORY_STORE_ID="your-memory-store-name"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,77 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to wrap MCP tools with a DelegatingAIFunction to add custom behavior (e.g., logging).
// Compare with Step09 which shows basic MCP tool usage without wrapping.
// The LoggingMcpTool pattern is useful for diagnostics, metering, or adding approval logic around tool calls.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
using SampleApp;
const string AgentInstructions = "You are a helpful assistant that can help with Microsoft documentation questions. Use the Microsoft Learn MCP tool to search for documentation.";
const string AgentName = "DocsAgent-RAPI";
// Connect to the MCP server locally via HTTP (Streamable HTTP transport).
Console.WriteLine("Connecting to MCP server at https://learn.microsoft.com/api/mcp ...");
await using McpClient mcpClient = await McpClient.CreateAsync(new HttpClientTransport(new()
{
Endpoint = new Uri("https://learn.microsoft.com/api/mcp"),
Name = "Microsoft Learn MCP",
}));
// Retrieve the list of tools available on the MCP server (resolved locally).
IList<McpClientTool> mcpTools = await mcpClient.ListToolsAsync();
Console.WriteLine($"MCP tools available: {string.Join(", ", mcpTools.Select(t => t.Name))}");
// Wrap each MCP tool with a DelegatingAIFunction to log local invocations.
List<AITool> wrappedTools = mcpTools.Select(tool => (AITool)new LoggingMcpTool(tool)).ToList();
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create a AIAgent with the locally-resolved MCP tools.
AIAgent agent = aiProjectClient.AsAIAgent(deploymentName,
instructions: AgentInstructions,
name: AgentName,
tools: wrappedTools);
Console.WriteLine($"Agent '{agent.Name}' created successfully.");
// First query
const string Prompt1 = "How does one create an Azure storage account using az cli?";
Console.WriteLine($"\nUser: {Prompt1}\n");
AgentResponse response1 = await agent.RunAsync(Prompt1);
Console.WriteLine($"Agent: {response1}");
Console.WriteLine("\n=======================================\n");
// Second query
const string Prompt2 = "What is Microsoft Agent Framework?";
Console.WriteLine($"User: {Prompt2}\n");
AgentResponse response2 = await agent.RunAsync(Prompt2);
Console.WriteLine($"Agent: {response2}");
namespace SampleApp
{
/// <summary>
/// Wraps an MCP tool to log when it is invoked locally,
/// confirming that the MCP call is happening client-side.
/// </summary>
internal sealed class LoggingMcpTool(AIFunction innerFunction) : DelegatingAIFunction(innerFunction)
{
protected override ValueTask<object?> InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken)
{
Console.WriteLine($" >> [LOCAL MCP] Invoking tool '{this.Name}' locally...");
return base.InvokeCoreAsync(arguments, cancellationToken);
}
}
}
@@ -0,0 +1,30 @@
# Local MCP with the Responses API
This sample demonstrates how to use a local MCP (Model Context Protocol) client with a `ChatClientAgent` using the Responses API directly.
## What this sample demonstrates
- Connecting to an MCP server via HTTP (Streamable HTTP transport)
- Resolving MCP tools locally and wrapping them with logging
- Using `DelegatingAIFunction` to add custom behavior to MCP tools
- Passing locally-resolved MCP tools to `ChatClientAgent`
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to download files generated by Code Interpreter using Microsoft Foundry.
// Code Interpreter generates files inside containers (cfile_ / cntr_ IDs) which cannot be
// downloaded via the standard Files API. Use ContainerClient from the project's OpenAI client instead.
#pragma warning disable OPENAI001
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-4o-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
// Create an agent with Code Interpreter tool enabled
AIAgent agent = aiProjectClient.AsAIAgent(
deploymentName,
instructions: "You are a helpful assistant that can generate files using code.",
name: "CodeInterpreterAgent",
tools: [new HostedCodeInterpreterTool()]);
// Ask the agent to generate a file
AgentResponse response = await agent.RunAsync(
"Create a CSV file with the multiplication times tables from 1 to 12. Include headers.");
// Display the text response
foreach (TextContent textContent in response.Messages.SelectMany(x => x.Contents).OfType<TextContent>())
{
Console.WriteLine(textContent.Text);
}
// Extract container file citations from response annotations and download.
// AIProjectClient.GetProjectOpenAIClient() returns a ProjectOpenAIClient (inherits from OpenAI.OpenAIClient)
// which supports GetContainerClient(), unlike AzureOpenAIClient which does not.
var containerClient = aiProjectClient.GetProjectOpenAIClient().GetContainerClient();
HashSet<string> downloadedFiles = [];
bool foundContainerFiles = false;
foreach (AIContent content in response.Messages.SelectMany(x => x.Contents))
{
if (content.Annotations is null)
{
continue;
}
foreach (AIAnnotation annotation in content.Annotations)
{
// Container files from Code Interpreter have ContainerFileCitationMessageAnnotation as raw representation
if (annotation is CitationAnnotation citation
&& citation.RawRepresentation is ContainerFileCitationMessageAnnotation containerCitation)
{
foundContainerFiles = true;
// Deduplicate by container+file ID in case the same file is cited multiple times
string key = $"{containerCitation.ContainerId}/{containerCitation.FileId}";
if (!downloadedFiles.Add(key))
{
continue;
}
Console.WriteLine($"\nDownloading container file: {containerCitation.Filename}");
Console.WriteLine($" Container ID: {containerCitation.ContainerId}");
Console.WriteLine($" File ID: {containerCitation.FileId}");
BinaryData fileData = await containerClient.DownloadContainerFileAsync(
containerCitation.ContainerId,
containerCitation.FileId);
// Sanitize filename to prevent path traversal
string safeFilename = Path.GetFileName(containerCitation.Filename);
string outputPath = Path.Combine(Directory.GetCurrentDirectory(), safeFilename);
await File.WriteAllBytesAsync(outputPath, fileData.ToArray());
Console.WriteLine($" Saved to: {outputPath}");
}
}
}
if (!foundContainerFiles)
{
Console.WriteLine("\nNo container file citations found in the response.");
Console.WriteLine("The model may not have generated a downloadable file for this prompt.");
}
@@ -0,0 +1,57 @@
# Code Interpreter File Download (Microsoft Foundry)
This sample demonstrates how to download files generated by Code Interpreter when using Microsoft Foundry.
## What this sample demonstrates
- Creating an agent with Code Interpreter tool using `AIProjectClient.AsAIAgent()`
- Generating files through Code Interpreter (e.g., CSV, Excel, images)
- Extracting container file citations from agent response annotations
- Downloading container files using the `ContainerClient` via `AIProjectClient.GetProjectOpenAIClient()`
## Container files vs regular files
When Code Interpreter generates a file, the file is stored inside a **container** with a `cntr_` prefixed ID. The file itself gets a `cfile_` prefixed ID.
These container files **cannot** be downloaded using the standard Files API (`GetOpenAIFileClient`), which returns 404 for `cfile_` IDs. Instead, you must use the **Containers API** to download them.
### Getting the ContainerClient with Foundry
`AzureOpenAIClient.GetContainerClient()` is not supported and throws `InvalidOperationException`. Instead, use the project's OpenAI client which inherits directly from `OpenAI.OpenAIClient`:
```csharp
// ❌ AzureOpenAIClient does not support ContainerClient
var azureClient = new AzureOpenAIClient(endpoint, credential);
azureClient.GetContainerClient(); // Throws InvalidOperationException
// ✅ Use AIProjectClient's project OpenAI client
var containerClient = aiProjectClient.GetProjectOpenAIClient().GetContainerClient();
await containerClient.DownloadContainerFileAsync("cntr_...", "cfile_...");
```
The container ID and file ID are available from the `ContainerFileCitationMessageAnnotation` annotation in the response, accessible via `CitationAnnotation.RawRepresentation`.
## Prerequisites
- .NET 10 SDK or later
- Microsoft Foundry service endpoint and deployment configured
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
```
## Run the sample
```powershell
dotnet run
```
## See also
- [Code Interpreter File Download with OpenAI](../../openai/Agent_OpenAI_Step06_CodeInterpreterFileDownload/) — same scenario using Public OpenAI
- [Code Interpreter](../Agent_Step14_CodeInterpreter/) — Code Interpreter without file download
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,150 @@
// Copyright (c) Microsoft. All rights reserved.
// Foundry Toolbox via MCP (Streamable HTTP).
//
// Point an `McpClient` at a Foundry Toolbox's MCP endpoint. The agent
// discovers the toolbox's tools at runtime and invokes them locally.
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Net.Http.Headers;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Core;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Experimental API
#pragma warning disable AAIP001 // AgentToolboxes is experimental
// Name of the toolbox to create and connect to.
const string ToolboxName = "research_toolbox";
const string Query = "What tools do you have access to?";
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
TokenCredential credential = new DefaultAzureCredential();
// Comment out if the toolbox already exists in your Foundry project.
var toolboxEndpoint = await CreateSampleToolboxAsync(ToolboxName, endpoint, credential);
// Inject a fresh Azure AI bearer token on every MCP request.
using var httpClient = new HttpClient(new BearerTokenHandler(credential, "https://ai.azure.com/.default")
{
InnerHandler = new HttpClientHandler(),
});
Console.WriteLine($"Connecting to toolbox MCP endpoint: {toolboxEndpoint}");
await using McpClient mcpClient = await McpClient.CreateAsync(
new HttpClientTransport(
new HttpClientTransportOptions
{
Endpoint = new Uri(toolboxEndpoint),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
AdditionalHeaders = new Dictionary<string, string>
{
["Foundry-Features"] = "Toolboxes=V1Preview",
},
},
httpClient));
IList<McpClientTool> mcpTools = await mcpClient.ListToolsAsync();
Console.WriteLine($"Toolbox MCP tools available: {string.Join(", ", mcpTools.Select(t => t.Name))}");
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);
AIAgent agent = aiProjectClient.AsAIAgent(
model: deploymentName,
instructions: "You are a helpful assistant. Use the available toolbox tools to answer the user.",
name: "ToolboxMcpAgent",
tools: [.. mcpTools.Cast<AITool>()]);
Console.WriteLine($"\nUser: {Query}\n");
Console.WriteLine($"Assistant: {await agent.RunAsync(Query)}");
// ---------------------------------------------------------------------------
// Helper: create (or replace) a sample toolbox so the sample runs end-to-end
// ---------------------------------------------------------------------------
static async Task<string> CreateSampleToolboxAsync(string name, string endpoint, TokenCredential credential)
{
// Toolboxes are normally configured in the Foundry portal or a deployment
// script, not the application itself. This helper exists so the sample can
// be run end-to-end without first setting a toolbox up by hand.
// The Foundry-Features header is currently required for toolbox CRUD operations.
var options = new AgentAdministrationClientOptions();
options.AddPolicy(new FoundryFeaturesPolicy("Toolboxes=V1Preview"), PipelinePosition.PerCall);
var adminClient = new AgentAdministrationClient(new Uri(endpoint), credential, options);
var toolboxClient = adminClient.GetAgentToolboxes();
// Delete existing toolbox if present (ignore 404).
try
{
await toolboxClient.DeleteAsync(name);
Console.WriteLine($"Deleted existing toolbox '{name}'");
}
catch (ClientResultException ex) when (ex.Status == 404)
{
// Toolbox does not exist — nothing to delete.
}
// Create a fresh version with a single MCP tool.
MCPToolboxTool mcpTool = new("api-specs")
{
ServerUri = new Uri("https://gitmcp.io/Azure/azure-rest-api-specs"),
ToolCallApprovalPolicy = new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.NeverRequireApproval),
};
ToolboxVersion created = (await toolboxClient.CreateVersionAsync(
name: name,
tools: [mcpTool],
description: "Sample toolbox with an MCP tool — created by Agent_Step25 sample.")).Value;
Console.WriteLine($"Created toolbox '{created.Name}' v{created.Version} ({created.Tools.Count} tool(s))");
return $"{endpoint}/toolboxes/{created.Name}/mcp?api-version=v{created.Version}";
}
// ---------------------------------------------------------------------------
// Pipeline policy: adds the Foundry-Features header for toolbox CRUD calls
// ---------------------------------------------------------------------------
internal sealed class FoundryFeaturesPolicy(string feature) : PipelinePolicy
{
private const string FeatureHeader = "Foundry-Features";
public override void Process(PipelineMessage message, IReadOnlyList<PipelinePolicy> pipeline, int currentIndex)
{
message.Request.Headers.Add(FeatureHeader, feature);
ProcessNext(message, pipeline, currentIndex);
}
public override ValueTask ProcessAsync(PipelineMessage message, IReadOnlyList<PipelinePolicy> pipeline, int currentIndex)
{
message.Request.Headers.Add(FeatureHeader, feature);
return ProcessNextAsync(message, pipeline, currentIndex);
}
}
// ---------------------------------------------------------------------------
// DelegatingHandler: attaches a fresh Azure AI bearer token to every request
// ---------------------------------------------------------------------------
internal sealed class BearerTokenHandler(TokenCredential credential, string scope) : DelegatingHandler
{
private readonly TokenRequestContext _tokenContext = new([scope]);
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AccessToken token = await credential.GetTokenAsync(this._tokenContext, cancellationToken).ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
@@ -0,0 +1,32 @@
# Foundry Toolbox via MCP
This sample shows how to use a Foundry Toolbox by pointing an `McpClient` at the toolbox's MCP endpoint. The agent discovers the toolbox's tools at runtime and invokes them locally over MCP.
## What this sample demonstrates
- Connecting to a Foundry toolbox's MCP endpoint via Streamable HTTP transport
- Injecting a fresh Azure AI bearer token (`https://ai.azure.com/.default`) on every MCP request
- Passing the discovered MCP tools to `AIProjectClient.AsAIAgent(...)`
- Optional helper to create (or replace) a sample toolbox in the project so the sample is runnable end-to-end
## Prerequisites
- A Microsoft Foundry project with a toolbox configured (or let the sample create one for you)
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
The sample creates a toolbox named `research_toolbox` in your Foundry project on
startup, then connects to its MCP endpoint at
`{FOUNDRY_PROJECT_ENDPOINT}/toolboxes/research_toolbox/mcp?api-version=v{version}`.
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.Projects" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Mcp\Microsoft.Agents.AI.Mcp.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,93 @@
// Copyright (c) Microsoft. All rights reserved.
// Foundry Toolbox MCP Skills.
//
// Uses AgentSkillsProviderBuilder to discover MCP-based skills from a Foundry
// Toolbox endpoint and inject them as AIContextProviders so the agent can
// discover and use them at runtime.
using System.Net.Http.Headers;
using Azure.AI.Projects;
using Azure.Core;
using Azure.Identity;
using Microsoft.Agents.AI;
using ModelContextProtocol.Client;
// --- Configuration ---
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
string toolboxMcpServerUrl = Environment.GetEnvironmentVariable("FOUNDRY_TOOLBOX_MCP_SERVER_URL")
?? throw new InvalidOperationException("FOUNDRY_TOOLBOX_MCP_SERVER_URL is not set.");
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
TokenCredential credential = new DefaultAzureCredential();
using var httpClient = new HttpClient(new BearerTokenHandler(credential, "https://ai.azure.com/.default")
{
InnerHandler = new HttpClientHandler(),
});
// --- Connect to the Foundry Toolbox MCP endpoint ---
await using McpClient mcpClient = await McpClient.CreateAsync(
new HttpClientTransport(
new HttpClientTransportOptions
{
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
AdditionalHeaders = new Dictionary<string, string>
{
["Foundry-Features"] = "Toolboxes=V1Preview",
},
},
httpClient));
// --- Discover MCP-based skills ---
var skillsProvider = new AgentSkillsProviderBuilder()
.UseMcpSkills(mcpClient)
.Build();
// --- Create the agent ---
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);
AIAgent agent = aiProjectClient.AsAIAgent(
options: new ChatClientAgentOptions
{
Name = "ToolboxMcpSkillsAgent",
ChatOptions = new()
{
ModelId = deploymentName,
Instructions = "You are a helpful assistant. Use available skills to answer the user.",
},
AIContextProviders = [skillsProvider],
});
// --- Interactive prompt ---
Console.Write("User: ");
string? query = Console.ReadLine();
if (string.IsNullOrWhiteSpace(query))
{
Console.WriteLine("No input provided.");
return;
}
Console.WriteLine($"Assistant: {await agent.RunAsync(query)}");
// ---------------------------------------------------------------------------
// DelegatingHandler: attaches a fresh Foundry bearer token to every request
// ---------------------------------------------------------------------------
internal sealed class BearerTokenHandler(TokenCredential credential, string scope) : DelegatingHandler
{
private readonly TokenRequestContext _tokenContext = new([scope]);
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AccessToken token = await credential.GetTokenAsync(this._tokenContext, cancellationToken).ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
@@ -0,0 +1,33 @@
# Foundry Toolbox MCP Skills
This sample uses
`AgentSkillsProviderBuilder` to discover MCP-based skills from a Foundry Toolbox endpoint
and inject them as `AIContextProviders` so the agent can discover and use them at runtime.
## What this sample demonstrates
- Connecting to a Foundry toolbox's MCP endpoint via Streamable HTTP transport
- Injecting a fresh Azure AI bearer token (`https://ai.azure.com/.default`) on every MCP request
- Using `AgentSkillsProviderBuilder.UseMcpSkills(client)` to discover skills from the toolbox
- Injecting the discovered skills into `AIProjectClient.AsAIAgent(...)` via `AIContextProviders`
## Prerequisites
- A Microsoft Foundry project with a toolbox already configured
- The toolbox MCP endpoint must expose `skill://index.json` with `skill-md` entries (SEP-2640). If the resource is absent, the sample runs but the skills provider will be empty.
- An authenticated Azure identity (for example, sign in with `az login`)
Set the following environment variables:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
$env:FOUNDRY_TOOLBOX_MCP_SERVER_URL="https://your-foundry-service.services.ai.azure.com/api/projects/your-project/toolboxes/your-toolbox/mcp?api-version=v1"
```
## Run the sample
```powershell
dotnet run
```
@@ -0,0 +1,90 @@
# Getting started with Foundry Agents
These samples demonstrate how to use Microsoft Foundry with Agent Framework.
## Quick start
You can create a Foundry agent directly with the `FoundryAgent` type:
```csharp
FoundryAgent agent = new(
new Uri(endpoint),
new DefaultAzureCredential(),
model: "gpt-5.4-mini",
instructions: "You are good at telling jokes.",
name: "JokerAgent");
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
```
Or using the `AIProjectClient.AsAIAgent(...)` extensions:
```csharp
AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential());
FoundryAgent agent = aiProjectClient.AsAIAgent(
model: deploymentName,
instructions: "You are good at telling jokes.",
name: "JokerAgent");
```
## Prerequisites
- .NET 10 SDK or later
- Foundry project endpoint
- An authenticated Azure identity (for example, sign in with `az login`)
Set:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project"
$env:FOUNDRY_MODEL="gpt-5.4-mini"
```
Some samples require extra tool-specific environment variables. See each sample for details.
## Samples
| Sample | Description |
| --- | --- |
| [FoundryAgent lifecycle](./Agent_Step00_FoundryAgentLifecycle/) | Create a FoundryAgent directly with endpoint and credentials |
| [Basics (Responses API)](./Agent_Step01_Basics/) | Create and run an agent using AsAIAgent extensions |
| [Multi-turn conversation](./Agent_Step02.1_MultiturnConversation/) | Multi-turn using sessions and response ID chaining |
| [Multi-turn with server conversations](./Agent_Step02.2_MultiturnWithServerConversations/) | Server-side conversations visible in Foundry UI |
| [Using function tools](./Agent_Step03_UsingFunctionTools/) | Function tools |
| [Function tools with approvals](./Agent_Step04_UsingFunctionToolsWithApprovals/) | Human-in-the-loop approval |
| [Structured output](./Agent_Step05_StructuredOutput/) | Structured output with JSON schema |
| [Persisted conversations](./Agent_Step06_PersistedConversations/) | Persisting and resuming conversations |
| [Observability](./Agent_Step07_Observability/) | OpenTelemetry observability |
| [Dependency injection](./Agent_Step08_DependencyInjection/) | DI with a hosted service |
| [Using MCP client as tools](./Agent_Step09_UsingMcpClientAsTools/) | MCP client tools |
| [Using images](./Agent_Step10_UsingImages/) | Image multi-modality |
| [Agent as function tool](./Agent_Step11_AsFunctionTool/) | Agent as a function tool for another |
| [Middleware](./Agent_Step12_Middleware/) | Multiple middleware layers |
| [Plugins](./Agent_Step13_Plugins/) | Plugins with dependency injection |
| [Code interpreter](./Agent_Step14_CodeInterpreter/) | Code interpreter tool |
| [Computer use](./Agent_Step15_ComputerUse/) | Computer use tool |
| [File search](./Agent_Step16_FileSearch/) | File search tool |
| [OpenAPI tools](./Agent_Step17_OpenAPITools/) | OpenAPI tools |
| [Bing custom search](./Agent_Step18_BingCustomSearch/) | Bing Custom Search tool |
| [SharePoint](./Agent_Step19_SharePoint/) | SharePoint grounding tool |
| [Microsoft Fabric](./Agent_Step20_MicrosoftFabric/) | Microsoft Fabric tool |
| [Web search](./Agent_Step21_WebSearch/) | Web search tool |
| [Memory search](./Agent_Step22_MemorySearch/) | Memory search tool |
| [Local MCP](./Agent_Step23_LocalMCP/) | Local MCP client with HTTP transport |
| [Code interpreter file download](./Agent_Step24_CodeInterpreterFileDownload/) | Download container files generated by code interpreter |
| [Foundry toolbox via MCP](./Agent_Step25_FoundryToolboxMcp/README.md) | Use a Foundry Toolbox from a non-hosted agent via its MCP endpoint |
| [Foundry toolbox MCP skills](./Agent_Step26_FoundryToolboxMcpSkills/README.md) | Use a Foundry Toolbox with MCP-based skills discovery (SEP-2640) via AIContextProviders |
## Running the samples
Use the basics sample for a quick smoke test:
```powershell
cd dotnet/samples/02-agents/AgentProviders/foundry
dotnet run --project .\Agent_Step01_Basics
```
If you want to exercise the full create-run-delete lifecycle, run `Agent_Step00_FoundryAgentLifecycle`.