mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Update to M.E.AI 10.3.0 (#3822)
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
a427af91a9
commit
b52136952f
@@ -33,18 +33,18 @@
|
||||
<!-- Newtonsoft.Json -->
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<!-- System.* -->
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.2" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.3" />
|
||||
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
|
||||
<PackageVersion Include="System.ClientModel" Version="1.8.1" />
|
||||
<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.2" />
|
||||
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="10.0.3" />
|
||||
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="10.0.0" />
|
||||
<PackageVersion Include="System.Net.Http.Json" Version="10.0.0" />
|
||||
<PackageVersion Include="System.Net.ServerSentEvents" Version="10.0.1" />
|
||||
<PackageVersion Include="System.Text.Json" Version="10.0.2" />
|
||||
<PackageVersion Include="System.Threading.Channels" Version="10.0.2" />
|
||||
<PackageVersion Include="System.Text.Json" Version="10.0.3" />
|
||||
<PackageVersion Include="System.Threading.Channels" Version="10.0.3" />
|
||||
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
|
||||
<PackageVersion Include="System.Net.Security" Version="4.3.2" />
|
||||
<!-- OpenTelemetry -->
|
||||
@@ -61,9 +61,9 @@
|
||||
<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.2.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="10.2.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.2.0-preview.1.26063.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.3.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="10.3.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.3.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" />
|
||||
@@ -71,11 +71,11 @@
|
||||
<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.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3" />
|
||||
<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.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
|
||||
<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" />
|
||||
|
||||
+3
-8
@@ -5,7 +5,6 @@
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI;
|
||||
using OpenAI.Responses;
|
||||
|
||||
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
|
||||
var model = Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-5";
|
||||
@@ -15,14 +14,10 @@ var client = new OpenAIClient(apiKey)
|
||||
.AsIChatClient().AsBuilder()
|
||||
.ConfigureOptions(o =>
|
||||
{
|
||||
o.RawRepresentationFactory = _ => new CreateResponseOptions()
|
||||
o.Reasoning = new()
|
||||
{
|
||||
ReasoningOptions = new()
|
||||
{
|
||||
ReasoningEffortLevel = ResponseReasoningEffortLevel.Medium,
|
||||
// Verbosity requires OpenAI verified Organization
|
||||
ReasoningSummaryVerbosity = ResponseReasoningSummaryVerbosity.Detailed
|
||||
}
|
||||
Effort = ReasoningEffort.Medium,
|
||||
Output = ReasoningOutput.Full,
|
||||
};
|
||||
}).Build();
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ AIAgent agent = await aiProjectClient.CreateAIAgentAsync(name: VisionName, model
|
||||
|
||||
ChatMessage message = new(ChatRole.User, [
|
||||
new TextContent("What do you see in this image?"),
|
||||
new DataContent(File.ReadAllBytes("assets/walkway.jpg"), "image/jpeg")
|
||||
await DataContent.LoadFromAsync("assets/walkway.jpg"),
|
||||
]);
|
||||
|
||||
AgentSession session = await agent.CreateSessionAsync();
|
||||
|
||||
@@ -283,8 +283,13 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
TextOptions = new() { TextFormat = ToOpenAIResponseTextFormat(options.ChatOptions?.ResponseFormat, options.ChatOptions) }
|
||||
};
|
||||
|
||||
// Attempt to capture breaking glass options from the raw representation factory that match the agent definition.
|
||||
if (options.ChatOptions?.RawRepresentationFactory?.Invoke(new NoOpChatClient()) is CreateResponseOptions respCreationOptions)
|
||||
// Map reasoning options from the abstraction-level ChatOptions.Reasoning,
|
||||
// falling back to extracting from the raw representation factory for breaking glass scenarios.
|
||||
if (options.ChatOptions?.Reasoning is { } reasoning)
|
||||
{
|
||||
agentDefinition.ReasoningOptions = ToResponseReasoningOptions(reasoning);
|
||||
}
|
||||
else if (options.ChatOptions?.RawRepresentationFactory?.Invoke(new NoOpChatClient()) is CreateResponseOptions respCreationOptions)
|
||||
{
|
||||
agentDefinition.ReasoningOptions = respCreationOptions.ReasoningOptions;
|
||||
}
|
||||
@@ -770,6 +775,36 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private static ResponseReasoningOptions? ToResponseReasoningOptions(ReasoningOptions reasoning)
|
||||
{
|
||||
ResponseReasoningEffortLevel? effortLevel = reasoning.Effort switch
|
||||
{
|
||||
ReasoningEffort.Low => ResponseReasoningEffortLevel.Low,
|
||||
ReasoningEffort.Medium => ResponseReasoningEffortLevel.Medium,
|
||||
ReasoningEffort.High => ResponseReasoningEffortLevel.High,
|
||||
ReasoningEffort.ExtraHigh => ResponseReasoningEffortLevel.High,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
ResponseReasoningSummaryVerbosity? summary = reasoning.Output switch
|
||||
{
|
||||
ReasoningOutput.Summary => ResponseReasoningSummaryVerbosity.Concise,
|
||||
ReasoningOutput.Full => ResponseReasoningSummaryVerbosity.Detailed,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (effortLevel is null && summary is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ResponseReasoningOptions
|
||||
{
|
||||
ReasoningEffortLevel = effortLevel,
|
||||
ReasoningSummaryVerbosity = summary,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSerializable(typeof(JsonElement))]
|
||||
|
||||
@@ -217,16 +217,15 @@ public sealed class GitHubCopilotAgent : AIAgent, IAsyncDisposable
|
||||
}
|
||||
});
|
||||
|
||||
List<string> tempFiles = [];
|
||||
string? tempDir = null;
|
||||
try
|
||||
{
|
||||
// Build prompt from text content
|
||||
string prompt = string.Join("\n", messages.Select(m => m.Text));
|
||||
|
||||
// Handle DataContent as attachments
|
||||
List<UserMessageDataAttachmentsItem>? attachments = await ProcessDataContentAttachmentsAsync(
|
||||
(List<UserMessageDataAttachmentsItem>? attachments, tempDir) = await ProcessDataContentAttachmentsAsync(
|
||||
messages,
|
||||
tempFiles,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Send the message with attachments
|
||||
@@ -245,7 +244,7 @@ public sealed class GitHubCopilotAgent : AIAgent, IAsyncDisposable
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupTempFiles(tempFiles);
|
||||
CleanupTempDir(tempDir);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -410,45 +409,23 @@ public sealed class GitHubCopilotAgent : AIAgent, IAsyncDisposable
|
||||
return new SessionConfig { Tools = mappedTools, SystemMessage = systemMessage };
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> s_mediaTypeExtensions = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["image/png"] = ".png",
|
||||
["image/jpeg"] = ".jpg",
|
||||
["image/jpg"] = ".jpg",
|
||||
["image/gif"] = ".gif",
|
||||
["image/webp"] = ".webp",
|
||||
["image/svg+xml"] = ".svg",
|
||||
["text/plain"] = ".txt",
|
||||
["text/html"] = ".html",
|
||||
["text/markdown"] = ".md",
|
||||
["application/json"] = ".json",
|
||||
["application/xml"] = ".xml",
|
||||
["application/pdf"] = ".pdf"
|
||||
};
|
||||
|
||||
private static string GetExtensionForMediaType(string? mediaType)
|
||||
{
|
||||
return mediaType is not null && s_mediaTypeExtensions.TryGetValue(mediaType, out string? extension) ? extension : ".dat";
|
||||
}
|
||||
|
||||
private static async Task<List<UserMessageDataAttachmentsItem>?> ProcessDataContentAttachmentsAsync(
|
||||
private static async Task<(List<UserMessageDataAttachmentsItem>? Attachments, string? TempDir)> ProcessDataContentAttachmentsAsync(
|
||||
IEnumerable<ChatMessage> messages,
|
||||
List<string> tempFiles,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
List<UserMessageDataAttachmentsItem>? attachments = null;
|
||||
string? tempDir = null;
|
||||
foreach (ChatMessage message in messages)
|
||||
{
|
||||
foreach (AIContent content in message.Contents)
|
||||
{
|
||||
if (content is DataContent dataContent)
|
||||
{
|
||||
// Write DataContent to a temp file
|
||||
string tempFilePath = Path.Combine(Path.GetTempPath(), $"agentframework_copilot_data_{Guid.NewGuid()}{GetExtensionForMediaType(dataContent.MediaType)}");
|
||||
await File.WriteAllBytesAsync(tempFilePath, dataContent.Data.ToArray(), cancellationToken).ConfigureAwait(false);
|
||||
tempFiles.Add(tempFilePath);
|
||||
tempDir ??= Directory.CreateDirectory(
|
||||
Path.Combine(Path.GetTempPath(), $"af_copilot_{Guid.NewGuid():N}")).FullName;
|
||||
|
||||
string tempFilePath = await dataContent.SaveToAsync(tempDir, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Create attachment
|
||||
attachments ??= [];
|
||||
attachments.Add(new UserMessageDataAttachmentsItem
|
||||
{
|
||||
@@ -460,19 +437,16 @@ public sealed class GitHubCopilotAgent : AIAgent, IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
return attachments;
|
||||
return (attachments, tempDir);
|
||||
}
|
||||
|
||||
private static void CleanupTempFiles(List<string> tempFiles)
|
||||
private static void CleanupTempDir(string? tempDir)
|
||||
{
|
||||
foreach (string tempFile in tempFiles)
|
||||
if (tempDir is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(tempFile))
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
Directory.Delete(tempDir, recursive: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -304,7 +304,7 @@ internal sealed class WorkflowRunner
|
||||
ChatMessage? responseMessage =
|
||||
requestItem switch
|
||||
{
|
||||
FunctionCallContent functionCall => await InvokeFunctionAsync(functionCall).ConfigureAwait(false),
|
||||
FunctionCallContent functionCall when !functionCall.InformationalOnly => await InvokeFunctionAsync(functionCall).ConfigureAwait(false),
|
||||
FunctionApprovalRequestContent functionApprovalRequest => ApproveFunction(functionApprovalRequest),
|
||||
McpServerToolApprovalRequestContent mcpApprovalRequest => ApproveMCP(mcpApprovalRequest),
|
||||
_ => HandleUnknown(requestItem),
|
||||
|
||||
+9
-2
@@ -524,8 +524,15 @@ public sealed class FunctionInvocationDelegatingAgentTests
|
||||
{
|
||||
// Arrange
|
||||
var testFunction = AIFunctionFactory.Create(() => "Function result", "TestFunction", "A test function");
|
||||
var functionCall = new FunctionCallContent("call_123", "TestFunction", new Dictionary<string, object?>());
|
||||
var mockChatClient = CreateMockChatClientWithFunctionCalls(functionCall);
|
||||
var mockChatClient = new Mock<IChatClient>();
|
||||
|
||||
mockChatClient.Setup(c => c.GetResponseAsync(
|
||||
It.IsAny<IEnumerable<ChatMessage>>(),
|
||||
It.IsAny<ChatOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(() => new ChatResponse([
|
||||
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("call_123", "TestFunction", new Dictionary<string, object?>())])
|
||||
]));
|
||||
|
||||
var innerAgent = new ChatClientAgent(mockChatClient.Object);
|
||||
var messages = new List<ChatMessage> { new(ChatRole.User, "Test message") };
|
||||
|
||||
Reference in New Issue
Block a user