mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: [BREAKING] Change namespaces of the Microsoft.Agents.AI.OpenAI classes (#2627)
* change namespaces for agents and extension methods of the Microsoft.Agents.AI.OpenAI package * remove unnecessary namespace * remove unused namespaces * fix compilation issues and rrolled back removed run methods * sort usings * add extension methods for AIAgent to work with OpenAI Responses primitives * Move OpenAIChatClientAgent and OpenAIResponseClientAgent to samples * sort usings * sort usings
This commit is contained in:
+2
-2
@@ -5,11 +5,11 @@ using OpenAI.Chat;
|
||||
|
||||
namespace Microsoft.Agents.AI.OpenAI;
|
||||
|
||||
internal sealed class AsyncStreamingUpdateCollectionResult : AsyncCollectionResult<StreamingChatCompletionUpdate>
|
||||
internal sealed class AsyncStreamingChatCompletionUpdateCollectionResult : AsyncCollectionResult<StreamingChatCompletionUpdate>
|
||||
{
|
||||
private readonly IAsyncEnumerable<AgentRunResponseUpdate> _updates;
|
||||
|
||||
internal AsyncStreamingUpdateCollectionResult(IAsyncEnumerable<AgentRunResponseUpdate> updates)
|
||||
internal AsyncStreamingChatCompletionUpdateCollectionResult(IAsyncEnumerable<AgentRunResponseUpdate> updates)
|
||||
{
|
||||
this._updates = updates;
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ClientModel;
|
||||
using OpenAI.Responses;
|
||||
|
||||
namespace Microsoft.Agents.AI.OpenAI;
|
||||
|
||||
internal sealed class AsyncStreamingResponseUpdateCollectionResult : AsyncCollectionResult<StreamingResponseUpdate>
|
||||
{
|
||||
private readonly IAsyncEnumerable<AgentRunResponseUpdate> _updates;
|
||||
|
||||
internal AsyncStreamingResponseUpdateCollectionResult(IAsyncEnumerable<AgentRunResponseUpdate> updates)
|
||||
{
|
||||
this._updates = updates;
|
||||
}
|
||||
|
||||
public override ContinuationToken? GetContinuationToken(ClientResult page) => null;
|
||||
|
||||
public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
|
||||
{
|
||||
yield return ClientResult.FromValue(this._updates, new StreamingUpdatePipelineResponse(this._updates));
|
||||
}
|
||||
|
||||
protected async override IAsyncEnumerable<StreamingResponseUpdate> GetValuesFromPageAsync(ClientResult page)
|
||||
{
|
||||
var updates = ((ClientResult<IAsyncEnumerable<AgentRunResponseUpdate>>)page).Value;
|
||||
|
||||
await foreach (var update in updates.ConfigureAwait(false))
|
||||
{
|
||||
switch (update.RawRepresentation)
|
||||
{
|
||||
case StreamingResponseUpdate rawUpdate:
|
||||
yield return rawUpdate;
|
||||
break;
|
||||
|
||||
case Extensions.AI.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ClientModel;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.OpenAI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
using OpenAI.Chat;
|
||||
using OpenAI.Responses;
|
||||
|
||||
namespace OpenAI;
|
||||
namespace Microsoft.Agents.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="AIAgent"/> to simplify interaction with OpenAI chat messages
|
||||
@@ -69,6 +69,60 @@ public static class AIAgentWithOpenAIExtensions
|
||||
|
||||
IAsyncEnumerable<AgentRunResponseUpdate> response = agent.RunStreamingAsync([.. messages.AsChatMessages()], thread, options, cancellationToken);
|
||||
|
||||
return new AsyncStreamingUpdateCollectionResult(response);
|
||||
return new AsyncStreamingChatCompletionUpdateCollectionResult(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the AI agent with a collection of OpenAI response items and returns the response as a native OpenAI <see cref="OpenAIResponse"/>.
|
||||
/// </summary>
|
||||
/// <param name="agent">The AI agent to run.</param>
|
||||
/// <param name="messages">The collection of OpenAI response items to send to the agent.</param>
|
||||
/// <param name="thread">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.</param>
|
||||
/// <param name="options">Optional parameters for agent invocation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="Task{OpenAIResponse}"/> representing the asynchronous operation that returns a native OpenAI <see cref="OpenAIResponse"/> response.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agent"/> or <paramref name="messages"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when the agent's response cannot be converted to an <see cref="OpenAIResponse"/>, typically when the underlying representation is not an OpenAI response.</exception>
|
||||
/// <exception cref="NotSupportedException">Thrown when any message in <paramref name="messages"/> has a type that is not supported by the message conversion method.</exception>
|
||||
/// <remarks>
|
||||
/// This method converts the OpenAI response items 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 <see cref="OpenAIResponse"/> from the response using <see cref="AgentRunResponseExtensions.AsOpenAIResponse"/>.
|
||||
/// </remarks>
|
||||
public static async Task<OpenAIResponse> RunAsync(this AIAgent agent, IEnumerable<ResponseItem> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(agent);
|
||||
Throw.IfNull(messages);
|
||||
|
||||
var response = await agent.RunAsync(messages.AsChatMessages(), thread, options, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return response.AsOpenAIResponse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the AI agent in streaming mode with a collection of OpenAI response items and returns the response as a collection of native OpenAI <see cref="StreamingResponseUpdate"/>.
|
||||
/// </summary>
|
||||
/// <param name="agent">The AI agent to run.</param>
|
||||
/// <param name="messages">The collection of OpenAI response items to send to the agent.</param>
|
||||
/// <param name="thread">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 updates.</param>
|
||||
/// <param name="options">Optional parameters for agent invocation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>An <see cref="AsyncCollectionResult{StreamingResponseUpdate}"/> representing the asynchronous enumerable that yields native OpenAI <see cref="StreamingResponseUpdate"/> instances as they are streamed.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agent"/> or <paramref name="messages"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when the agent's response cannot be converted to <see cref="StreamingResponseUpdate"/> instances, typically when the underlying representation is not an OpenAI response.</exception>
|
||||
/// <exception cref="NotSupportedException">Thrown when any message in <paramref name="messages"/> has a type that is not supported by the message conversion method.</exception>
|
||||
/// <remarks>
|
||||
/// This method converts the OpenAI response items to the Microsoft Extensions AI format using the appropriate conversion method,
|
||||
/// runs the agent in streaming mode, and then yields native OpenAI <see cref="StreamingResponseUpdate"/> instances as they are produced.
|
||||
/// The method attempts to extract <see cref="StreamingResponseUpdate"/> from the underlying response representation. If a raw update is not available,
|
||||
/// it is skipped because the OpenAI library does not currently expose model factory methods for creating such instances.
|
||||
/// </remarks>
|
||||
public static AsyncCollectionResult<StreamingResponseUpdate> RunStreamingAsync(this AIAgent agent, IEnumerable<ResponseItem> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(agent);
|
||||
Throw.IfNull(messages);
|
||||
|
||||
IAsyncEnumerable<AgentRunResponseUpdate> response = agent.RunStreamingAsync([.. messages.AsChatMessages()], thread, options, cancellationToken);
|
||||
|
||||
return new AsyncStreamingResponseUpdateCollectionResult(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Microsoft.Shared.Diagnostics;
|
||||
using OpenAI.Chat;
|
||||
using OpenAI.Responses;
|
||||
|
||||
namespace OpenAI;
|
||||
namespace Microsoft.Agents.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="AgentRunResponse"/> and <see cref="AgentRunResponseUpdate"/> instances to
|
||||
|
||||
@@ -5,9 +5,8 @@ using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
using OpenAI.Assistants;
|
||||
|
||||
namespace OpenAI;
|
||||
namespace OpenAI.Assistants;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for OpenAI <see cref="AssistantClient"/>
|
||||
|
||||
@@ -4,9 +4,8 @@ using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
using OpenAI.Chat;
|
||||
|
||||
namespace OpenAI;
|
||||
namespace OpenAI.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="ChatClient"/>
|
||||
|
||||
@@ -4,9 +4,8 @@ using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
using OpenAI.Responses;
|
||||
|
||||
namespace OpenAI;
|
||||
namespace OpenAI.Responses;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="OpenAIResponseClient"/>
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
using OpenAI.Chat;
|
||||
using ChatMessage = OpenAI.Chat.ChatMessage;
|
||||
|
||||
namespace OpenAI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides an <see cref="AIAgent"/> backed by an OpenAI chat completion implementation.
|
||||
/// </summary>
|
||||
public class OpenAIChatClientAgent : DelegatingAIAgent
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize an instance of <see cref="OpenAIChatClientAgent"/>
|
||||
/// </summary>
|
||||
/// <param name="client">Instance of <see cref="ChatClient"/></param>
|
||||
/// <param name="instructions">Optional instructions for the agent.</param>
|
||||
/// <param name="name">Optional name for the agent.</param>
|
||||
/// <param name="description">Optional description for the agent.</param>
|
||||
/// <param name="loggerFactory">Optional instance of <see cref="ILoggerFactory"/></param>
|
||||
public OpenAIChatClientAgent(
|
||||
ChatClient client,
|
||||
string? instructions = null,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
ILoggerFactory? loggerFactory = null) :
|
||||
this(client, new()
|
||||
{
|
||||
Name = name,
|
||||
Description = description,
|
||||
ChatOptions = new ChatOptions() { Instructions = instructions },
|
||||
}, loggerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize an instance of <see cref="OpenAIChatClientAgent"/>
|
||||
/// </summary>
|
||||
/// <param name="client">Instance of <see cref="ChatClient"/></param>
|
||||
/// <param name="options">Options to create the agent.</param>
|
||||
/// <param name="loggerFactory">Optional instance of <see cref="ILoggerFactory"/></param>
|
||||
public OpenAIChatClientAgent(
|
||||
ChatClient client, ChatClientAgentOptions options, ILoggerFactory? loggerFactory = null) :
|
||||
base(new ChatClientAgent(Throw.IfNull(client).AsIChatClient(), options, loggerFactory))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the agent with the provided message and arguments.
|
||||
/// </summary>
|
||||
/// <param name="messages">The messages to pass to the agent.</param>
|
||||
/// <param name="thread">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.</param>
|
||||
/// <param name="options">Optional parameters for agent invocation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatCompletion"/> containing the list of <see cref="ChatMessage"/> items.</returns>
|
||||
public virtual async Task<ChatCompletion> RunAsync(
|
||||
IEnumerable<ChatMessage> messages,
|
||||
AgentThread? thread = null,
|
||||
AgentRunOptions? options = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await this.RunAsync(messages.AsChatMessages(), thread, options, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return response.AsOpenAIChatCompletion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the agent streaming with the provided message and arguments.
|
||||
/// </summary>
|
||||
/// <param name="messages">The messages to pass to the agent.</param>
|
||||
/// <param name="thread">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.</param>
|
||||
/// <param name="options">Optional parameters for agent invocation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatCompletion"/> containing the list of <see cref="ChatMessage"/> items.</returns>
|
||||
public virtual IAsyncEnumerable<StreamingChatCompletionUpdate> RunStreamingAsync(
|
||||
IEnumerable<ChatMessage> messages,
|
||||
AgentThread? thread = null,
|
||||
AgentRunOptions? options = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = this.RunStreamingAsync(messages.AsChatMessages(), thread, options, cancellationToken);
|
||||
|
||||
return response.AsChatResponseUpdatesAsync().AsOpenAIStreamingChatCompletionUpdatesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed override Task<AgentRunResponse> RunAsync(IEnumerable<Microsoft.Extensions.AI.ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
|
||||
base.RunAsync(messages, thread, options, cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<Microsoft.Extensions.AI.ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
|
||||
base.RunStreamingAsync(messages, thread, options, cancellationToken);
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
// 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;
|
||||
|
||||
/// <summary>
|
||||
/// Provides an <see cref="AIAgent"/> backed by an OpenAI Responses implementation.
|
||||
/// </summary>
|
||||
public class OpenAIResponseClientAgent : DelegatingAIAgent
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize an instance of <see cref="OpenAIResponseClientAgent"/>.
|
||||
/// </summary>
|
||||
/// <param name="client">Instance of <see cref="OpenAIResponseClient"/></param>
|
||||
/// <param name="instructions">Optional instructions for the agent.</param>
|
||||
/// <param name="name">Optional name for the agent.</param>
|
||||
/// <param name="description">Optional description for the agent.</param>
|
||||
/// <param name="loggerFactory">Optional instance of <see cref="ILoggerFactory"/></param>
|
||||
public OpenAIResponseClientAgent(
|
||||
OpenAIResponseClient client,
|
||||
string? instructions = null,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
ILoggerFactory? loggerFactory = null) :
|
||||
this(client, new()
|
||||
{
|
||||
Name = name,
|
||||
Description = description,
|
||||
ChatOptions = new ChatOptions() { Instructions = instructions },
|
||||
}, loggerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize an instance of <see cref="OpenAIResponseClientAgent"/>.
|
||||
/// </summary>
|
||||
/// <param name="client">Instance of <see cref="OpenAIResponseClient"/></param>
|
||||
/// <param name="options">Options to create the agent.</param>
|
||||
/// <param name="loggerFactory">Optional instance of <see cref="ILoggerFactory"/></param>
|
||||
public OpenAIResponseClientAgent(
|
||||
OpenAIResponseClient client, ChatClientAgentOptions options, ILoggerFactory? loggerFactory = null) :
|
||||
base(new ChatClientAgent(Throw.IfNull(client).AsIChatClient(), options, loggerFactory))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the agent with the provided message and arguments.
|
||||
/// </summary>
|
||||
/// <param name="messages">The messages to pass to the agent.</param>
|
||||
/// <param name="thread">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.</param>
|
||||
/// <param name="options">Optional parameters for agent invocation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="OpenAIResponse"/> containing the list of <see cref="ChatMessage"/> items.</returns>
|
||||
public virtual async Task<OpenAIResponse> RunAsync(
|
||||
IEnumerable<ResponseItem> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the agent streaming with the provided message and arguments.
|
||||
/// </summary>
|
||||
/// <param name="messages">The messages to pass to the agent.</param>
|
||||
/// <param name="thread">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.</param>
|
||||
/// <param name="options">Optional parameters for agent invocation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="OpenAIResponse"/> containing the list of <see cref="ChatMessage"/> items.</returns>
|
||||
public virtual async IAsyncEnumerable<StreamingResponseUpdate> RunStreamingAsync(
|
||||
IEnumerable<ResponseItem> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
|
||||
base.RunAsync(messages, thread, options, cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
|
||||
base.RunStreamingAsync(messages, thread, options, cancellationToken);
|
||||
}
|
||||
Reference in New Issue
Block a user