Files
agent-framework/dotnet/tests/AzureAI.IntegrationTests/AIProjectClientCreateTests.cs
T
Chris 904a5b843e Python / .NET Samples - Restructure and Improve Samples (Feature Branc… (#4092)
* Python: .NET Samples - Restructure and Improve Samples (Feature Branch) (#4091)

* Moved by agent (#4094)

* Fix readme links

* .NET Samples - Create `04-hosting` learning path step (#4098)

* Agent move

* Agent reorderd

* Remove A2A section from README 

Removed A2A section from the Getting Started README.

* Agent fixed links

* Fix broken sample links in durable-agents README (#4101)

* Initial plan

* Fix broken internal links in documentation

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Revert template link changes; keep only durable-agents README fix

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* .NET Samples - Create `03-workflows` learning path step (#4102)

* Fix solution project path

* Python: Fix broken markdown links to repo resources (outside /docs) (#4105)

* Initial plan

* Fix broken markdown links to repo resources

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Update README to rename .NET Workflows Samples section

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* .NET Samples - Create `02-agents` learning path step (#4107)

* .NET: Fix broken relative link in GroupChatToolApproval README (#4108)

* Initial plan

* Fix broken link in GroupChatToolApproval README

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Update labeler configuration for workflow samples

* .NET - Reorder Agents samples to start from Step01 instead of Step04 (#4110)

* Fix solution

* Resolve new sample paths

* Move new AgentSkills and AgentWithMemory_Step04 samples

* Fix link

* Fix readme path

* fix: update stale dotnet/samples/Durable path reference in AGENTS.md

Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>

* Moved new sample

* Update solution

* Resolve merge (new sample)

* Sync to new sample - FoundryAgents_Step21_BingCustomSearch

* Updated README

* .NET Samples - Configuration Naming Update (#4149)

* .NET: Restore AzureFunctions index parity with ConsoleApps under DurableAgents samples (#4221)

* Clean-up `05_host_your_agent`

* Config setting consistency

* Refine samples

* AGENTS.md

* Move new samples

* Re-order samples

* Move new project and fixup solution

* Fixup model config

* Fix up new UT project

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
2026-02-26 00:56:10 +00:00

232 lines
11 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.IO;
using System.Threading.Tasks;
using AgentConformance.IntegrationTests.Support;
using Azure.AI.Projects;
using Azure.AI.Projects.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Files;
using OpenAI.Responses;
using Shared.IntegrationTests;
namespace AzureAI.IntegrationTests;
public class AIProjectClientCreateTests
{
private readonly AIProjectClient _client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), new AzureCliCredential());
[Theory]
[InlineData("CreateWithChatClientAgentOptionsAsync")]
[InlineData("CreateWithFoundryOptionsAsync")]
public async Task CreateAgent_CreatesAgentWithCorrectMetadataAsync(string createMechanism)
{
// Arrange.
string AgentName = AIProjectClientFixture.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()
{
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}")
};
try
{
// Assert.
Assert.NotNull(agent);
Assert.Equal(AgentName, agent.Name);
Assert.Equal(AgentDescription, agent.Description);
Assert.Equal(AgentInstructions, agent.Instructions);
var agentRecord = await this._client.Agents.GetAgentAsync(agent.Name);
Assert.NotNull(agentRecord);
Assert.Equal(AgentName, agentRecord.Value.Name);
var definition = Assert.IsType<PromptAgentDefinition>(agentRecord.Value.Versions.Latest.Definition);
Assert.Equal(AgentDescription, agentRecord.Value.Versions.Latest.Description);
Assert.Equal(AgentInstructions, definition.Instructions);
}
finally
{
// Cleanup.
await this._client.Agents.DeleteAgentAsync(agent.Name);
}
}
[Theory(Skip = "For manual testing only")]
[InlineData("CreateWithChatClientAgentOptionsAsync")]
[InlineData("CreateWithFoundryOptionsAsync")]
public async Task CreateAgent_CreatesAgentWithVectorStoresAsync(string createMechanism)
{
// Arrange.
string AgentName = AIProjectClientFixture.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.
Do not answer a question unless you can find the answer using the File Search Tool.
""";
// Get the project OpenAI client.
var projectOpenAIClient = this._client.GetProjectOpenAIClient();
// Create a vector store.
var searchFilePath = Path.GetTempFileName() + "wordcodelookup.txt";
File.WriteAllText(
path: searchFilePath,
contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."
);
OpenAIFile uploadedAgentFile = projectOpenAIClient.GetProjectFilesClient().UploadFile(
filePath: searchFilePath,
purpose: FileUploadPurpose.Assistants
);
var vectorStoreMetadata = await projectOpenAIClient.GetProjectVectorStoresClient().CreateVectorStoreAsync(options: new() { FileIds = { uploadedAgentFile.Id }, Name = "WordCodeLookup_VectorStore" });
// Act.
var agent = createMechanism switch
{
"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}")
};
try
{
// Assert.
// Verify that the agent can use the vector store to answer a question.
var result = await agent.RunAsync("Can you give me the documented code for 'banana'?");
Assert.Contains("673457", result.ToString());
}
finally
{
// Cleanup.
await this._client.Agents.DeleteAgentAsync(agent.Name);
await projectOpenAIClient.GetProjectVectorStoresClient().DeleteVectorStoreAsync(vectorStoreMetadata.Value.Id);
await projectOpenAIClient.GetProjectFilesClient().DeleteFileAsync(uploadedAgentFile.Id);
File.Delete(searchFilePath);
}
}
[Theory]
[InlineData("CreateWithChatClientAgentOptionsAsync")]
[InlineData("CreateWithFoundryOptionsAsync")]
public async Task CreateAgent_CreatesAgentWithCodeInterpreterAsync(string createMechanism)
{
// Arrange.
string AgentName = AIProjectClientFixture.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.
""";
// Get the project OpenAI client.
var projectOpenAIClient = this._client.GetProjectOpenAIClient();
// Create a python file that prints a known value.
var codeFilePath = Path.GetTempFileName() + "secret_number.py";
File.WriteAllText(
path: codeFilePath,
contents: "print(\"SECRET_NUMBER=24601\")" // Deterministic output we will look for.
);
OpenAIFile uploadedCodeFile = projectOpenAIClient.GetProjectFilesClient().UploadFile(
filePath: codeFilePath,
purpose: FileUploadPurpose.Assistants
);
// Act.
var agent = createMechanism switch
{
// 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}")
};
try
{
// Assert.
var result = await agent.RunAsync("What is the SECRET_NUMBER?");
// We expect the model to run the code and surface the number.
Assert.Contains("24601", result.ToString());
}
finally
{
// Cleanup.
await this._client.Agents.DeleteAgentAsync(agent.Name);
await projectOpenAIClient.GetProjectFilesClient().DeleteFileAsync(uploadedCodeFile.Id);
File.Delete(codeFilePath);
}
}
[Theory]
[InlineData("CreateWithChatClientAgentOptionsAsync")]
public async Task CreateAgent_CreatesAgentWithAIFunctionToolsAsync(string createMechanism)
{
// Arrange.
string AgentName = AIProjectClientFixture.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);
ChatClientAgent agent = createMechanism switch
{
"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}")
};
try
{
// Act.
var response = await agent.RunAsync("What is the weather like in Amsterdam?");
// Assert - ensure function was invoked and its output surfaced.
var text = response.Text;
Assert.Contains("Amsterdam", text, StringComparison.OrdinalIgnoreCase);
Assert.Contains("sunny", text, StringComparison.OrdinalIgnoreCase);
Assert.Contains("23", text, StringComparison.OrdinalIgnoreCase);
}
finally
{
await this._client.Agents.DeleteAgentAsync(agent.Name);
}
}
}