mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
84fe6c46ab
* Add AsIChatClientWithStoredOutputDisabled for ProjectResponsesClient Add extension method on ProjectResponsesClient in Microsoft.Agents.AI.AzureAI package (Azure.AI.Extensions.OpenAI namespace) mirroring the existing extension on ResponsesClient in the OpenAI package. This enables Azure AI consumers to disable server-side response storage without depending on the OpenAI package. - New ProjectResponsesClientExtensions class with AsIChatClientWithStoredOutputDisabled - Optional deploymentName parameter (model is no longer required) - Updated OpenAI counterpart doc to remove 'Required' wording for model param - Added unit tests covering null guard, inner client accessibility, StoredOutputEnabled=false, and reasoning encrypted content inclusion/exclusion Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Preserve existing RawRepresentationFactory when disabling stored output Address PR review feedback: wrap/chain the existing factory instead of replacing it, so upstream configuration (e.g., deploymentName/model defaults from AsIChatClient) is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
170 lines
7.0 KiB
C#
170 lines
7.0 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Reflection;
|
|
using Azure.AI.Extensions.OpenAI;
|
|
using Microsoft.Extensions.AI;
|
|
using OpenAI.Responses;
|
|
|
|
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
|
|
|
/// <summary>
|
|
/// Unit tests for the <see cref="ProjectResponsesClientExtensions"/> class.
|
|
/// </summary>
|
|
public sealed class ProjectResponsesClientExtensionsTests
|
|
{
|
|
private static ProjectResponsesClient CreateTestClient()
|
|
{
|
|
return new ProjectResponsesClient(new FakeAuthenticationTokenProvider());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled throws ArgumentNullException when client is null.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_WithNullClient_ThrowsArgumentNullException()
|
|
{
|
|
// Act & Assert
|
|
var exception = Assert.Throws<ArgumentNullException>(() =>
|
|
((ProjectResponsesClient)null!).AsIChatClientWithStoredOutputDisabled());
|
|
|
|
Assert.Equal("responseClient", exception.ParamName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled wraps the original ProjectResponsesClient,
|
|
/// which remains accessible via the service chain.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_InnerResponsesClientIsAccessible()
|
|
{
|
|
// Arrange
|
|
var responseClient = CreateTestClient();
|
|
|
|
// Act
|
|
var chatClient = responseClient.AsIChatClientWithStoredOutputDisabled();
|
|
|
|
// Assert - the inner ProjectResponsesClient should be accessible via GetService
|
|
var innerClient = chatClient.GetService<ResponsesClient>();
|
|
Assert.NotNull(innerClient);
|
|
Assert.Same(responseClient, innerClient);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled with includeReasoningEncryptedContent false
|
|
/// wraps the original ProjectResponsesClient, which remains accessible via the service chain.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_WithIncludeReasoningFalse_InnerResponsesClientIsAccessible()
|
|
{
|
|
// Arrange
|
|
var responseClient = CreateTestClient();
|
|
|
|
// Act
|
|
var chatClient = responseClient.AsIChatClientWithStoredOutputDisabled(includeReasoningEncryptedContent: false);
|
|
|
|
// Assert - the inner ProjectResponsesClient should be accessible via GetService
|
|
var innerClient = chatClient.GetService<ResponsesClient>();
|
|
Assert.NotNull(innerClient);
|
|
Assert.Same(responseClient, innerClient);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled with default parameter (includeReasoningEncryptedContent = true)
|
|
/// configures StoredOutputEnabled to false and includes ReasoningEncryptedContent in IncludedProperties.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_Default_ConfiguresStoredOutputDisabledWithReasoningEncryptedContent()
|
|
{
|
|
// Arrange
|
|
var responseClient = CreateTestClient();
|
|
|
|
// Act
|
|
var chatClient = responseClient.AsIChatClientWithStoredOutputDisabled();
|
|
|
|
// Assert
|
|
var createResponseOptions = GetCreateResponseOptionsFromPipeline(chatClient);
|
|
Assert.NotNull(createResponseOptions);
|
|
Assert.False(createResponseOptions.StoredOutputEnabled);
|
|
Assert.Contains(IncludedResponseProperty.ReasoningEncryptedContent, createResponseOptions.IncludedProperties);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled with includeReasoningEncryptedContent explicitly set to true
|
|
/// configures StoredOutputEnabled to false and includes ReasoningEncryptedContent in IncludedProperties.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_WithIncludeReasoningTrue_ConfiguresStoredOutputDisabledWithReasoningEncryptedContent()
|
|
{
|
|
// Arrange
|
|
var responseClient = CreateTestClient();
|
|
|
|
// Act
|
|
var chatClient = responseClient.AsIChatClientWithStoredOutputDisabled(includeReasoningEncryptedContent: true);
|
|
|
|
// Assert
|
|
var createResponseOptions = GetCreateResponseOptionsFromPipeline(chatClient);
|
|
Assert.NotNull(createResponseOptions);
|
|
Assert.False(createResponseOptions.StoredOutputEnabled);
|
|
Assert.Contains(IncludedResponseProperty.ReasoningEncryptedContent, createResponseOptions.IncludedProperties);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled with includeReasoningEncryptedContent set to false
|
|
/// configures StoredOutputEnabled to false and does not include ReasoningEncryptedContent in IncludedProperties.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_WithIncludeReasoningFalse_ConfiguresStoredOutputDisabledWithoutReasoningEncryptedContent()
|
|
{
|
|
// Arrange
|
|
var responseClient = CreateTestClient();
|
|
|
|
// Act
|
|
var chatClient = responseClient.AsIChatClientWithStoredOutputDisabled(includeReasoningEncryptedContent: false);
|
|
|
|
// Assert
|
|
var createResponseOptions = GetCreateResponseOptionsFromPipeline(chatClient);
|
|
Assert.NotNull(createResponseOptions);
|
|
Assert.False(createResponseOptions.StoredOutputEnabled);
|
|
Assert.DoesNotContain(IncludedResponseProperty.ReasoningEncryptedContent, createResponseOptions.IncludedProperties);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify that AsIChatClientWithStoredOutputDisabled works with an optional deployment name.
|
|
/// </summary>
|
|
[Fact]
|
|
public void AsIChatClientWithStoredOutputDisabled_WithDeploymentName_ConfiguresStoredOutputDisabled()
|
|
{
|
|
// Arrange
|
|
var responseClient = CreateTestClient();
|
|
|
|
// Act
|
|
var chatClient = responseClient.AsIChatClientWithStoredOutputDisabled(deploymentName: "my-deployment");
|
|
|
|
// Assert
|
|
var createResponseOptions = GetCreateResponseOptionsFromPipeline(chatClient);
|
|
Assert.NotNull(createResponseOptions);
|
|
Assert.False(createResponseOptions.StoredOutputEnabled);
|
|
Assert.Contains(IncludedResponseProperty.ReasoningEncryptedContent, createResponseOptions.IncludedProperties);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extracts the <see cref="CreateResponseOptions"/> produced by the ConfigureOptions pipeline
|
|
/// by using reflection to access the configure action and invoking it on a test <see cref="ChatOptions"/>.
|
|
/// </summary>
|
|
private static CreateResponseOptions? GetCreateResponseOptionsFromPipeline(IChatClient chatClient)
|
|
{
|
|
var configureField = chatClient.GetType().GetField("_configureOptions", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
Assert.NotNull(configureField);
|
|
|
|
var configureAction = configureField.GetValue(chatClient) as Action<ChatOptions>;
|
|
Assert.NotNull(configureAction);
|
|
|
|
var options = new ChatOptions();
|
|
configureAction(options);
|
|
|
|
Assert.NotNull(options.RawRepresentationFactory);
|
|
return options.RawRepresentationFactory(chatClient) as CreateResponseOptions;
|
|
}
|
|
}
|