// Copyright (c) Microsoft. All rights reserved. using System.Collections.Generic; using System.Linq; using System.Text.Json; using Microsoft.Agents.AI.AGUI.Shared; using Microsoft.Extensions.AI; namespace Microsoft.Agents.AI.AGUI.UnitTests; /// /// Unit tests for the class. /// public sealed class AIToolExtensionsTests { [Fact] public void AsAGUITools_WithAIFunction_ConvertsToAGUIToolCorrectly() { // Arrange AIFunction function = AIFunctionFactory.Create( (string location) => $"Weather in {location}", "GetWeather", "Gets the current weather"); List tools = [function]; // Act List aguiTools = tools.AsAGUITools().ToList(); // Assert AGUITool aguiTool = Assert.Single(aguiTools); Assert.Equal("GetWeather", aguiTool.Name); Assert.Equal("Gets the current weather", aguiTool.Description); Assert.NotEqual(default, aguiTool.Parameters); } [Fact] public void AsAGUITools_WithMultipleFunctions_ConvertsAllCorrectly() { // Arrange List tools = [ AIFunctionFactory.Create(() => "Result1", "Tool1", "First tool"), AIFunctionFactory.Create(() => "Result2", "Tool2", "Second tool"), AIFunctionFactory.Create(() => "Result3", "Tool3", "Third tool") ]; // Act List aguiTools = tools.AsAGUITools().ToList(); // Assert Assert.Equal(3, aguiTools.Count); Assert.Equal("Tool1", aguiTools[0].Name); Assert.Equal("Tool2", aguiTools[1].Name); Assert.Equal("Tool3", aguiTools[2].Name); } [Fact] public void AsAGUITools_WithNullInput_ReturnsEmptyEnumerable() { // Arrange IEnumerable? tools = null; // Act IEnumerable aguiTools = tools!.AsAGUITools(); // Assert Assert.NotNull(aguiTools); Assert.Empty(aguiTools); } [Fact] public void AsAGUITools_WithEmptyInput_ReturnsEmptyEnumerable() { // Arrange List tools = []; // Act List aguiTools = tools.AsAGUITools().ToList(); // Assert Assert.Empty(aguiTools); } [Fact] public void AsAGUITools_FiltersOutNonAIFunctionTools() { // Arrange - mix of AIFunction and non-function tools AIFunction function = AIFunctionFactory.Create(() => "Result", "TestTool"); // Create a custom AITool that's not an AIFunction var declaration = AIFunctionFactory.CreateDeclaration("DeclarationOnly", "Description", JsonElement.Parse("{}")); List tools = [function, declaration]; // Act List aguiTools = tools.AsAGUITools().ToList(); // Assert // Only the AIFunction should be converted, declarations are filtered Assert.Equal(2, aguiTools.Count); // Actually both convert since declaration is also AIFunctionDeclaration } [Fact] public void AsAITools_WithAGUITool_ConvertsToAIFunctionDeclarationCorrectly() { // Arrange AGUITool aguiTool = new() { Name = "TestTool", Description = "Test description", Parameters = JsonElement.Parse("""{"type":"object","properties":{}}""") }; List aguiTools = [aguiTool]; // Act List tools = aguiTools.AsAITools().ToList(); // Assert AITool tool = Assert.Single(tools); Assert.IsType(tool, exactMatch: false); var declaration = (AIFunctionDeclaration)tool; Assert.Equal("TestTool", declaration.Name); Assert.Equal("Test description", declaration.Description); } [Fact] public void AsAITools_WithMultipleAGUITools_ConvertsAllCorrectly() { // Arrange List aguiTools = [ new AGUITool { Name = "Tool1", Description = "Desc1", Parameters = JsonElement.Parse("{}") }, new AGUITool { Name = "Tool2", Description = "Desc2", Parameters = JsonElement.Parse("{}") }, new AGUITool { Name = "Tool3", Description = "Desc3", Parameters = JsonElement.Parse("{}") } ]; // Act List tools = aguiTools.AsAITools().ToList(); // Assert Assert.Equal(3, tools.Count); Assert.All(tools, t => Assert.IsType(t, exactMatch: false)); } [Fact] public void AsAITools_WithNullInput_ReturnsEmptyEnumerable() { // Arrange IEnumerable? aguiTools = null; // Act IEnumerable tools = aguiTools!.AsAITools(); // Assert Assert.NotNull(tools); Assert.Empty(tools); } [Fact] public void AsAITools_WithEmptyInput_ReturnsEmptyEnumerable() { // Arrange List aguiTools = []; // Act List tools = aguiTools.AsAITools().ToList(); // Assert Assert.Empty(tools); } [Fact] public void AsAITools_CreatesDeclarationsOnly_NotInvokableFunctions() { // Arrange AGUITool aguiTool = new() { Name = "RemoteTool", Description = "Tool implemented on server", Parameters = JsonElement.Parse("""{"type":"object"}""") }; // Act List aguiToolsList = [aguiTool]; AITool tool = aguiToolsList.AsAITools().Single(); // Assert // The tool should be a declaration, not an executable function Assert.IsType(tool, exactMatch: false); // AIFunctionDeclaration cannot be invoked (no implementation) // This is correct since the actual implementation exists on the client side } [Fact] public void RoundTrip_AIFunctionToAGUIToolBackToDeclaration_PreservesMetadata() { // Arrange AIFunction originalFunction = AIFunctionFactory.Create( (string name, int age) => $"{name} is {age} years old", "FormatPerson", "Formats person information"); // Act List originalList = [originalFunction]; AGUITool aguiTool = originalList.AsAGUITools().Single(); List aguiToolsList = [aguiTool]; AITool reconstructed = aguiToolsList.AsAITools().Single(); // Assert Assert.IsType(reconstructed, exactMatch: false); var declaration = (AIFunctionDeclaration)reconstructed; Assert.Equal("FormatPerson", declaration.Name); Assert.Equal("Formats person information", declaration.Description); // Schema should be preserved through the round trip Assert.NotEqual(default, declaration.JsonSchema); } }