// Copyright (c) Microsoft. All rights reserved. using System.Threading.Tasks; using AgentConformance.IntegrationTests; using AgentConformance.IntegrationTests.Support; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; namespace Foundry.IntegrationTests; public class FoundryVersionedAgentStructuredOutputRunTests() : StructuredOutputRunTests>(() => new FoundryVersionedAgentStructuredOutputFixture()) { private const string NotSupported = "Versioned Foundry agents do not support specifying structured output type at invocation time."; private const string ResponseFormatNotSupported = "AzureAIProjectChatClient clears ResponseFormat for versioned agents; structured output must be defined in the server-side agent definition."; /// /// Verifies that response format provided at agent initialization is used when invoking RunAsync. /// /// [RetryFact(Constants.RetryCount, Constants.RetryDelay, Skip = ResponseFormatNotSupported)] public async Task RunWithResponseFormatAtAgentInitializationReturnsExpectedResultAsync() { // Arrange var agent = this.Fixture.Agent; var session = await agent.CreateSessionAsync(); await using var cleanup = new SessionCleanup(session, this.Fixture); // Act var response = await agent.RunAsync(new ChatMessage(ChatRole.User, "Provide information about the capital of France."), session); // Assert Assert.NotNull(response); Assert.Single(response.Messages); Assert.Contains("Paris", response.Text); Assert.True(TryDeserialize(response.Text, AgentAbstractionsJsonUtilities.DefaultOptions, out CityInfo cityInfo)); Assert.Equal("Paris", cityInfo.Name); } /// /// Verifies that generic RunAsync works with versioned Foundry agents when structured output is configured at agent initialization. /// /// /// Versioned Foundry agents do not support specifying the structured output type at invocation time yet. /// The type T provided to RunAsync<T> is ignored by AzureAIProjectChatClient and is only used /// for deserializing the agent response by AgentResponse<T>.Result. /// [RetryFact(Constants.RetryCount, Constants.RetryDelay, Skip = ResponseFormatNotSupported)] public async Task RunGenericWithResponseFormatAtAgentInitializationReturnsExpectedResultAsync() { // Arrange var agent = this.Fixture.Agent; var session = await agent.CreateSessionAsync(); await using var cleanup = new SessionCleanup(session, this.Fixture); // Act AgentResponse response = await agent.RunAsync( new ChatMessage(ChatRole.User, "Provide information about the capital of France."), session); // Assert Assert.NotNull(response); Assert.Single(response.Messages); Assert.Contains("Paris", response.Text); Assert.NotNull(response.Result); Assert.Equal("Paris", response.Result.Name); } public override Task RunWithGenericTypeReturnsExpectedResultAsync() { Assert.Skip(NotSupported); return base.RunWithGenericTypeReturnsExpectedResultAsync(); } public override Task RunWithResponseFormatReturnsExpectedResultAsync() { Assert.Skip(NotSupported); return base.RunWithResponseFormatReturnsExpectedResultAsync(); } public override Task RunWithPrimitiveTypeReturnsExpectedResultAsync() { Assert.Skip(NotSupported); return base.RunWithPrimitiveTypeReturnsExpectedResultAsync(); } } /// /// Represents a fixture for testing versioned Foundry agents with structured output of type provided at agent initialization. /// public class FoundryVersionedAgentStructuredOutputFixture : FoundryVersionedAgentFixture { public override async ValueTask InitializeAsync() { var agentOptions = new ChatClientAgentOptions { ChatOptions = new ChatOptions() { ResponseFormat = ChatResponseFormat.ForJsonSchema(AgentAbstractionsJsonUtilities.DefaultOptions) }, }; await this.InitializeAsync(agentOptions); } }