Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
be315cb
Initial plan
Copilot Mar 11, 2026
199984a
Update code for Microsoft.Extensions.AI.Abstractions 10.4.0 breaking …
Copilot Mar 11, 2026
0bca676
Update OpenAI 2.9.1, ME.AI 10.4.0, fix breaking API changes
Copilot Mar 11, 2026
0d39b0c
Fix remaining ME.AI 10.4.0 breaking changes: MCP approval types, .Out…
Copilot Mar 11, 2026
81c6d89
Use pattern matching with `when` for ToolApprovalRequestContent/Funct…
Copilot Mar 11, 2026
da2a21d
Update Azure.AI.OpenAI to 2.9.0-beta.1
Copilot Mar 17, 2026
9fd42d5
Fix remaining GetResponsesClient(model) build failures for Azure.AI.O…
Copilot Mar 17, 2026
94460d1
Address review feedback: remove redundant type checks in TestRequestA…
Copilot Mar 17, 2026
e599cc7
Update Azure.AI.Projects to 2.0.0-beta.2 with namespace migration
Copilot Mar 18, 2026
133a95c
Fix remaining type renames for Azure.AI.Projects 2.0.0-beta.2
Copilot Mar 18, 2026
522f25a
Fix format errors and OpenTelemetry test for ME.AI 10.4.0
rogerbarreto Mar 18, 2026
61fd488
Fix GetRepoFolder() to work in git worktrees
rogerbarreto Mar 18, 2026
67d14c8
Fix formatting: remove unused usings and fix import ordering
rogerbarreto Mar 18, 2026
c1c10a1
Disable AzureAIAgentsPersistent integration tests (#4769)
rogerbarreto Mar 18, 2026
e98ebed
Add README with compatibility note for AzureAI.Persistent (#4769)
rogerbarreto Mar 18, 2026
1b1fb1a
Merge branch 'main' into copilot/update-openai-and-microsoft-extensio…
rogerbarreto Mar 18, 2026
8e0be02
Fix file encoding: restore UTF-8 BOM on Persistent test files
rogerbarreto Mar 18, 2026
27b3ba2
Mark AzureAI.Persistent as IsPackable=false (#4769)
rogerbarreto Mar 19, 2026
b326514
Moving IsPackable after import
rogerbarreto Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
<PackageVersion Include="Aspire.Microsoft.Azure.Cosmos" Version="$(AspireAppHostSdkVersion)" />
<PackageVersion Include="CommunityToolkit.Aspire.OllamaSharp" Version="13.0.0" />
<!-- Azure.* -->
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0-beta.1" />
<PackageVersion Include="Azure.AI.Projects.OpenAI" Version="2.0.0-beta.1" />
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.8" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.8.0-beta.1" />
<PackageVersion Include="Azure.Identity" Version="1.17.1" />
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0-beta.2" />
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.9" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.9.0-beta.1" />
<PackageVersion Include="Azure.Identity" Version="1.19.0" />
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
<!-- Google Gemini -->
<PackageVersion Include="Google.GenAI" Version="0.11.0" />
Expand All @@ -40,12 +39,12 @@
<PackageVersion Include="System.CodeDom" Version="10.0.0" />
<PackageVersion Include="System.Collections.Immutable" Version="10.0.1" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-rc.2.25502.107" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="10.0.3" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="10.0.4" />
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="10.0.4" />
<PackageVersion Include="System.Net.Http.Json" Version="10.0.0" />
<PackageVersion Include="System.Net.ServerSentEvents" Version="10.0.3" />
<PackageVersion Include="System.Text.Json" Version="10.0.3" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.3" />
<PackageVersion Include="System.Net.ServerSentEvents" Version="10.0.4" />
<PackageVersion Include="System.Text.Json" Version="10.0.4" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.4" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
<PackageVersion Include="System.Net.Security" Version="4.3.2" />
<!-- OpenTelemetry -->
Expand All @@ -64,24 +63,24 @@
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.0.0" />
<!-- Microsoft.Extensions.* -->
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.3.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="10.3.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation" Version="10.3.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation.Quality" Version="10.3.0" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation.Quality" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation.Safety" Version="10.3.0-preview.1.26109.11" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.3.0" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.4" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.4" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.VectorData.Abstractions" Version="9.7.0" />
Expand Down Expand Up @@ -111,9 +110,9 @@
<PackageVersion Include="Microsoft.ML.OnnxRuntimeGenAI" Version="0.10.0" />
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="2.0.0" />
<PackageVersion Include="OllamaSharp" Version="5.4.8" />
<PackageVersion Include="OpenAI" Version="2.8.0" />
<PackageVersion Include="OpenAI" Version="2.9.1" />
<!-- Identity -->
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.78.0" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.83.1" />
<!-- Workflows -->
<PackageVersion Include="Microsoft.Agents.ObjectModel" Version="2026.2.4.1" />
<PackageVersion Include="Microsoft.Agents.ObjectModel.Json" Version="2026.2.4.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@
{
switch (content)
{
case FunctionApprovalRequestContent approvalRequest:
DisplayApprovalRequest(approvalRequest);
case ToolApprovalRequestContent approvalRequest when approvalRequest.ToolCall is FunctionCallContent fcc:
DisplayApprovalRequest(approvalRequest, fcc);

Console.Write($"\nApprove '{approvalRequest.FunctionCall.Name}'? (yes/no): ");
Console.Write($"\nApprove '{fcc.Name}'? (yes/no): ");
string? userInput = Console.ReadLine();
bool approved = userInput?.ToUpperInvariant() is "YES" or "Y";

FunctionApprovalResponseContent approvalResponse = approvalRequest.CreateResponse(approved);
ToolApprovalResponseContent approvalResponse = approvalRequest.CreateResponse(approved);

if (approvalRequest.AdditionalProperties != null)
{
Expand Down Expand Up @@ -128,19 +128,19 @@
}

#pragma warning disable MEAI001
static void DisplayApprovalRequest(FunctionApprovalRequestContent approvalRequest)
static void DisplayApprovalRequest(ToolApprovalRequestContent approvalRequest, FunctionCallContent fcc)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine();
Console.WriteLine("============================================================");
Console.WriteLine("APPROVAL REQUIRED");
Console.WriteLine("============================================================");
Console.WriteLine($"Function: {approvalRequest.FunctionCall.Name}");
Console.WriteLine($"Function: {fcc.Name}");

if (approvalRequest.FunctionCall.Arguments != null)
if (fcc.Arguments != null)
{
Console.WriteLine("Arguments:");
foreach (var arg in approvalRequest.FunctionCall.Arguments)
foreach (var arg in fcc.Arguments)
{
Console.WriteLine($" {arg.Key} = {arg.Value}");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

/// <summary>
/// A delegating agent that handles server function approval requests and responses.
/// Transforms between FunctionApprovalRequestContent/FunctionApprovalResponseContent
/// Transforms between ToolApprovalRequestContent/ToolApprovalResponseContent
/// and the server's request_approval tool call pattern.
/// </summary>
internal sealed class ServerFunctionApprovalClientAgent : DelegatingAIAgent
Expand Down Expand Up @@ -50,14 +50,14 @@ protected override async IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingA
}

#pragma warning disable MEAI001 // Type is for evaluation purposes only
private static FunctionResultContent ConvertApprovalResponseToToolResult(FunctionApprovalResponseContent approvalResponse, JsonSerializerOptions jsonOptions)
private static FunctionResultContent ConvertApprovalResponseToToolResult(ToolApprovalResponseContent approvalResponse, JsonSerializerOptions jsonOptions)
{
return new FunctionResultContent(
callId: approvalResponse.Id,
callId: approvalResponse.RequestId,
result: JsonSerializer.SerializeToElement(
new ApprovalResponse
{
ApprovalId = approvalResponse.Id,
ApprovalId = approvalResponse.RequestId,
Approved = approvalResponse.Approved
},
jsonOptions));
Expand Down Expand Up @@ -89,7 +89,7 @@ private static List<ChatMessage> ProcessOutgoingServerFunctionApprovals(
{
List<ChatMessage>? result = null;

Dictionary<string, FunctionApprovalRequestContent> approvalRequests = [];
Dictionary<string, ToolApprovalRequestContent> approvalRequests = [];
for (var messageIndex = 0; messageIndex < messages.Count; messageIndex++)
{
var message = messages[messageIndex];
Expand All @@ -102,21 +102,21 @@ private static List<ChatMessage> ProcessOutgoingServerFunctionApprovals(
var content = message.Contents[contentIndex];

// Handle pending approval requests (transform to tool call)
if (content is FunctionApprovalRequestContent approvalRequest &&
if (content is ToolApprovalRequestContent approvalRequest &&
approvalRequest.AdditionalProperties?.TryGetValue("original_function", out var originalFunction) == true &&
originalFunction is FunctionCallContent original)
{
approvalRequests[approvalRequest.Id] = approvalRequest;
approvalRequests[approvalRequest.RequestId] = approvalRequest;
transformedContents ??= CopyContentsUpToIndex(message.Contents, contentIndex);
transformedContents.Add(original);
}
// Handle pending approval responses (transform to tool result)
else if (content is FunctionApprovalResponseContent approvalResponse &&
approvalRequests.TryGetValue(approvalResponse.Id, out var correspondingRequest))
else if (content is ToolApprovalResponseContent approvalResponse &&
approvalRequests.TryGetValue(approvalResponse.RequestId, out var correspondingRequest))
{
transformedContents ??= CopyContentsUpToIndex(message.Contents, contentIndex);
transformedContents.Add(ConvertApprovalResponseToToolResult(approvalResponse, jsonSerializerOptions));
approvalRequests.Remove(approvalResponse.Id);
approvalRequests.Remove(approvalResponse.RequestId);
correspondingRequest.AdditionalProperties?.Remove("original_function");
}
// Skip historical approval content
Expand Down Expand Up @@ -198,8 +198,8 @@ private static AgentResponseUpdate ProcessIncomingServerApprovalRequests(
var functionCallArgs = (Dictionary<string, object?>?)approvalRequest.FunctionArguments?
.Deserialize(jsonSerializerOptions.GetTypeInfo(typeof(Dictionary<string, object?>)));

var approvalRequestContent = new FunctionApprovalRequestContent(
id: approvalRequest.ApprovalId,
var approvalRequestContent = new ToolApprovalRequestContent(
requestId: approvalRequest.ApprovalId,
new FunctionCallContent(
callId: approvalRequest.ApprovalId,
name: approvalRequest.FunctionName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

/// <summary>
/// A delegating agent that handles function approval requests on the server side.
/// Transforms between FunctionApprovalRequestContent/FunctionApprovalResponseContent
/// Transforms between ToolApprovalRequestContent/ToolApprovalResponseContent
/// and the request_approval tool call pattern for client communication.
/// </summary>
internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
Expand Down Expand Up @@ -50,7 +50,7 @@ protected override async IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingA
}

#pragma warning disable MEAI001 // Type is for evaluation purposes only
private static FunctionApprovalRequestContent ConvertToolCallToApprovalRequest(FunctionCallContent toolCall, JsonSerializerOptions jsonSerializerOptions)
private static ToolApprovalRequestContent ConvertToolCallToApprovalRequest(FunctionCallContent toolCall, JsonSerializerOptions jsonSerializerOptions)
{
if (toolCall.Name != "request_approval" || toolCall.Arguments == null)
{
Expand All @@ -67,15 +67,15 @@ reqObj is JsonElement argsElement &&
throw new InvalidOperationException("Failed to deserialize approval request from tool call");
}

return new FunctionApprovalRequestContent(
id: request.ApprovalId,
return new ToolApprovalRequestContent(
requestId: request.ApprovalId,
new FunctionCallContent(
callId: request.ApprovalId,
name: request.FunctionName,
arguments: request.FunctionArguments));
}

private static FunctionApprovalResponseContent ConvertToolResultToApprovalResponse(FunctionResultContent result, FunctionApprovalRequestContent approval, JsonSerializerOptions jsonSerializerOptions)
private static ToolApprovalResponseContent ConvertToolResultToApprovalResponse(FunctionResultContent result, ToolApprovalRequestContent approval, JsonSerializerOptions jsonSerializerOptions)
{
var approvalResponse = result.Result is JsonElement je ?
(ApprovalResponse?)je.Deserialize(jsonSerializerOptions.GetTypeInfo(typeof(ApprovalResponse))) :
Expand Down Expand Up @@ -121,7 +121,7 @@ private static List<ChatMessage> ProcessIncomingFunctionApprovals(
// Track approval ID to original call ID mapping
_ = new Dictionary<string, string>();
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Dictionary<string, FunctionApprovalRequestContent> trackedRequestApprovalToolCalls = new(); // Remote approvals
Dictionary<string, ToolApprovalRequestContent> trackedRequestApprovalToolCalls = new(); // Remote approvals
for (int messageIndex = 0; messageIndex < messages.Count; messageIndex++)
{
var message = messages[messageIndex];
Expand Down Expand Up @@ -181,11 +181,10 @@ private static AgentResponseUpdate ProcessOutgoingApprovalRequests(
{
var content = update.Contents[i];
#pragma warning disable MEAI001 // Type is for evaluation purposes only
if (content is FunctionApprovalRequestContent request)
if (content is ToolApprovalRequestContent request && request.ToolCall is FunctionCallContent functionCall)
{
updatedContents ??= [.. update.Contents];
var functionCall = request.FunctionCall;
var approvalId = request.Id;
var approvalId = request.RequestId;

var approvalData = new ApprovalRequest
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// This sample shows how to create and use a AI agents with Azure Foundry Agents as the backend.

using Azure.AI.Projects;
using Azure.AI.Projects.OpenAI;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetResponsesClient(deploymentName)
.AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");
.GetResponsesClient()
.AsAIAgent(model: deploymentName, instructions: "You are good at telling jokes.", name: "Joker");

// Invoke the agent and output the text result.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
Expand All @@ -29,8 +29,8 @@
AIAgent agentStoreFalse = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetResponsesClient(deploymentName)
.AsIChatClientWithStoredOutputDisabled()
.GetResponsesClient()
.AsIChatClientWithStoredOutputDisabled(model: deploymentName)
.AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");

// Invoke the agent and output the text result.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

AIAgent agent = new OpenAIClient(
apiKey)
.GetResponsesClient(model)
.AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");
.GetResponsesClient()
.AsAIAgent(model: model, instructions: "You are good at telling jokes.", name: "Joker");

// Invoke the agent and output the text result.
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

// --- Agent Setup ---
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient(deploymentName)
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
Expand All @@ -32,7 +32,8 @@
Instructions = "You are a helpful assistant.",
},
AIContextProviders = [skillsProvider],
});
},
model: deploymentName);

// --- Example 1: Expense policy question (loads FAQ resource) ---
Console.WriteLine("Example 1: Checking expense policy FAQ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
var model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-5";

var client = new OpenAIClient(apiKey)
.GetResponsesClient(model)
.AsIChatClient().AsBuilder()
.GetResponsesClient()
.AsIChatClient(model).AsBuilder()
.ConfigureOptions(o =>
{
o.Reasoning = new()
Expand Down
Loading
Loading