mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Rename Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry and consolidate FoundryMemory (#5042)
* Update Foundry Responses as ChatClientAgent * Migrate obsolete AzureAI integration tests to versioned agent pattern Replace obsolete CreateAIAgentAsync/GetAIAgentAsync calls with Agents.CreateAgentVersionAsync() + AsAIAgent(AgentVersion) in all AzureAI integration tests. - Rename AIProjectClient* test files to FoundryVersionedAgent* - Register AIFunction tools in PromptAgentDefinition.Tools for server-side visibility via AsOpenAIResponseTool() - Skip structured output tests (AzureAIProjectChatClient clears ResponseFormat for versioned agents) - Remove all [Obsolete] attributes and #pragma warning disable CS0618 * Merge FoundryMemory package into AzureAI under Memory/ folder Move all FoundryMemory source, unit tests, and integration tests into the Microsoft.Agents.AI.AzureAI package. Change namespace from Microsoft.Agents.AI.FoundryMemory to Microsoft.Agents.AI.AzureAI. - Add [Experimental] to FoundryMemoryProviderOptions and Scope - Rename internal AIProjectClientExtensions to MemoryStoreExtensions - Update AzureAI .csproj with Compliance.Abstractions, Redaction - Remove FoundryMemory from solution and release filter - Update sample to reference AzureAI instead of FoundryMemory - Delete old Microsoft.Agents.AI.FoundryMemory project and tests * Add EnsureMemoryStoreCreatedAsync and memory existence checks to integration tests - Ensure memory store is created before testing memory operations - Add AZURE_AI_EMBEDDING_DEPLOYMENT_NAME config setting - Assert memories exist in store via SearchMemoriesAsync before cleanup - Verify scope isolation with direct memory store queries * Fix and rename AzureAI unit tests for RAPI vs Versioned clarity - Rename AsAIAgentAsync_* to AsAIAgent_* (drop Async from method group) - Add _Rapi_ prefix to non-versioned (Responses API) tests - Add _Versioned_ prefix to versioned agent tests where needed - Fix RAPI tests: assert GetService<AIProjectClient>() is null - Fix Versioned tests: assert IsType<FoundryAgent> and GetService<AIProjectClient>() returns the client instance - Fix UserAgent header tests: proper HTTP handler routing - Fix ChatClient_UsesDefaultConversationIdAsync test setup - All 153 unit tests pass with 0 failures * Rename Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry Rename the project, namespace, folder, and all references from Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry. Also rename Workflows.Declarative.AzureAI to .Foundry. - Rename src, unit test, integration test, and workflow folders - Update namespaces in all source and test .cs files - Update ProjectReferences in ~47 sample and test .csproj files - Update solution files (.slnx, .slnf) - Update sample using statements - Update READMEs, SKILL.md, ADRs in docs/ - Disable package validation baseline for renamed packages - Fix UTF-8 BOM encoding on all affected .cs files - AzureAI.Persistent left completely unchanged * Fix format: remove ImplicitUsings, add explicit usings, fix BOM encoding - Remove ImplicitUsings=enable from Foundry csproj to resolve IDE0005 on shared ReplacingRedactor.cs - Add explicit System usings to all source files that relied on them - Sort usings alphabetically per editorconfig rules - Fix UTF-8 BOM on 12 sample Program.cs files - Rename Azure AI Foundry Agents to Microsoft Foundry Agents in docs
This commit is contained in:
-18
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete AIProjectClientFixture
|
||||
[Obsolete("Use FoundryVersionedAgentRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientChatClientAgentRunStreamingTests() : ChatClientAgentRunStreamingTests<AIProjectClientFixture>(() => new())
|
||||
{
|
||||
public override Task RunWithInstructionsAndNoMessageReturnsExpectedResultAsync()
|
||||
{
|
||||
Assert.Skip("No messages is not supported");
|
||||
return base.RunWithInstructionsAndNoMessageReturnsExpectedResultAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete AIProjectClientFixture
|
||||
[Obsolete("Use FoundryVersionedAgentRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientChatClientAgentRunTests() : ChatClientAgentRunTests<AIProjectClientFixture>(() => new())
|
||||
{
|
||||
public override Task RunWithInstructionsAndNoMessageReturnsExpectedResultAsync()
|
||||
{
|
||||
Assert.Skip("No messages is not supported");
|
||||
return base.RunWithInstructionsAndNoMessageReturnsExpectedResultAsync();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
|
||||
<ProjectReference Include="..\AgentConformance.IntegrationTests\AgentConformance.IntegrationTests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class FoundryVersionedAgentChatClientRunStreamingTests() : ChatClientAgentRunStreamingTests<FoundryVersionedAgentFixture>(() => new())
|
||||
{
|
||||
public override Task RunWithInstructionsAndNoMessageReturnsExpectedResultAsync()
|
||||
{
|
||||
Assert.Skip("No messages is not supported");
|
||||
return base.RunWithInstructionsAndNoMessageReturnsExpectedResultAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class FoundryVersionedAgentChatClientRunTests() : ChatClientAgentRunTests<FoundryVersionedAgentFixture>(() => new())
|
||||
{
|
||||
public override Task RunWithInstructionsAndNoMessageReturnsExpectedResultAsync()
|
||||
{
|
||||
Assert.Skip("No messages is not supported");
|
||||
return base.RunWithInstructionsAndNoMessageReturnsExpectedResultAsync();
|
||||
}
|
||||
}
|
||||
+62
-76
@@ -1,7 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete extension methods
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
@@ -9,45 +7,43 @@ using AgentConformance.IntegrationTests.Support;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Agents;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.AzureAI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI.Files;
|
||||
using OpenAI.Responses;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
[Obsolete("Use FoundryVersionedAgentCreateTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientCreateTests
|
||||
/// <summary>
|
||||
/// Integration tests for versioned <see cref="FoundryAgent"/> creation via
|
||||
/// <c>AIProjectClient.Agents.CreateAgentVersionAsync</c> and <c>AIProjectClient.AsAIAgent(AgentVersion)</c>.
|
||||
/// </summary>
|
||||
public class FoundryVersionedAgentCreateTests
|
||||
{
|
||||
private readonly AIProjectClient _client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
[Theory]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
[InlineData("CreateWithFoundryOptionsAsync")]
|
||||
public async Task CreateAgent_CreatesAgentWithCorrectMetadataAsync(string createMechanism)
|
||||
[Fact]
|
||||
public async Task CreateAgent_CreatesAgentWithCorrectMetadataAsync()
|
||||
{
|
||||
// Arrange.
|
||||
string AgentName = AIProjectClientFixture.GenerateUniqueAgentName("IntegrationTestAgent");
|
||||
string AgentName = FoundryVersionedAgentFixture.GenerateUniqueAgentName("IntegrationTestAgent");
|
||||
const string AgentDescription = "An agent created during integration tests";
|
||||
const string AgentInstructions = "You are an integration test agent";
|
||||
|
||||
// Act.
|
||||
var agent = createMechanism switch
|
||||
{
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName),
|
||||
options: new ChatClientAgentOptions()
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Name = AgentName,
|
||||
Description = AgentDescription,
|
||||
ChatOptions = new() { Instructions = AgentInstructions }
|
||||
}),
|
||||
"CreateWithFoundryOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
name: AgentName,
|
||||
creationOptions: new AgentVersionCreationOptions(new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName)) { Instructions = AgentInstructions }) { Description = AgentDescription }),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
};
|
||||
Instructions = AgentInstructions
|
||||
})
|
||||
{
|
||||
Description = AgentDescription
|
||||
});
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -72,12 +68,11 @@ public class AIProjectClientCreateTests
|
||||
}
|
||||
|
||||
[Theory(Skip = "For manual testing only")]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
[InlineData("CreateWithFoundryOptionsAsync")]
|
||||
public async Task CreateAgent_CreatesAgentWithVectorStoresAsync(string createMechanism)
|
||||
[InlineData("FileSearchTool")]
|
||||
public async Task CreateAgent_CreatesAgentWithVectorStoresAsync(string _)
|
||||
{
|
||||
// Arrange.
|
||||
string AgentName = AIProjectClientFixture.GenerateUniqueAgentName("VectorStoreAgent");
|
||||
string AgentName = FoundryVersionedAgentFixture.GenerateUniqueAgentName("VectorStoreAgent");
|
||||
const string AgentInstructions = """
|
||||
You are a helpful agent that can help fetch data from files you know about.
|
||||
Use the File Search Tool to look up codes for words.
|
||||
@@ -99,22 +94,19 @@ public class AIProjectClientCreateTests
|
||||
);
|
||||
var vectorStoreMetadata = await projectOpenAIClient.GetProjectVectorStoresClient().CreateVectorStoreAsync(options: new() { FileIds = { uploadedAgentFile.Id }, Name = "WordCodeLookup_VectorStore" });
|
||||
|
||||
// Act.
|
||||
var agent = createMechanism switch
|
||||
// Act — create agent version with FileSearch tool via native SDK, then wrap with AsAIAgent.
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName),
|
||||
name: AgentName,
|
||||
instructions: AgentInstructions,
|
||||
tools: [new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreMetadata.Value.Id)] }]),
|
||||
"CreateWithFoundryOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName),
|
||||
name: AgentName,
|
||||
instructions: AgentInstructions,
|
||||
tools: [ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStoreMetadata.Value.Id]).AsAITool()]),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStoreMetadata.Value.Id]) }
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
try
|
||||
{
|
||||
// Assert.
|
||||
@@ -132,13 +124,11 @@ public class AIProjectClientCreateTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
[InlineData("CreateWithFoundryOptionsAsync")]
|
||||
public async Task CreateAgent_CreatesAgentWithCodeInterpreterAsync(string createMechanism)
|
||||
[Fact]
|
||||
public async Task CreateAgent_CreatesAgentWithCodeInterpreterAsync()
|
||||
{
|
||||
// Arrange.
|
||||
string AgentName = AIProjectClientFixture.GenerateUniqueAgentName("CodeInterpreterAgent");
|
||||
string AgentName = FoundryVersionedAgentFixture.GenerateUniqueAgentName("CodeInterpreterAgent");
|
||||
const string AgentInstructions = """
|
||||
You are a helpful coding agent. A Python file is provided. Use the Code Interpreter Tool to run the file
|
||||
and report the SECRET_NUMBER value it prints. Respond only with the number.
|
||||
@@ -158,24 +148,19 @@ public class AIProjectClientCreateTests
|
||||
purpose: FileUploadPurpose.Assistants
|
||||
);
|
||||
|
||||
// Act.
|
||||
var agent = createMechanism switch
|
||||
// Act — create agent version with CodeInterpreter tool via native SDK, then wrap with AsAIAgent.
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
// Hosted tool path (tools supplied via ChatClientAgentOptions)
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName),
|
||||
name: AgentName,
|
||||
instructions: AgentInstructions,
|
||||
tools: [new HostedCodeInterpreterTool() { Inputs = [new HostedFileContent(uploadedCodeFile.Id)] }]),
|
||||
// Foundry (definitions + resources provided directly)
|
||||
"CreateWithFoundryOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName),
|
||||
name: AgentName,
|
||||
instructions: AgentInstructions,
|
||||
tools: [ResponseTool.CreateCodeInterpreterTool(new CodeInterpreterToolContainer(CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration([uploadedCodeFile.Id]))).AsAITool()]),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { ResponseTool.CreateCodeInterpreterTool(new CodeInterpreterToolContainer(CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration([uploadedCodeFile.Id]))) }
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
try
|
||||
{
|
||||
// Assert.
|
||||
@@ -202,7 +187,7 @@ public class AIProjectClientCreateTests
|
||||
public async Task AsAIAgent_WithOpenAPITool_NativeSDKCreation_InvokesServerSideToolAsync()
|
||||
{
|
||||
// Arrange — create agent version with OpenAPI tool using native Azure.AI.Projects SDK types.
|
||||
string AgentName = AIProjectClientFixture.GenerateUniqueAgentName("OpenAPITestAgent");
|
||||
string AgentName = FoundryVersionedAgentFixture.GenerateUniqueAgentName("OpenAPITestAgent");
|
||||
const string AgentInstructions = "You are a helpful assistant that can use the countries API to retrieve information about countries by their currency code.";
|
||||
|
||||
const string CountriesOpenApiSpec = """
|
||||
@@ -320,28 +305,29 @@ public class AIProjectClientCreateTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
public async Task CreateAgent_CreatesAgentWithAIFunctionToolsAsync(string createMechanism)
|
||||
[Fact]
|
||||
public async Task CreateAgent_CreatesAgentWithAIFunctionToolsAsync()
|
||||
{
|
||||
// Arrange.
|
||||
string AgentName = AIProjectClientFixture.GenerateUniqueAgentName("WeatherAgent");
|
||||
string AgentName = FoundryVersionedAgentFixture.GenerateUniqueAgentName("WeatherAgent");
|
||||
const string AgentInstructions = "You are a helpful weather assistant. Always call the GetWeather function to answer questions about weather.";
|
||||
|
||||
static string GetWeather(string location) => $"The weather in {location} is sunny with a high of 23C.";
|
||||
var weatherFunction = AIFunctionFactory.Create(GetWeather);
|
||||
|
||||
FoundryAgent agent = createMechanism switch
|
||||
// Create agent version with the function tool registered in the server-side definition,
|
||||
// then wrap with AsAIAgent passing the local AIFunction implementation.
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._client.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
Name = AgentName,
|
||||
ChatOptions = new() { Instructions = AgentInstructions, Tools = [weatherFunction] }
|
||||
}),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
Instructions = AgentInstructions,
|
||||
};
|
||||
definition.Tools.Add(weatherFunction.AsOpenAIResponseTool());
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
FoundryAgent agent = this._client.AsAIAgent(agentVersion, tools: [weatherFunction]);
|
||||
|
||||
try
|
||||
{
|
||||
+67
-11
@@ -1,7 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete extension methods
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -10,16 +8,21 @@ using AgentConformance.IntegrationTests;
|
||||
using AgentConformance.IntegrationTests.Support;
|
||||
using Azure.AI.Extensions.OpenAI;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Agents;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.AzureAI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI.Responses;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
[Obsolete("Use FoundryVersionedAgentFixture instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientFixture : IChatClientAgentFixture
|
||||
/// <summary>
|
||||
/// Integration test fixture that creates versioned Foundry agents via
|
||||
/// <c>AIProjectClient.Agents.CreateAgentVersionAsync</c> and wraps them
|
||||
/// with <c>AIProjectClient.AsAIAgent(AgentVersion)</c>.
|
||||
/// </summary>
|
||||
public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
private FoundryAgent _agent = null!;
|
||||
private AIProjectClient _client = null!;
|
||||
@@ -40,7 +43,6 @@ public class AIProjectClientFixture : IChatClientAgentFixture
|
||||
|
||||
if (chatClientSession.ConversationId?.StartsWith("conv_", StringComparison.OrdinalIgnoreCase) == true)
|
||||
{
|
||||
// Conversation sessions do not persist message history.
|
||||
return await this.GetChatHistoryFromConversationAsync(chatClientSession.ConversationId);
|
||||
}
|
||||
|
||||
@@ -119,14 +121,48 @@ public class AIProjectClientFixture : IChatClientAgentFixture
|
||||
string instructions = "You are a helpful assistant.",
|
||||
IList<AITool>? aiTools = null)
|
||||
{
|
||||
return (await this._client.CreateAIAgentAsync(GenerateUniqueAgentName(name), model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName), instructions: instructions, tools: aiTools)).GetService<ChatClientAgent>()!;
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = instructions
|
||||
};
|
||||
|
||||
// Register AIFunction tool definitions in the server-side agent definition so the model
|
||||
// can invoke them. The local AIFunction implementations are matched by name via AsAIAgent.
|
||||
if (aiTools is not null)
|
||||
{
|
||||
foreach (var tool in aiTools)
|
||||
{
|
||||
if (tool.AsOpenAIResponseTool() is ResponseTool responseTool)
|
||||
{
|
||||
definition.Tools.Add(responseTool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
GenerateUniqueAgentName(name),
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
return this._client.AsAIAgent(agentVersion, tools: aiTools).GetService<ChatClientAgent>()!;
|
||||
}
|
||||
|
||||
public async Task<ChatClientAgent> CreateChatClientAgentAsync(ChatClientAgentOptions options)
|
||||
{
|
||||
options.Name ??= GenerateUniqueAgentName("HelpfulAssistant");
|
||||
|
||||
return (await this._client.CreateAIAgentAsync(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName), options)).GetService<ChatClientAgent>()!;
|
||||
var definition = new PromptAgentDefinition(
|
||||
options.ChatOptions?.ModelId ?? TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = options.ChatOptions?.Instructions
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
options.Name,
|
||||
new AgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion, tools: options.ChatOptions?.Tools);
|
||||
|
||||
return agent.GetService<ChatClientAgent>()!;
|
||||
}
|
||||
|
||||
public static string GenerateUniqueAgentName(string baseName) =>
|
||||
@@ -174,13 +210,33 @@ public class AIProjectClientFixture : IChatClientAgentFixture
|
||||
public virtual async ValueTask InitializeAsync()
|
||||
{
|
||||
this._client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
this._agent = await this._client.CreateAIAgentAsync(GenerateUniqueAgentName("HelpfulAssistant"), model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName), instructions: "You are a helpful assistant.");
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
GenerateUniqueAgentName("HelpfulAssistant"),
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = "You are a helpful assistant."
|
||||
}));
|
||||
|
||||
this._agent = this._client.AsAIAgent(agentVersion);
|
||||
}
|
||||
|
||||
public async Task InitializeAsync(ChatClientAgentOptions options)
|
||||
{
|
||||
this._client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
options.Name ??= GenerateUniqueAgentName("HelpfulAssistant");
|
||||
this._agent = await this._client.CreateAIAgentAsync(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName), options);
|
||||
|
||||
var definition = new PromptAgentDefinition(
|
||||
options.ChatOptions?.ModelId ?? TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = options.ChatOptions?.Instructions
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
options.Name,
|
||||
new AgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
|
||||
this._agent = this._client.AsAIAgent(agentVersion, tools: options.ChatOptions?.Tools);
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -5,11 +5,9 @@ using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
using Microsoft.Agents.AI;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete AIProjectClientFixture
|
||||
[Obsolete("Use FoundryVersionedAgentRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientAgentRunPreviousResponseTests() : RunTests<AIProjectClientFixture>(() => new())
|
||||
public class FoundryVersionedAgentRunStreamingPreviousResponseTests() : RunStreamingTests<FoundryVersionedAgentFixture>(() => new())
|
||||
{
|
||||
public override Task RunWithNoMessageDoesNotFailAsync()
|
||||
{
|
||||
@@ -18,8 +16,7 @@ public class AIProjectClientAgentRunPreviousResponseTests() : RunTests<AIProject
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use FoundryVersionedAgentRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientAgentRunConversationTests() : RunTests<AIProjectClientFixture>(() => new())
|
||||
public class FoundryVersionedAgentRunStreamingConversationTests() : RunStreamingTests<FoundryVersionedAgentFixture>(() => new())
|
||||
{
|
||||
public override Func<Task<AgentRunOptions?>> AgentRunOptionsFactory => async () =>
|
||||
{
|
||||
+3
-6
@@ -5,11 +5,9 @@ using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
using Microsoft.Agents.AI;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete AIProjectClientFixture
|
||||
[Obsolete("Use FoundryVersionedAgentRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientAgentRunStreamingPreviousResponseTests() : RunStreamingTests<AIProjectClientFixture>(() => new())
|
||||
public class FoundryVersionedAgentRunPreviousResponseTests() : RunTests<FoundryVersionedAgentFixture>(() => new())
|
||||
{
|
||||
public override Task RunWithNoMessageDoesNotFailAsync()
|
||||
{
|
||||
@@ -18,8 +16,7 @@ public class AIProjectClientAgentRunStreamingPreviousResponseTests() : RunStream
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use FoundryVersionedAgentRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientAgentRunStreamingConversationTests() : RunStreamingTests<AIProjectClientFixture>(() => new())
|
||||
public class FoundryVersionedAgentRunConversationTests() : RunTests<FoundryVersionedAgentFixture>(() => new())
|
||||
{
|
||||
public override Func<Task<AgentRunOptions?>> AgentRunOptionsFactory => async () =>
|
||||
{
|
||||
+10
-13
@@ -1,25 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
using AgentConformance.IntegrationTests.Support;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete AIProjectClientFixture
|
||||
[Obsolete("Use FoundryVersionedAgentStructuredOutputRunTests instead. These tests exercise obsolete AIProjectClient extension methods.")]
|
||||
public class AIProjectClientAgentStructuredOutputRunTests() : StructuredOutputRunTests<AIProjectClientStructuredOutputFixture<CityInfo>>(() => new AIProjectClientStructuredOutputFixture<CityInfo>())
|
||||
public class FoundryVersionedAgentStructuredOutputRunTests() : StructuredOutputRunTests<FoundryVersionedAgentStructuredOutputFixture<CityInfo>>(() => new FoundryVersionedAgentStructuredOutputFixture<CityInfo>())
|
||||
{
|
||||
private const string NotSupported = "AIProjectClient does not support specifying structured output type at invocation time.";
|
||||
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.";
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that response format provided at agent initialization is used when invoking RunAsync.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[RetryFact(Constants.RetryCount, Constants.RetryDelay)]
|
||||
[RetryFact(Constants.RetryCount, Constants.RetryDelay, Skip = ResponseFormatNotSupported)]
|
||||
public async Task RunWithResponseFormatAtAgentInitializationReturnsExpectedResultAsync()
|
||||
{
|
||||
// Arrange
|
||||
@@ -39,14 +37,14 @@ public class AIProjectClientAgentStructuredOutputRunTests() : StructuredOutputRu
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that generic RunAsync works with AIProjectClient when structured output is configured at agent initialization.
|
||||
/// Verifies that generic RunAsync works with versioned Foundry agents when structured output is configured at agent initialization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// AIProjectClient does not support specifying the structured output type at invocation time yet.
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[RetryFact(Constants.RetryCount, Constants.RetryDelay)]
|
||||
[RetryFact(Constants.RetryCount, Constants.RetryDelay, Skip = ResponseFormatNotSupported)]
|
||||
public async Task RunGenericWithResponseFormatAtAgentInitializationReturnsExpectedResultAsync()
|
||||
{
|
||||
// Arrange
|
||||
@@ -88,10 +86,9 @@ public class AIProjectClientAgentStructuredOutputRunTests() : StructuredOutputRu
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a fixture for testing AIProjectClient with structured output of type <typeparamref name="T"/> provided at agent initialization.
|
||||
/// Represents a fixture for testing versioned Foundry agents with structured output of type <typeparamref name="T"/> provided at agent initialization.
|
||||
/// </summary>
|
||||
[Obsolete("Use FoundryVersionedAgentStructuredOutputFixture instead.")]
|
||||
public class AIProjectClientStructuredOutputFixture<T> : AIProjectClientFixture
|
||||
public class FoundryVersionedAgentStructuredOutputFixture<T> : FoundryVersionedAgentFixture
|
||||
{
|
||||
public override async ValueTask InitializeAsync()
|
||||
{
|
||||
+70
-13
@@ -1,14 +1,17 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
#pragma warning disable CS0618 // Tests intentionally exercise obsolete extension methods
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using OpenAI.Responses;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace Microsoft.Agents.AI.FoundryMemory.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests.Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for <see cref="FoundryMemoryProvider"/> against a configured Azure AI Foundry Memory service.
|
||||
@@ -16,7 +19,6 @@ namespace Microsoft.Agents.AI.FoundryMemory.IntegrationTests;
|
||||
/// <remarks>
|
||||
/// These integration tests are skipped by default and require a live Azure AI Foundry Memory service.
|
||||
/// The tests need to be updated to use the new AIAgent-based API pattern.
|
||||
/// Set <see cref="SkipReason"/> to null to enable them after configuring the service.
|
||||
/// </remarks>
|
||||
public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
{
|
||||
@@ -25,6 +27,7 @@ public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
private readonly AIProjectClient? _client;
|
||||
private readonly string? _memoryStoreName;
|
||||
private readonly string? _deploymentName;
|
||||
private readonly string? _embeddingDeploymentName;
|
||||
private bool _disposed;
|
||||
|
||||
public FoundryMemoryProviderTests()
|
||||
@@ -38,13 +41,15 @@ public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
var endpoint = configuration[TestSettings.AzureAIProjectEndpoint];
|
||||
var memoryStoreName = configuration[TestSettings.AzureAIMemoryStoreId];
|
||||
var deploymentName = configuration[TestSettings.AzureAIModelDeploymentName];
|
||||
var embeddingDeploymentName = configuration[TestSettings.AzureAIEmbeddingDeploymentName];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(endpoint) &&
|
||||
!string.IsNullOrWhiteSpace(memoryStoreName))
|
||||
{
|
||||
this._client = new AIProjectClient(new Uri(endpoint), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
this._client = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
this._memoryStoreName = memoryStoreName;
|
||||
this._deploymentName = deploymentName ?? "gpt-4.1-mini";
|
||||
this._embeddingDeploymentName = embeddingDeploymentName ?? "text-embedding-ada-002";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +62,17 @@ public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
this._memoryStoreName!,
|
||||
stateInitializer: _ => new(new FoundryMemoryProviderScope("it-user-1")));
|
||||
|
||||
AIAgent agent = await this._client!.CreateAIAgentAsync(this._deploymentName!,
|
||||
options: new ChatClientAgentOptions { AIContextProviders = [memoryProvider] });
|
||||
await memoryProvider.EnsureMemoryStoreCreatedAsync(this._deploymentName!, this._embeddingDeploymentName!);
|
||||
|
||||
AIAgent agent = this._client!.AsAIAgent(new ChatClientAgentOptions
|
||||
{
|
||||
ChatOptions = new ChatOptions
|
||||
{
|
||||
ModelId = this._deploymentName!,
|
||||
Instructions = "You are a helpful assistant. Use known memories about the user when responding, and do not invent details."
|
||||
},
|
||||
AIContextProviders = [memoryProvider]
|
||||
});
|
||||
|
||||
AgentSession session = await agent.CreateSessionAsync();
|
||||
|
||||
@@ -72,6 +86,15 @@ public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
await memoryProvider.WhenUpdatesCompletedAsync();
|
||||
await Task.Delay(2000);
|
||||
|
||||
// Assert - verify memories were actually created in the store before querying via agent
|
||||
var searchResult = await this._client!.MemoryStores.SearchMemoriesAsync(
|
||||
this._memoryStoreName!,
|
||||
new MemorySearchOptions("it-user-1")
|
||||
{
|
||||
Items = { ResponseItem.CreateUserMessageItem("Caoimhe") }
|
||||
});
|
||||
Assert.NotEmpty(searchResult.Value.Memories);
|
||||
|
||||
AgentResponse resultAfter = await agent.RunAsync("What is my name?", session);
|
||||
|
||||
// Cleanup
|
||||
@@ -95,10 +118,27 @@ public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
this._memoryStoreName!,
|
||||
stateInitializer: _ => new(new FoundryMemoryProviderScope("it-scope-b")));
|
||||
|
||||
AIAgent agent1 = await this._client!.CreateAIAgentAsync(this._deploymentName!,
|
||||
options: new ChatClientAgentOptions { AIContextProviders = [memoryProvider1] });
|
||||
AIAgent agent2 = await this._client!.CreateAIAgentAsync(this._deploymentName!,
|
||||
options: new ChatClientAgentOptions { AIContextProviders = [memoryProvider2] });
|
||||
await memoryProvider1.EnsureMemoryStoreCreatedAsync(this._deploymentName!, this._embeddingDeploymentName!);
|
||||
|
||||
AIAgent agent1 = this._client!.AsAIAgent(new ChatClientAgentOptions
|
||||
{
|
||||
ChatOptions = new ChatOptions
|
||||
{
|
||||
ModelId = this._deploymentName!,
|
||||
Instructions = "You are a helpful assistant. Use known memories about the user when responding, and do not invent details."
|
||||
},
|
||||
AIContextProviders = [memoryProvider1]
|
||||
});
|
||||
|
||||
AIAgent agent2 = this._client!.AsAIAgent(new ChatClientAgentOptions
|
||||
{
|
||||
ChatOptions = new ChatOptions
|
||||
{
|
||||
ModelId = this._deploymentName!,
|
||||
Instructions = "You are a helpful assistant. Use known memories about the user when responding, and do not invent details."
|
||||
},
|
||||
AIContextProviders = [memoryProvider2]
|
||||
});
|
||||
|
||||
AgentSession session1 = await agent1.CreateSessionAsync();
|
||||
AgentSession session2 = await agent2.CreateSessionAsync();
|
||||
@@ -111,8 +151,25 @@ public sealed class FoundryMemoryProviderTests : IDisposable
|
||||
await memoryProvider1.WhenUpdatesCompletedAsync();
|
||||
await Task.Delay(2000);
|
||||
|
||||
AgentResponse result1 = await agent1.RunAsync("What is your name?", session1);
|
||||
AgentResponse result2 = await agent2.RunAsync("What is your name?", session2);
|
||||
// Assert - verify memories were created in scope A but not in scope B
|
||||
var searchResultA = await this._client!.MemoryStores.SearchMemoriesAsync(
|
||||
this._memoryStoreName!,
|
||||
new MemorySearchOptions("it-scope-a")
|
||||
{
|
||||
Items = { ResponseItem.CreateUserMessageItem("Caoimhe") }
|
||||
});
|
||||
Assert.NotEmpty(searchResultA.Value.Memories);
|
||||
|
||||
var searchResultB = await this._client.MemoryStores.SearchMemoriesAsync(
|
||||
this._memoryStoreName!,
|
||||
new MemorySearchOptions("it-scope-b")
|
||||
{
|
||||
Items = { ResponseItem.CreateUserMessageItem("Caoimhe") }
|
||||
});
|
||||
Assert.Empty(searchResultB.Value.Memories);
|
||||
|
||||
AgentResponse result1 = await agent1.RunAsync("What is my name?", session1);
|
||||
AgentResponse result2 = await agent2.RunAsync("What is my name?", session2);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Caoimhe", result1.Text);
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class ResponsesAgentChatClientRunStreamingTests() : ChatClientAgentRunStreamingTests<ResponsesAgentFixture>(() => new())
|
||||
{
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class ResponsesAgentChatClientRunTests() : ChatClientAgentRunTests<ResponsesAgentFixture>(() => new())
|
||||
{
|
||||
+26
-10
@@ -3,13 +3,13 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests.Support;
|
||||
using Azure.AI.Extensions.OpenAI;
|
||||
using Azure.AI.Projects;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.AzureAI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for non-versioned <see cref="ChatClientAgent"/> creation via <see cref="AIProjectClient"/> extension methods.
|
||||
@@ -30,16 +30,19 @@ public class ResponsesAgentExtensionCreateTests
|
||||
const string AgentDescription = "Integration test agent created from AIProjectClient.AsAIAgent(model, instructions).";
|
||||
const string VerificationToken = "integration-extension-ok";
|
||||
|
||||
FoundryAgent agent = this._client.AsAIAgent(
|
||||
ChatClientAgent agent = this._client.AsAIAgent(
|
||||
model: Model,
|
||||
instructions: $"You are a helpful assistant. When asked for verification, reply with exactly '{VerificationToken}'.",
|
||||
name: AgentName,
|
||||
description: AgentDescription);
|
||||
|
||||
AgentSession session = await agent.CreateSessionAsync();
|
||||
AgentSession? session = null;
|
||||
|
||||
try
|
||||
{
|
||||
var conversation = await CreateConversationAsync(this._client);
|
||||
session = await agent.CreateSessionAsync(conversation.Id);
|
||||
|
||||
// Act
|
||||
AgentResponse response = await agent.RunAsync("Return the verification token.", session);
|
||||
|
||||
@@ -47,7 +50,6 @@ public class ResponsesAgentExtensionCreateTests
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal(AgentName, agent.Name);
|
||||
Assert.Equal(AgentDescription, agent.Description);
|
||||
Assert.Same(this._client, agent.GetService<AIProjectClient>());
|
||||
Assert.NotNull(agent.GetService<IChatClient>());
|
||||
Assert.Contains(VerificationToken, response.Text, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -73,19 +75,22 @@ public class ResponsesAgentExtensionCreateTests
|
||||
},
|
||||
};
|
||||
|
||||
FoundryAgent agent = this._client.AsAIAgent(options);
|
||||
ChatClientAgentSession session = await agent.CreateConversationSessionAsync();
|
||||
ChatClientAgent agent = this._client.AsAIAgent(options);
|
||||
|
||||
ChatClientAgentSession? session = null;
|
||||
|
||||
try
|
||||
{
|
||||
var conversation = await CreateConversationAsync(this._client);
|
||||
session = ((await agent.CreateSessionAsync(conversation.Id)) as ChatClientAgentSession)!;
|
||||
|
||||
// Act
|
||||
AgentResponse response = await agent.RunAsync("Return the verification token.", session);
|
||||
|
||||
// Assert
|
||||
Assert.StartsWith("conv_", session.ConversationId, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.StartsWith("conv_", session!.ConversationId, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Equal(options.Name, agent.Name);
|
||||
Assert.Equal(options.Description, agent.Description);
|
||||
Assert.Same(this._client, agent.GetService<AIProjectClient>());
|
||||
Assert.Contains(VerificationToken, response.Text, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
finally
|
||||
@@ -94,8 +99,13 @@ public class ResponsesAgentExtensionCreateTests
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task DeleteSessionAsync(AIProjectClient client, AgentSession session)
|
||||
private static async Task DeleteSessionAsync(AIProjectClient client, AgentSession? session)
|
||||
{
|
||||
if (session is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChatClientAgentSession typedSession = (ChatClientAgentSession)session;
|
||||
|
||||
if (typedSession.ConversationId?.StartsWith("conv_", StringComparison.OrdinalIgnoreCase) == true)
|
||||
@@ -119,4 +129,10 @@ public class ResponsesAgentExtensionCreateTests
|
||||
await DeleteResponseChainAsync(client, response.Value.PreviousResponseId);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<ProjectConversation> CreateConversationAsync(AIProjectClient client)
|
||||
{
|
||||
ProjectConversationsClient conversationsClient = client.GetProjectOpenAIClient().GetProjectConversationsClient();
|
||||
return (await conversationsClient.CreateProjectConversationAsync()).Value!;
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -9,19 +9,18 @@ using AgentConformance.IntegrationTests.Support;
|
||||
using Azure.AI.Extensions.OpenAI;
|
||||
using Azure.AI.Projects;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.AzureAI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI.Responses;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration test fixture that creates non-versioned Responses agents via the direct <c>AIProjectClient.AsAIAgent(...)</c> path.
|
||||
/// </summary>
|
||||
public class ResponsesAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
private FoundryAgent _agent = null!;
|
||||
private ChatClientAgent _agent = null!;
|
||||
private AIProjectClient _client = null!;
|
||||
|
||||
public IChatClient ChatClient => this._agent.GetService<ChatClientAgent>()!.ChatClient;
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
using Microsoft.Agents.AI;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class ResponsesAgentRunStreamingPreviousResponseTests() : RunStreamingTests<ResponsesAgentFixture>(() => new())
|
||||
{
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests;
|
||||
using Microsoft.Agents.AI;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class ResponsesAgentRunPreviousResponseTests() : RunTests<ResponsesAgentFixture>(() => new())
|
||||
{
|
||||
+1
-1
@@ -7,7 +7,7 @@ using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace AzureAI.IntegrationTests;
|
||||
namespace Foundry.IntegrationTests;
|
||||
|
||||
public class ResponsesAgentStructuredOutputRunTests() : StructuredOutputRunTests<ResponsesAgentStructuredOutputFixture<CityInfo>>(() => new())
|
||||
{
|
||||
-3472
File diff suppressed because it is too large
Load Diff
+1814
File diff suppressed because it is too large
Load Diff
+18
-34
@@ -6,33 +6,35 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Extensions.OpenAI;
|
||||
using Azure.AI.Projects;
|
||||
|
||||
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests;
|
||||
|
||||
#pragma warning disable CS0618
|
||||
[Obsolete("Uses obsolete AIProjectClient.GetAIAgentAsync compatibility extensions while validating chat-client behavior.")]
|
||||
public class AzureAIProjectChatClientTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify that when the ChatOptions has a "conv_" prefixed conversation ID, the chat client uses conversation in the http requests via the chat client
|
||||
/// Verify that after the first RunAsync, the session's ConversationId is set from the
|
||||
/// response, and subsequent requests include that conversation ID automatically.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ChatClient_UsesDefaultConversationIdAsync()
|
||||
{
|
||||
// Arrange
|
||||
var requestTriggered = false;
|
||||
var responsesRequestCount = 0;
|
||||
using var httpHandler = new HttpHandlerAssert(async (request) =>
|
||||
{
|
||||
if (request.Method == HttpMethod.Post && request.RequestUri!.PathAndQuery.Contains("/responses"))
|
||||
{
|
||||
requestTriggered = true;
|
||||
responsesRequestCount++;
|
||||
|
||||
// Assert
|
||||
if (request.Content is not null)
|
||||
// Assert: On the second Responses API call, verify the conversation ID
|
||||
// from the first response is automatically included in the request body.
|
||||
if (responsesRequestCount == 2 && request.Content is not null)
|
||||
{
|
||||
var requestBody = await request.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
Assert.Contains("conv_12345", requestBody);
|
||||
Assert.Contains("resp_0888a", requestBody);
|
||||
}
|
||||
|
||||
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(TestDataUtil.GetOpenAIDefaultResponseJson(), Encoding.UTF8, "application/json") };
|
||||
@@ -50,20 +52,17 @@ public class AzureAIProjectChatClientTests
|
||||
new FakeAuthenticationTokenProvider(),
|
||||
new AIProjectClientOptions() { Transport = new HttpClientPipelineTransport(httpClient) });
|
||||
|
||||
var agent = await projectClient.GetAIAgentAsync(
|
||||
new ChatClientAgentOptions
|
||||
{
|
||||
Name = "test-agent",
|
||||
ChatOptions = new() { Instructions = "Test instructions", ConversationId = "conv_12345" }
|
||||
});
|
||||
var agent = projectClient.AsAIAgent(new AgentReference("agent-name"));
|
||||
|
||||
// Act
|
||||
var session = await agent.CreateSessionAsync();
|
||||
await agent.RunAsync("Hello", session);
|
||||
await agent.RunAsync("Follow up", session);
|
||||
|
||||
Assert.True(requestTriggered);
|
||||
// Assert
|
||||
Assert.Equal(2, responsesRequestCount);
|
||||
var chatClientSession = Assert.IsType<ChatClientAgentSession>(session);
|
||||
Assert.Equal("conv_12345", chatClientSession.ConversationId);
|
||||
Assert.Equal("resp_0888a46cbf2b1ff3006914596e05d08195a77c3f5187b769a7", chatClientSession.ConversationId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -102,12 +101,7 @@ public class AzureAIProjectChatClientTests
|
||||
new FakeAuthenticationTokenProvider(),
|
||||
new AIProjectClientOptions() { Transport = new HttpClientPipelineTransport(httpClient) });
|
||||
|
||||
var agent = await projectClient.GetAIAgentAsync(
|
||||
new ChatClientAgentOptions
|
||||
{
|
||||
Name = "test-agent",
|
||||
ChatOptions = new() { Instructions = "Test instructions" },
|
||||
});
|
||||
var agent = projectClient.AsAIAgent(new AgentReference("agent-name"));
|
||||
|
||||
// Act
|
||||
var session = await agent.CreateSessionAsync();
|
||||
@@ -154,12 +148,7 @@ public class AzureAIProjectChatClientTests
|
||||
new FakeAuthenticationTokenProvider(),
|
||||
new AIProjectClientOptions() { Transport = new HttpClientPipelineTransport(httpClient) });
|
||||
|
||||
var agent = await projectClient.GetAIAgentAsync(
|
||||
new ChatClientAgentOptions
|
||||
{
|
||||
Name = "test-agent",
|
||||
ChatOptions = new() { Instructions = "Test instructions", ConversationId = "conv_should_not_use_default" }
|
||||
});
|
||||
var agent = projectClient.AsAIAgent(new AgentReference("agent-name"));
|
||||
|
||||
// Act
|
||||
var session = await agent.CreateSessionAsync();
|
||||
@@ -206,12 +195,7 @@ public class AzureAIProjectChatClientTests
|
||||
new FakeAuthenticationTokenProvider(),
|
||||
new AIProjectClientOptions() { Transport = new HttpClientPipelineTransport(httpClient) });
|
||||
|
||||
var agent = await projectClient.GetAIAgentAsync(
|
||||
new ChatClientAgentOptions
|
||||
{
|
||||
Name = "test-agent",
|
||||
ChatOptions = new() { Instructions = "Test instructions" },
|
||||
});
|
||||
var agent = projectClient.AsAIAgent(new AgentReference("agent-name"));
|
||||
|
||||
// Act
|
||||
var session = await agent.CreateSessionAsync();
|
||||
+1
-1
@@ -7,7 +7,7 @@ using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests;
|
||||
|
||||
internal sealed class FakeAuthenticationTokenProvider : AuthenticationTokenProvider
|
||||
{
|
||||
+1
-1
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the <see cref="FoundryAgent"/> class.
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests;
|
||||
|
||||
internal sealed class HttpHandlerAssert : HttpClientHandler
|
||||
{
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Agents.AI.FoundryMemory.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests.Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="FoundryMemoryProvider"/> constructor validation.
|
||||
+1
-1
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.Core;
|
||||
|
||||
namespace Microsoft.Agents.AI.FoundryMemory.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests.Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a testable AIProjectClient with a mock HTTP handler.
|
||||
+6
-1
@@ -1,7 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||
<PackageReference Include="Azure.AI.Projects" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
+1
-1
@@ -6,7 +6,7 @@ using Azure.AI.Extensions.OpenAI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI.Responses;
|
||||
|
||||
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the <see cref="ProjectResponsesClientExtensions"/> class.
|
||||
+1
-1
@@ -4,7 +4,7 @@ using System.ClientModel.Primitives;
|
||||
using System.IO;
|
||||
using Azure.AI.Projects.Agents;
|
||||
|
||||
namespace Microsoft.Agents.AI.AzureAI.UnitTests;
|
||||
namespace Microsoft.Agents.AI.Foundry.UnitTests;
|
||||
|
||||
/// <summary>
|
||||
/// Utility class for loading and processing test data files.
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<InjectSharedIntegrationTestCode>True</InjectSharedIntegrationTestCode>
|
||||
<InjectSharedIntegrationTestAzureCredentialsCode>True</InjectSharedIntegrationTestAzureCredentialsCode>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.FoundryMemory\Microsoft.Agents.AI.FoundryMemory.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
|
||||
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.FoundryMemory\Microsoft.Agents.AI.FoundryMemory.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.Projects" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Workflows.Declarative\Microsoft.Agents.AI.Workflows.Declarative.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Workflows.Declarative.AzureAI\Microsoft.Agents.AI.Workflows.Declarative.AzureAI.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Workflows.Declarative.Foundry\Microsoft.Agents.AI.Workflows.Declarative.Foundry.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Workflows.Declarative.Mcp\Microsoft.Agents.AI.Workflows.Declarative.Mcp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user