mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Add integration test validating OpenAPI tools with AsAIAgent(agentVersion) (#4931)
* .NET: Add integration test for OpenAPI tools with AsAIAgent(agentVersion) Validates end-to-end flow creating a Foundry agent with an OpenAPI tool definition via native Azure.AI.Projects SDK types and wrapping it with AsAIAgent(agentVersion). The test confirms the server-side OpenAPI function is invoked correctly through RunAsync. Addresses #4883 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: RetryFact, PascalCase naming, stronger tool assertion - Use RetryFact with Skip for manual testing (flaky due to external API) - Fix agentName -> AgentName to match PascalCase convention in file - Strengthen tool invocation assertion: require >= 3 Eurozone countries - Add comment explaining server-side OpenAPI tools don't surface as FunctionCallContent in the MEAI abstraction Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
84fe6c46ab
commit
d2977d63da
@@ -188,6 +188,134 @@ public class AIProjectClientCreateTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that an agent version created with an OpenAPI tool definition via the native
|
||||
/// Azure.AI.Projects SDK and then wrapped with <c>AsAIAgent(agentVersion)</c> correctly
|
||||
/// invokes the server-side OpenAPI function through <c>RunAsync</c>.
|
||||
/// Regression test for https://github.com/microsoft/agent-framework/issues/4883.
|
||||
/// </summary>
|
||||
[RetryFact(Constants.RetryCount, Constants.RetryDelay, Skip = "For manual testing only")]
|
||||
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");
|
||||
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 = """
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "REST Countries API",
|
||||
"description": "Retrieve information about countries by currency code",
|
||||
"version": "v3.1"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://restcountries.com/v3.1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/currency/{currency}": {
|
||||
"get": {
|
||||
"description": "Get countries that use a specific currency code (e.g., USD, EUR, GBP)",
|
||||
"operationId": "GetCountriesByCurrency",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "currency",
|
||||
"in": "path",
|
||||
"description": "Currency code (e.g., USD, EUR, GBP)",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response with list of countries",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "No countries found for the currency"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
// Step 1: Create the OpenAPI function definition and agent version using native SDK types.
|
||||
var openApiFunction = new OpenApiFunctionDefinition(
|
||||
"get_countries",
|
||||
BinaryData.FromString(CountriesOpenApiSpec),
|
||||
new OpenAPIAnonymousAuthenticationDetails())
|
||||
{
|
||||
Description = "Retrieve information about countries by currency code"
|
||||
};
|
||||
|
||||
var definition = new PromptAgentDefinition(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { (ResponseTool)AgentTool.CreateOpenApiTool(openApiFunction) }
|
||||
};
|
||||
|
||||
AgentVersionCreationOptions creationOptions = new(definition);
|
||||
AgentVersion agentVersion = await this._client.Agents.CreateAgentVersionAsync(AgentName, creationOptions);
|
||||
|
||||
try
|
||||
{
|
||||
// Step 2: Wrap the agent version using AsAIAgent extension.
|
||||
ChatClientAgent agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert the agent was created correctly and retains version metadata.
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal(AgentName, agent.Name);
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
Assert.NotNull(retrievedVersion);
|
||||
|
||||
// Step 3: Call RunAsync to trigger the server-side OpenAPI function.
|
||||
var result = await agent.RunAsync("What countries use the Euro (EUR) as their currency? Please list them.");
|
||||
|
||||
// Step 4: Validate the OpenAPI tool was invoked server-side.
|
||||
// Note: Server-side OpenAPI tools (executed within the Responses API via AgentReference)
|
||||
// do not surface as FunctionCallContent in the MEAI abstraction — the API handles the full
|
||||
// tool loop internally. We validate tool invocation by asserting the response contains
|
||||
// multiple specific country names that the model would need API data to enumerate accurately.
|
||||
var text = result.ToString();
|
||||
Assert.NotEmpty(text);
|
||||
|
||||
// The response must mention multiple well-known Eurozone countries — requiring several
|
||||
// correct entries makes it highly unlikely the model answered purely from parametric knowledge.
|
||||
int matchCount = 0;
|
||||
foreach (var country in new[] { "Germany", "France", "Italy", "Spain", "Portugal", "Netherlands", "Belgium", "Austria", "Ireland", "Finland" })
|
||||
{
|
||||
if (text.Contains(country, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
matchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.True(
|
||||
matchCount >= 3,
|
||||
$"Expected response to list at least 3 Eurozone countries from the OpenAPI tool, but found {matchCount}. Response: {text}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.Agents.DeleteAgentAsync(AgentName);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
public async Task CreateAgent_CreatesAgentWithAIFunctionToolsAsync(string createMechanism)
|
||||
|
||||
Reference in New Issue
Block a user