diff --git a/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdateExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseExtensions.cs
similarity index 71%
rename from dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdateExtensions.cs
rename to dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseExtensions.cs
index 848bd5fd24..adad80d890 100644
--- a/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdateExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseExtensions.cs
@@ -14,10 +14,91 @@ using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
///
-/// Provides extension methods for working with instances.
+/// Provides extension methods for working with and instances.
///
-public static class AgentRunResponseUpdateExtensions
+public static class AgentRunResponseExtensions
{
+ ///
+ /// Creates a from an .
+ ///
+ /// The .
+ /// A built from .
+ ///
+ /// If the 's is a
+ /// instance, that instance is returned directly. Otherwise, a new
+ /// is created and populated with the data from the .
+ /// The instance is a shallow copy; any reference-type members (e.g. )
+ /// will be shared between the two instances.
+ ///
+ public static ChatResponse AsChatResponse(this AgentRunResponse response)
+ {
+ Throw.IfNull(response);
+
+ return
+ response.RawRepresentation as ChatResponse ??
+ new()
+ {
+ AdditionalProperties = response.AdditionalProperties,
+ CreatedAt = response.CreatedAt,
+ Messages = response.Messages,
+ RawRepresentation = response,
+ ResponseId = response.ResponseId,
+ Usage = response.Usage,
+ };
+ }
+
+ ///
+ /// Creates a from an .
+ ///
+ /// The .
+ /// A built from .
+ ///
+ /// If the 's is a
+ /// instance, that instance is returned directly. Otherwise, a new
+ /// is created and populated with the data from the .
+ /// The instance is a shallow copy; any reference-type members (e.g. )
+ /// will be shared between the two instances.
+ ///
+ public static ChatResponseUpdate AsChatResponseUpdate(this AgentRunResponseUpdate responseUpdate)
+ {
+ Throw.IfNull(responseUpdate);
+
+ return
+ responseUpdate.RawRepresentation as ChatResponseUpdate ??
+ new()
+ {
+ AdditionalProperties = responseUpdate.AdditionalProperties,
+ AuthorName = responseUpdate.AuthorName,
+ Contents = responseUpdate.Contents,
+ CreatedAt = responseUpdate.CreatedAt,
+ MessageId = responseUpdate.MessageId,
+ RawRepresentation = responseUpdate,
+ ResponseId = responseUpdate.ResponseId,
+ Role = responseUpdate.Role,
+ };
+ }
+
+ ///
+ /// Creates an asynchronous enumerable of instances from an asynchronous
+ /// enumerable of instances.
+ ///
+ /// The sequence .
+ /// A sequence of instances built from .
+ ///
+ /// Each is converted to a using
+ /// .
+ ///
+ public static async IAsyncEnumerable AsChatResponseUpdatesAsync(
+ this IAsyncEnumerable responseUpdates)
+ {
+ Throw.IfNull(responseUpdates);
+
+ await foreach (var responseUpdate in responseUpdates.ConfigureAwait(false))
+ {
+ yield return responseUpdate.AsChatResponseUpdate();
+ }
+ }
+
/// Combines instances into a single .
/// The updates to be combined.
/// The combined .
diff --git a/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdate.cs b/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdate.cs
index 3087c78b92..f9f7b674dd 100644
--- a/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdate.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunResponseUpdate.cs
@@ -22,7 +22,7 @@ namespace Microsoft.Agents.AI;
///
///
/// The relationship between and is
-/// codified in the and
+/// codified in the and
/// , which enable bidirectional conversions
/// between the two. Note, however, that the provided conversions may be lossy, for example if multiple
/// updates all have different objects whereas there's only one slot for
@@ -135,7 +135,7 @@ public class AgentRunResponseUpdate
/// Some providers may consider streaming responses to be a single message, and in that case
/// the value of this property may be the same as the response ID.
///
- /// This value is used when
+ /// This value is used when
/// groups instances into instances.
/// The value must be unique to each call to the underlying provider, and must be shared by
/// all updates that are part of the same logical message within a streaming response.
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/AsyncStreamingUpdateCollectionResult.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/AsyncStreamingUpdateCollectionResult.cs
index 2c273b98ce..127f45ef6e 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/AsyncStreamingUpdateCollectionResult.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/AsyncStreamingUpdateCollectionResult.cs
@@ -3,7 +3,7 @@
using System.ClientModel;
using OpenAI.Chat;
-namespace Microsoft.Agents.AI.OpenAI.ChatClient;
+namespace Microsoft.Agents.AI.OpenAI;
internal sealed class AsyncStreamingUpdateCollectionResult : AsyncCollectionResult
{
@@ -19,13 +19,10 @@ internal sealed class AsyncStreamingUpdateCollectionResult : AsyncCollectionResu
public override IAsyncEnumerable GetRawPagesAsync() =>
AsyncEnumerable.Repeat(ClientResult.FromValue(this._updates, new StreamingUpdatePipelineResponse(this._updates)), 1);
- protected override async IAsyncEnumerable GetValuesFromPageAsync(ClientResult page)
+ protected override IAsyncEnumerable GetValuesFromPageAsync(ClientResult page)
{
var updates = ((ClientResult>)page).Value;
- await foreach (var update in updates.ConfigureAwait(false))
- {
- yield return update.AsStreamingChatCompletionUpdate();
- }
+ return updates.AsChatResponseUpdatesAsync().AsOpenAIStreamingChatCompletionUpdatesAsync();
}
}
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/StreamingUpdatePipelineResponse.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/StreamingUpdatePipelineResponse.cs
index 1768d100ad..e999ad04e7 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/StreamingUpdatePipelineResponse.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/StreamingUpdatePipelineResponse.cs
@@ -2,7 +2,7 @@
using System.ClientModel.Primitives;
-namespace Microsoft.Agents.AI.OpenAI.ChatClient;
+namespace Microsoft.Agents.AI.OpenAI;
internal sealed class StreamingUpdatePipelineResponse : PipelineResponse
{
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AIAgentWithOpenAIExtensions.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AIAgentWithOpenAIExtensions.cs
index c51698c973..32bb50080d 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AIAgentWithOpenAIExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AIAgentWithOpenAIExtensions.cs
@@ -2,7 +2,7 @@
using System.ClientModel;
using Microsoft.Agents.AI;
-using Microsoft.Agents.AI.OpenAI.ChatClient;
+using Microsoft.Agents.AI.OpenAI;
using Microsoft.Shared.Diagnostics;
using OpenAI.Chat;
@@ -34,7 +34,7 @@ public static class AIAgentWithOpenAIExtensions
/// Thrown when any message in has a type that is not supported by the message conversion method.
///
/// This method converts the OpenAI chat messages to the Microsoft Extensions AI format using the appropriate conversion method,
- /// runs the agent with the converted message collection, and then extracts the native OpenAI from the response using .
+ /// runs the agent with the converted message collection, and then extracts the native OpenAI from the response using .
///
public static async Task RunAsync(this AIAgent agent, IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
@@ -43,7 +43,7 @@ public static class AIAgentWithOpenAIExtensions
var response = await agent.RunAsync([.. messages.AsChatMessages()], thread, options, cancellationToken).ConfigureAwait(false);
- return response.AsChatCompletion();
+ return response.AsOpenAIChatCompletion();
}
///
@@ -60,7 +60,7 @@ public static class AIAgentWithOpenAIExtensions
/// Thrown when the type is not supported by the message conversion method.
///
/// This method converts the OpenAI chat messages to the Microsoft Extensions AI format using the appropriate conversion method,
- /// runs the agent, and then extracts the native OpenAI from the response using .
+ /// runs the agent, and then extracts the native OpenAI from the response using .
///
public static AsyncCollectionResult RunStreamingAsync(this AIAgent agent, IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseExtensions.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseExtensions.cs
index 4c727788e0..1660192fad 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseExtensions.cs
@@ -1,52 +1,45 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
using Microsoft.Shared.Diagnostics;
using OpenAI.Chat;
+using OpenAI.Responses;
namespace OpenAI;
///
-/// Provides extension methods for to extract native OpenAI response objects
-/// from the Microsoft Agent Framework responses.
+/// Provides extension methods for and instances to
+/// create or extract native OpenAI response objects from the Microsoft Agent Framework responses.
///
-///
-/// These extensions enable developers to access the underlying OpenAI SDK objects when working with
-/// AI agents that are backed by OpenAI services. The methods extract strongly-typed OpenAI responses
-/// from the property, providing a bridge between
-/// the Microsoft Extensions AI framework and the native OpenAI SDK types.
-///
public static class AgentRunResponseExtensions
{
///
- /// Extracts a native OpenAI object from an .
+ /// Creates or extracts a native OpenAI object from an .
///
- /// The agent response containing the raw OpenAI representation.
- /// The native OpenAI object.
- /// Thrown when is .
- ///
- /// Thrown when the is not a object.
- /// This typically occurs when the agent response was not generated by an OpenAI chat completion service
- /// or when the underlying representation has been modified or corrupted.
- ///
- ///
- ///
- /// This method provides access to the native OpenAI object that was used
- /// to generate the agent response. This is useful when you need to access OpenAI-specific properties
- /// or metadata that are not exposed through the Microsoft Extensions AI abstractions.
- ///
- ///
- public static ChatCompletion AsChatCompletion(this AgentRunResponse agentResponse)
+ /// The agent response.
+ /// The OpenAI object.
+ /// is .
+ public static ChatCompletion AsOpenAIChatCompletion(this AgentRunResponse response)
{
- Throw.IfNull(agentResponse);
+ Throw.IfNull(response);
- if (agentResponse.RawRepresentation is ChatResponse chatResponse)
- {
- return chatResponse.RawRepresentation is ChatCompletion chatCompletion
- ? chatCompletion
- : throw new ArgumentException("ChatResponse.RawRepresentation must be a ChatCompletion");
- }
- throw new ArgumentException("AgentRunResponse.RawRepresentation must be a ChatResponse");
+ return
+ response.RawRepresentation as ChatCompletion ??
+ response.AsChatResponse().AsOpenAIChatCompletion();
+ }
+
+ ///
+ /// Creates or extracts a native OpenAI object from an .
+ ///
+ /// The agent response.
+ /// The OpenAI object.
+ /// is .
+ public static OpenAIResponse AsOpenAIResponse(this AgentRunResponse response)
+ {
+ Throw.IfNull(response);
+
+ return
+ response.RawRepresentation as OpenAIResponse ??
+ response.AsChatResponse().AsOpenAIResponse();
}
}
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseUpdateExtensions.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseUpdateExtensions.cs
deleted file mode 100644
index 83d800aaba..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/AgentRunResponseUpdateExtensions.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.AI;
-using Microsoft.Shared.Diagnostics;
-using OpenAI.Chat;
-
-namespace Microsoft.Agents.AI;
-
-///
-/// Provides extension methods for to extract native OpenAI response objects
-/// from the Microsoft Agent Framework responses.
-///
-///
-/// These extensions enable developers to access the underlying OpenAI SDK objects when working with
-/// AI agents that are backed by OpenAI services. The methods extract strongly-typed OpenAI responses
-/// from the property, providing a bridge between
-/// the Microsoft Extensions AI framework and the native OpenAI SDK types.
-///
-public static class AgentRunResponseUpdateExtensions
-{
- ///
- /// Extracts a native OpenAI object from an .
- ///
- /// The agent response containing the raw OpenAI representation.
- /// The native OpenAI object.
- /// Thrown when is .
- ///
- /// Thrown when the is not a object,
- /// or when the nested is not a object.
- /// This typically occurs when the agent response was not generated by an OpenAI streaming chat completion service
- /// or when the underlying representation has been modified or corrupted.
- ///
- ///
- ///
- /// This method provides access to the native OpenAI object that was used
- /// to generate the agent response. This is useful when you need to access OpenAI-specific properties
- /// or metadata that are not exposed through the Microsoft Extensions AI abstractions.
- ///
- ///
- public static StreamingChatCompletionUpdate AsStreamingChatCompletionUpdate(this AgentRunResponseUpdate agentResponseUpdate)
- {
- Throw.IfNull(agentResponseUpdate);
-
- if (agentResponseUpdate.RawRepresentation is ChatResponseUpdate chatResponseUpdate)
- {
- return chatResponseUpdate.RawRepresentation is StreamingChatCompletionUpdate streamingChatCompletionUpdate
- ? streamingChatCompletionUpdate
- : throw new ArgumentException("ChatResponseUpdate.RawRepresentation must be a StreamingChatCompletionUpdate");
- }
- throw new ArgumentException("AgentRunResponseUpdate.RawRepresentation must be a ChatResponseUpdate");
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIChatClientAgent.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIChatClientAgent.cs
index fbef8d10fa..b529e1151b 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIChatClientAgent.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIChatClientAgent.cs
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft. All rights reserved.
-using System.Text.Json;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Logging;
@@ -11,12 +10,10 @@ using ChatMessage = OpenAI.Chat.ChatMessage;
namespace OpenAI;
///
-/// OpenAI chat completion based implementation of .
+/// Provides an backed by an OpenAI chat completion implementation.
///
-public class OpenAIChatClientAgent : AIAgent
+public class OpenAIChatClientAgent : DelegatingAIAgent
{
- private readonly ChatClientAgent _chatClientAgent;
-
///
/// Initialize an instance of
///
@@ -30,20 +27,14 @@ public class OpenAIChatClientAgent : AIAgent
string? instructions = null,
string? name = null,
string? description = null,
- ILoggerFactory? loggerFactory = null)
+ ILoggerFactory? loggerFactory = null) :
+ this(client, new()
+ {
+ Name = name,
+ Description = description,
+ Instructions = instructions,
+ }, loggerFactory)
{
- Throw.IfNull(client);
-
- var chatClient = client.AsIChatClient();
- this._chatClientAgent = new(
- chatClient,
- new ChatClientAgentOptions()
- {
- Name = name,
- Description = description,
- Instructions = instructions,
- },
- loggerFactory);
}
///
@@ -52,12 +43,10 @@ public class OpenAIChatClientAgent : AIAgent
/// Instance of
/// Options to create the agent.
/// Optional instance of
- public OpenAIChatClientAgent(ChatClient client, ChatClientAgentOptions options, ILoggerFactory? loggerFactory = null)
+ public OpenAIChatClientAgent(
+ ChatClient client, ChatClientAgentOptions options, ILoggerFactory? loggerFactory = null) :
+ base(new ChatClientAgent(Throw.IfNull(client).AsIChatClient(), options, loggerFactory))
{
- Throw.IfNull(client);
-
- var chatClient = client.AsIChatClient();
- this._chatClientAgent = new(chatClient, options, loggerFactory);
}
///
@@ -74,37 +63,35 @@ public class OpenAIChatClientAgent : AIAgent
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
- var response = await this.RunAsync([.. messages.AsChatMessages()], thread, options, cancellationToken).ConfigureAwait(false);
+ var response = await this.RunAsync(messages.AsChatMessages(), thread, options, cancellationToken).ConfigureAwait(false);
- return response.AsChatCompletion();
+ return response.AsOpenAIChatCompletion();
+ }
+
+ ///
+ /// Run the agent streaming with the provided message and arguments.
+ ///
+ /// The messages to pass to the agent.
+ /// The conversation thread to continue with this invocation. If not provided, creates a new thread. The thread will be mutated with the provided messages and agent response.
+ /// Optional parameters for agent invocation.
+ /// The to monitor for cancellation requests. The default is .
+ /// A containing the list of items.
+ public virtual IAsyncEnumerable RunStreamingAsync(
+ IEnumerable messages,
+ AgentThread? thread = null,
+ AgentRunOptions? options = null,
+ CancellationToken cancellationToken = default)
+ {
+ var response = this.RunStreamingAsync(messages.AsChatMessages(), thread, options, cancellationToken);
+
+ return response.AsChatResponseUpdatesAsync().AsOpenAIStreamingChatCompletionUpdatesAsync(cancellationToken);
}
///
- public sealed override AgentThread GetNewThread()
- => this._chatClientAgent.GetNewThread();
+ public sealed override Task RunAsync(IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
+ base.RunAsync(messages, thread, options, cancellationToken);
///
- public sealed override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
- => this._chatClientAgent.DeserializeThread(serializedThread, jsonSerializerOptions);
-
- ///
- public sealed override Task RunAsync(
- IEnumerable messages,
- AgentThread? thread = null,
- AgentRunOptions? options = null,
- CancellationToken cancellationToken = default)
- => this._chatClientAgent.RunAsync(messages, thread, options, cancellationToken);
-
- ///
- public sealed override IAsyncEnumerable RunStreamingAsync(
- IEnumerable messages,
- AgentThread? thread = null,
- AgentRunOptions? options = null,
- CancellationToken cancellationToken = default)
- => this._chatClientAgent.RunStreamingAsync(messages, thread, options, cancellationToken);
-
- ///
- public override object? GetService(Type serviceType, object? serviceKey = null)
- => base.GetService(serviceType, serviceKey)
- ?? this._chatClientAgent.GetService(serviceType, serviceKey);
+ public override IAsyncEnumerable RunStreamingAsync(IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
+ base.RunStreamingAsync(messages, thread, options, cancellationToken);
}
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIResponseClientAgent.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIResponseClientAgent.cs
new file mode 100644
index 0000000000..8c5603fb05
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/OpenAIResponseClientAgent.cs
@@ -0,0 +1,115 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Runtime.CompilerServices;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Logging;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Responses;
+
+namespace OpenAI;
+
+///
+/// Provides an backed by an OpenAI Responses implementation.
+///
+public class OpenAIResponseClientAgent : DelegatingAIAgent
+{
+ ///
+ /// Initialize an instance of .
+ ///
+ /// Instance of
+ /// Optional instructions for the agent.
+ /// Optional name for the agent.
+ /// Optional description for the agent.
+ /// Optional instance of
+ public OpenAIResponseClientAgent(
+ OpenAIResponseClient client,
+ string? instructions = null,
+ string? name = null,
+ string? description = null,
+ ILoggerFactory? loggerFactory = null) :
+ this(client, new()
+ {
+ Name = name,
+ Description = description,
+ Instructions = instructions,
+ }, loggerFactory)
+ {
+ }
+
+ ///
+ /// Initialize an instance of .
+ ///
+ /// Instance of
+ /// Options to create the agent.
+ /// Optional instance of
+ public OpenAIResponseClientAgent(
+ OpenAIResponseClient client, ChatClientAgentOptions options, ILoggerFactory? loggerFactory = null) :
+ base(new ChatClientAgent(Throw.IfNull(client).AsIChatClient(), options, loggerFactory))
+ {
+ }
+
+ ///
+ /// Run the agent with the provided message and arguments.
+ ///
+ /// The messages to pass to the agent.
+ /// The conversation thread to continue with this invocation. If not provided, creates a new thread. The thread will be mutated with the provided messages and agent response.
+ /// Optional parameters for agent invocation.
+ /// The to monitor for cancellation requests. The default is .
+ /// A containing the list of items.
+ public virtual async Task RunAsync(
+ IEnumerable messages,
+ AgentThread? thread = null,
+ AgentRunOptions? options = null,
+ CancellationToken cancellationToken = default)
+ {
+ var response = await this.RunAsync(messages.AsChatMessages(), thread, options, cancellationToken).ConfigureAwait(false);
+
+ return response.AsOpenAIResponse();
+ }
+
+ ///
+ /// Run the agent streaming with the provided message and arguments.
+ ///
+ /// The messages to pass to the agent.
+ /// The conversation thread to continue with this invocation. If not provided, creates a new thread. The thread will be mutated with the provided messages and agent response.
+ /// Optional parameters for agent invocation.
+ /// The to monitor for cancellation requests. The default is .
+ /// A containing the list of items.
+ public virtual async IAsyncEnumerable RunStreamingAsync(
+ IEnumerable messages,
+ AgentThread? thread = null,
+ AgentRunOptions? options = null,
+ [EnumeratorCancellation] CancellationToken cancellationToken = default)
+ {
+ var response = this.RunStreamingAsync(messages.AsChatMessages(), thread, options, cancellationToken);
+
+ await foreach (var update in response.ConfigureAwait(false))
+ {
+ switch (update.RawRepresentation)
+ {
+ case StreamingResponseUpdate rawUpdate:
+ yield return rawUpdate;
+ break;
+
+ case ChatResponseUpdate { RawRepresentation: StreamingResponseUpdate rawUpdate }:
+ yield return rawUpdate;
+ break;
+
+ default:
+ // TODO: The OpenAI library does not currently expose model factory methods for creating
+ // StreamingResponseUpdates. We are thus unable to manufacture such instances when there isn't
+ // already one in the update and instead skip them.
+ break;
+ }
+ }
+ }
+
+ ///
+ public sealed override Task RunAsync(IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
+ base.RunAsync(messages, thread, options, cancellationToken);
+
+ ///
+ public sealed override IAsyncEnumerable RunStreamingAsync(IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
+ base.RunStreamingAsync(messages, thread, options, cancellationToken);
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows/MessageMerger.cs b/dotnet/src/Microsoft.Agents.AI.Workflows/MessageMerger.cs
index 8489d43f86..4560074dd2 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows/MessageMerger.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows/MessageMerger.cs
@@ -72,19 +72,7 @@ internal sealed class MessageMerger
throw new InvalidOperationException($"No updates found for message ID '{messageId}' in response '{this.ResponseId}'.");
}
- return updates.Select(oldUpdate =>
- oldUpdate.RawRepresentation as ChatResponseUpdate ??
- new()
- {
- AdditionalProperties = oldUpdate.AdditionalProperties,
- AuthorName = oldUpdate.AuthorName,
- Contents = oldUpdate.Contents,
- CreatedAt = oldUpdate.CreatedAt,
- MessageId = oldUpdate.MessageId,
- RawRepresentation = oldUpdate.RawRepresentation,
- Role = oldUpdate.Role,
- ResponseId = oldUpdate.ResponseId,
- }).ToChatResponse().Messages;
+ return updates.Select(oldUpdate => oldUpdate.AsChatResponseUpdate()).ToChatResponse().Messages;
}
}
}
diff --git a/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs b/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs
index ba8e35a46c..fafc224e77 100644
--- a/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs
+++ b/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs
@@ -182,15 +182,7 @@ public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable
var response = await parentAgent.InnerAgent.RunAsync(messages, fo?.Thread, fo?.Options, cancellationToken).ConfigureAwait(false);
// Wrap the response in a ChatResponse so we can pass it back through OpenTelemetryChatClient.
- return new ChatResponse
- {
- AdditionalProperties = response.AdditionalProperties,
- CreatedAt = response.CreatedAt,
- Messages = response.Messages,
- RawRepresentation = response,
- ResponseId = response.ResponseId,
- Usage = response.Usage,
- };
+ return response.AsChatResponse();
}
public async IAsyncEnumerable GetStreamingResponseAsync(
@@ -205,17 +197,7 @@ public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable
await foreach (var update in parentAgent.InnerAgent.RunStreamingAsync(messages, fo?.Thread, fo?.Options, cancellationToken).ConfigureAwait(false))
{
// Wrap the response updates in ChatResponseUpdates so we can pass them back through OpenTelemetryChatClient.
- yield return new ChatResponseUpdate
- {
- AdditionalProperties = update.AdditionalProperties,
- AuthorName = update.AuthorName,
- Contents = update.Contents,
- CreatedAt = update.CreatedAt,
- MessageId = update.MessageId,
- RawRepresentation = update,
- ResponseId = update.ResponseId,
- Role = update.Role,
- };
+ yield return update.AsChatResponseUpdate();
}
}