diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index f7a78e5535..324d63cb19 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -49,6 +49,7 @@
+
diff --git a/dotnet/samples/A2AClientServer/A2AClient/HostClientAgent.cs b/dotnet/samples/A2AClientServer/A2AClient/HostClientAgent.cs
index db95f49af4..75513b0834 100644
--- a/dotnet/samples/A2AClientServer/A2AClient/HostClientAgent.cs
+++ b/dotnet/samples/A2AClientServer/A2AClient/HostClientAgent.cs
@@ -25,7 +25,7 @@ internal sealed class HostClientAgent
// Connect to the remote agents via A2A
var createAgentTasks = agentUrls.Select(agentUrl => this.CreateAgentAsync(agentUrl));
var agents = await Task.WhenAll(createAgentTasks);
- var tools = agents.Select(agent => (AITool)AgentAIFunctionFactory.CreateFromAgent(agent)).ToList();
+ var tools = agents.Select(agent => (AITool)agent.AsAIFunction()).ToList();
// Create the agent that uses the remote agents as tools
this.Agent = new OpenAIClient(new ApiKeyCredential(apiKey))
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step12_AsFunctionTool/Agent_Step12_AsFunctionTool.csproj b/dotnet/samples/GettingStarted/Agents/Agent_Step12_AsFunctionTool/Agent_Step12_AsFunctionTool.csproj
new file mode 100644
index 0000000000..84ef628db4
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step12_AsFunctionTool/Agent_Step12_AsFunctionTool.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net9.0
+ 12
+
+ enable
+ disable
+ 3afc9b74-af74-4d8e-ae96-fa1c511d11ac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step12_AsFunctionTool/Program.cs b/dotnet/samples/GettingStarted/Agents/Agent_Step12_AsFunctionTool/Program.cs
new file mode 100644
index 0000000000..50feac82bd
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step12_AsFunctionTool/Program.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample shows how to create and use a Azure OpenAI AI agent as a function tool.
+
+using System;
+using System.ComponentModel;
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.AI.Agents;
+using OpenAI;
+
+var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+[Description("Get the weather for a given location.")]
+static string GetWeather([Description("The location to get the weather for.")] string location)
+ => $"The weather in {location} is cloudy with a high of 15°C.";
+
+// Create the chat client and agent, and provide the function tool to the agent.
+AIAgent weatherAgent = new AzureOpenAIClient(
+ new Uri(endpoint),
+ new AzureCliCredential())
+ .GetChatClient(deploymentName)
+ .CreateAIAgent(
+ instructions: "You answer questions about the weather.",
+ name: "WeatherAgent",
+ description: "An agent that answers questions about the weather.",
+ tools: [AIFunctionFactory.Create(GetWeather)]);
+
+// Create the main agent, and provide the weather agent as a function tool.
+AIAgent agent = new AzureOpenAIClient(
+ new Uri(endpoint),
+ new AzureCliCredential())
+ .GetChatClient(deploymentName)
+ .CreateAIAgent(instructions: "You are a helpful assistant who responds in French.", tools: [weatherAgent.AsAIFunction()]);
+
+// Invoke the agent and output the text result.
+Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));
diff --git a/dotnet/samples/GettingStarted/Agents/README.md b/dotnet/samples/GettingStarted/Agents/README.md
index c6959aee65..43da38e0ff 100644
--- a/dotnet/samples/GettingStarted/Agents/README.md
+++ b/dotnet/samples/GettingStarted/Agents/README.md
@@ -37,6 +37,7 @@ Before you begin, ensure you have the following prerequisites:
|[Dependency injection with a simple agent](./Agent_Step09_DependencyInjection/)|This sample demonstrates how to add and resolve an agent with a dependency injection container|
|[Exposing a simple agent as MCP tool](./Agent_Step10_AsMcpTool/)|This sample demonstrates how to expose an agent as an MCP tool|
|[Using images with a simple agent](./Agent_Step11_UsingImages/)|This sample demonstrates how to use image multi-modality with an AI agent|
+|[Exposing a simple agent a function tool](./Agent_Step12_AsFunctionTool/)|This sample demonstrates how to expose an agent as a function tool|
## Running the samples from the console
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents/AgentAIFunctionFactory.cs b/dotnet/src/Microsoft.Extensions.AI.Agents/AgentAIFunctionFactory.cs
deleted file mode 100644
index 76f8f8fe12..0000000000
--- a/dotnet/src/Microsoft.Extensions.AI.Agents/AgentAIFunctionFactory.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Shared.Diagnostics;
-using static Microsoft.Extensions.AI.Agents.OpenTelemetryConsts.GenAI;
-
-namespace Microsoft.Extensions.AI.Agents;
-
-///
-/// Provides factory methods for creating implementations of backed by an .
-///
-public static class AgentAIFunctionFactory
-{
- ///
- /// Creates a that will invoke the provided Agent.
- ///
- /// The to be represented via the created .
- /// Metadata to use to override defaults inferred from .
- /// The created for invoking the .
- public static AIFunction CreateFromAgent(
- AIAgent agent,
- AIFunctionFactoryOptions? options = null)
- {
- Throw.IfNull(agent);
-
- async Task RunAgentAsync(string query, CancellationToken cancellationToken)
- {
- var response = await agent.RunAsync(query, cancellationToken: cancellationToken).ConfigureAwait(false);
- return response.Text;
- }
-
- return AIFunctionFactory.Create(RunAgentAsync, options ?? new()
- {
- Name = agent.Name,
- Description = agent.Description,
- });
- }
-}
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents/AgentExtensions.cs b/dotnet/src/Microsoft.Extensions.AI.Agents/AgentExtensions.cs
index d45130ce38..4ceec57304 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents/AgentExtensions.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents/AgentExtensions.cs
@@ -1,6 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
+using System.ComponentModel;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
+using Microsoft.Shared.Diagnostics;
namespace Microsoft.Extensions.AI.Agents;
@@ -24,4 +28,31 @@ public static class AgentExtensions
EnableSensitiveData = enableSensitiveData ?? false
};
}
+
+ ///
+ /// Creates a that will invoke the provided Agent.
+ ///
+ /// The to be represented via the created .
+ /// Metadata to use to override defaults inferred from .
+ /// The to use for the function.
+ /// The created for invoking the .
+ public static AIFunction AsAIFunction(this AIAgent agent, AIFunctionFactoryOptions? options = null, AgentThread? thread = null)
+ {
+ Throw.IfNull(agent);
+
+ [Description("Invoke an agent to retrieve some information.")]
+ async Task InvokeAgentAsync(
+ [Description("Input query to invoke the agent.")] string query,
+ CancellationToken cancellationToken)
+ {
+ var response = await agent.RunAsync(query, thread: thread, cancellationToken: cancellationToken).ConfigureAwait(false);
+ return response.Text;
+ }
+
+ options ??= new();
+ options.Name ??= agent.Name;
+ options.Description ??= agent.Description;
+
+ return AIFunctionFactory.Create(InvokeAgentAsync, options);
+ }
}
diff --git a/dotnet/tests/Microsoft.Extensions.AI.Agents.UnitTests/AgentAIFunctionFactoryTests.cs b/dotnet/tests/Microsoft.Extensions.AI.Agents.UnitTests/AgentExtensionsTests.cs
similarity index 88%
rename from dotnet/tests/Microsoft.Extensions.AI.Agents.UnitTests/AgentAIFunctionFactoryTests.cs
rename to dotnet/tests/Microsoft.Extensions.AI.Agents.UnitTests/AgentExtensionsTests.cs
index 014c9b6759..5292277f02 100644
--- a/dotnet/tests/Microsoft.Extensions.AI.Agents.UnitTests/AgentAIFunctionFactoryTests.cs
+++ b/dotnet/tests/Microsoft.Extensions.AI.Agents.UnitTests/AgentExtensionsTests.cs
@@ -10,16 +10,16 @@ using Moq;
namespace Microsoft.Extensions.AI.Agents.UnitTests;
///
-/// Unit tests for the class.
+/// Unit tests for the method.
///
-public class AgentAIFunctionFactoryTests
+public class AgentExtensionsTests
{
[Fact]
public void CreateFromAgent_WithNullAgent_ThrowsArgumentNullException()
{
// Act & Assert
var exception = Assert.Throws(() =>
- AgentAIFunctionFactory.CreateFromAgent(null!));
+ AgentExtensions.AsAIFunction(null!));
Assert.Equal("agent", exception.ParamName);
}
@@ -33,7 +33,7 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns("Test agent description");
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object);
+ var result = mockAgent.Object.AsAIFunction();
// Assert
Assert.NotNull(result);
@@ -51,7 +51,7 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns("Test description");
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object);
+ var result = mockAgent.Object.AsAIFunction();
// Assert
Assert.NotNull(result);
@@ -60,7 +60,7 @@ public class AgentAIFunctionFactoryTests
}
[Fact]
- public void CreateFromAgent_WithAgentHavingNullDescription_UsesEmptyDescription()
+ public void CreateFromAgent_WithAgentHavingNullDescription_UsesDefaultDescription()
{
// Arrange
var mockAgent = new Mock();
@@ -68,12 +68,12 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns((string?)null);
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object);
+ var result = mockAgent.Object.AsAIFunction();
// Assert
Assert.NotNull(result);
Assert.Equal("TestAgent", result.Name);
- Assert.Equal(string.Empty, result.Description);
+ Assert.Equal("Invoke an agent to retrieve some information.", result.Description);
}
[Fact]
@@ -91,7 +91,7 @@ public class AgentAIFunctionFactoryTests
};
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object, customOptions);
+ var result = mockAgent.Object.AsAIFunction(customOptions);
// Assert
Assert.NotNull(result);
@@ -108,7 +108,7 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns("Test agent description");
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object, null);
+ var result = mockAgent.Object.AsAIFunction(null);
// Assert
Assert.NotNull(result);
@@ -123,7 +123,7 @@ public class AgentAIFunctionFactoryTests
var expectedResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Test response"));
var testAgent = new TestAgent("TestAgent", "Test description", expectedResponse);
- var aiFunction = AgentAIFunctionFactory.CreateFromAgent(testAgent);
+ var aiFunction = testAgent.AsAIFunction();
// Act
var arguments = new AIFunctionArguments() { ["query"] = "Test query" };
@@ -143,7 +143,7 @@ public class AgentAIFunctionFactoryTests
using var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
- var aiFunction = AgentAIFunctionFactory.CreateFromAgent(testAgent);
+ var aiFunction = testAgent.AsAIFunction();
// Act
var arguments = new AIFunctionArguments() { ["query"] = "Test query" };
@@ -161,7 +161,7 @@ public class AgentAIFunctionFactoryTests
var expectedException = new InvalidOperationException("Test exception");
var testAgent = new TestAgent("TestAgent", "Test description", expectedException);
- var aiFunction = AgentAIFunctionFactory.CreateFromAgent(testAgent);
+ var aiFunction = testAgent.AsAIFunction();
// Act & Assert
var arguments = new AIFunctionArguments() { ["query"] = "Test query" };
@@ -180,7 +180,7 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns("Test description");
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object);
+ var result = mockAgent.Object.AsAIFunction();
// Assert
Assert.NotNull(result);
@@ -204,7 +204,7 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns("Test description");
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object);
+ var result = mockAgent.Object.AsAIFunction();
// Assert
Assert.NotNull(result);
@@ -221,7 +221,7 @@ public class AgentAIFunctionFactoryTests
mockAgent.Setup(a => a.Description).Returns(string.Empty);
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object);
+ var result = mockAgent.Object.AsAIFunction();
// Assert
Assert.NotNull(result);
@@ -244,7 +244,7 @@ public class AgentAIFunctionFactoryTests
};
// Act
- var result = AgentAIFunctionFactory.CreateFromAgent(mockAgent.Object, customOptions);
+ var result = mockAgent.Object.AsAIFunction(customOptions);
// Assert
Assert.NotNull(result);
@@ -265,7 +265,7 @@ public class AgentAIFunctionFactoryTests
};
var testAgent = new TestAgent("TestAgent", "Test description", expectedResponse);
- var aiFunction = AgentAIFunctionFactory.CreateFromAgent(testAgent);
+ var aiFunction = testAgent.AsAIFunction();
// Act
var arguments = new AIFunctionArguments() { ["query"] = "Test query" };