.NET: AzureAI Package - Skip tool validation when UseProvidedChatClientAsIs is true (#4389)

* Skip tool validation when UseProvidedChatClientAsIs is true (#3855)

When GetAIAgentAsync is called with ChatClientAgentOptions.UseProvidedChatClientAsIs = true,
skip requireInvocableTools validation so users can handle function calls manually
via custom ChatClient middleware without needing to provide matching AIFunction tools.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Simplify requireInvocableTools expression per review feedback

UseProvidedChatClientAsIs is a non-nullable bool, so use ! operator
instead of != true for clarity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Decouple tool matching from validation and add tool preservation test (#3855)

Always match provided AIFunctions to server-side function definitions
regardless of requireInvocableTools flag. Only throw when validation
is required and no match is found. This ensures UseProvidedChatClientAsIs
still preserves user-provided AIFunction tools instead of falling back
to the broken ResponseToolAITool wrapper.

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:
Roger Barreto
2026-03-02 22:12:55 +00:00
committed by GitHub
Unverified
parent 3b4eed270f
commit a442ee115d
2 changed files with 75 additions and 9 deletions
@@ -191,7 +191,7 @@ public static partial class AzureAIProjectChatClientExtensions
AgentRecord agentRecord = await GetAgentRecordByNameAsync(aiProjectClient, options.Name, cancellationToken).ConfigureAwait(false);
var agentVersion = agentRecord.Versions.Latest;
var agentOptions = CreateChatClientAgentOptions(agentVersion, options, requireInvocableTools: true);
var agentOptions = CreateChatClientAgentOptions(agentVersion, options, requireInvocableTools: !options.UseProvidedChatClientAsIs);
return AsChatClientAgent(
aiProjectClient,
@@ -522,21 +522,23 @@ public static partial class AzureAIProjectChatClientExtensions
// Check function tools
foreach (ResponseTool responseTool in definitionTools)
{
if (requireInvocableTools && responseTool is FunctionTool functionTool)
if (responseTool is FunctionTool functionTool)
{
// Check if a tool with the same type and name exists in the provided tools.
// When invocable tools are required, match only AIFunction.
// Always prefer matching AIFunction when available, regardless of requireInvocableTools.
var matchingTool = chatOptions?.Tools?.FirstOrDefault(t => t is AIFunction tf && functionTool.FunctionName == tf.Name);
if (matchingTool is null)
{
(missingTools ??= []).Add($"Function tool: {functionTool.FunctionName}");
}
else
if (matchingTool is not null)
{
(agentTools ??= []).Add(matchingTool!);
continue;
}
if (requireInvocableTools)
{
(missingTools ??= []).Add($"Function tool: {functionTool.FunctionName}");
continue;
}
continue;
}
(agentTools ??= []).Add(responseTool.AsAITool());