-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New CreateFromType and CreateMetadataFromType methods
- Loading branch information
1 parent
ec9233c
commit 6dc2321
Showing
6 changed files
with
266 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
dotnet/src/SemanticKernel.Core/Functions/KernelFunctionMetadataFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Reflection; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.SemanticKernel; | ||
|
||
/// <summary> | ||
/// Provides factory methods for creating collections of <see cref="KernelFunctionMetadata"/>, such as | ||
/// those backed by a prompt to be submitted to an LLM or those backed by a .NET method. | ||
/// </summary> | ||
[Experimental("SKEXP0001")] | ||
public static class KernelFunctionMetadataFactory | ||
{ | ||
/// <summary> | ||
/// Creates a <see cref="KernelFunctionMetadata"/> enumeration for a method, specified via an <see cref="MethodInfo"/> instance. | ||
/// </summary> | ||
/// <param name="instanceType">Specifies the type of the object to extract <see cref="KernelFunctionMetadata"/> for.</param> | ||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging. If null, no logging will be performed.</param> | ||
/// <returns>A <see cref="KernelPlugin"/> containing <see cref="KernelFunction"/>s for all relevant members of <paramref name="instanceType"/>.</returns> | ||
/// <remarks> | ||
/// Methods decorated with <see cref="KernelFunctionAttribute"/> will be included in the plugin. | ||
/// Attributed methods must all have different names; overloads are not supported. | ||
/// </remarks> | ||
public static IEnumerable<KernelFunctionMetadata> CreateFromType(Type instanceType, ILoggerFactory? loggerFactory = null) | ||
{ | ||
Verify.NotNull(instanceType); | ||
|
||
MethodInfo[] methods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); | ||
|
||
// Filter out non-KernelFunctions and fail if two functions have the same name (with or without the same casing). | ||
var functionMetadata = new List<KernelFunctionMetadata>(); | ||
KernelFunctionFromMethodOptions options = new(); | ||
foreach (MethodInfo method in methods) | ||
{ | ||
if (method.GetCustomAttribute<KernelFunctionAttribute>() is not null) | ||
{ | ||
functionMetadata.Add(KernelFunctionFromMethod.CreateMetadata(method, loggerFactory: loggerFactory)); | ||
} | ||
} | ||
if (functionMetadata.Count == 0) | ||
{ | ||
throw new ArgumentException($"The {instanceType} instance doesn't implement any [KernelFunction]-attributed methods."); | ||
} | ||
|
||
return functionMetadata; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
dotnet/src/SemanticKernel.UnitTests/Functions/KernelFunctionMetadataFactoryTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
using Microsoft.SemanticKernel; | ||
using Xunit; | ||
|
||
namespace SemanticKernel.UnitTests.Functions; | ||
public class KernelFunctionMetadataFactoryTests | ||
{ | ||
[Fact] | ||
public void ItCanCreateFromType() | ||
{ | ||
// Arrange | ||
var instanceType = typeof(MyKernelFunctions); | ||
|
||
// Act | ||
var functionMetadata = KernelFunctionMetadataFactory.CreateFromType(instanceType); | ||
|
||
// Assert | ||
Assert.NotNull(functionMetadata); | ||
Assert.Equal(3, functionMetadata.Count<KernelFunctionMetadata>()); | ||
Assert.Contains(functionMetadata, f => f.Name == "Function1"); | ||
Assert.Contains(functionMetadata, f => f.Name == "Function2"); | ||
Assert.Contains(functionMetadata, f => f.Name == "Function3"); | ||
} | ||
|
||
#region private | ||
#pragma warning disable CA1812 // Used in test case above | ||
private sealed class MyKernelFunctions | ||
{ | ||
[KernelFunction("Function1")] | ||
[Description("Description for function 1.")] | ||
public string Function1([Description("Description for parameter 1")] string param1) => $"Function1: {param1}"; | ||
|
||
[KernelFunction("Function2")] | ||
[Description("Description for function 2.")] | ||
public string Function2([Description("Description for parameter 1")] string param1) => $"Function2: {param1}"; | ||
|
||
[KernelFunction("Function3")] | ||
[Description("Description for function 3.")] | ||
public string Function3([Description("Description for parameter 1")] string param1) => $"Function3: {param1}"; | ||
} | ||
#pragma warning restore CA1812 | ||
#endregion | ||
} |
80 changes: 80 additions & 0 deletions
80
dotnet/src/SemanticKernel.UnitTests/Functions/KernelPluginFactoryTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System.ComponentModel; | ||
using System.Threading.Tasks; | ||
using Microsoft.SemanticKernel; | ||
using Xunit; | ||
|
||
namespace SemanticKernel.UnitTests.Functions; | ||
public class KernelPluginFactoryTests | ||
{ | ||
[Fact] | ||
public async Task ItCanCreateFromObjectAsync() | ||
{ | ||
// Arrange | ||
var kernel = new Kernel(); | ||
var args = new KernelArguments { { "param1", "value1" } }; | ||
var target = new MyKernelFunctions(); | ||
|
||
// Act | ||
var plugin = KernelPluginFactory.CreateFromObject(target); | ||
FunctionResult result = await plugin["Function1"].InvokeAsync(kernel, args); | ||
|
||
// Assert | ||
Assert.NotNull(plugin); | ||
Assert.Equal(3, plugin.FunctionCount); | ||
Assert.Equal("Function1: value1", result.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task ItCanCreateFromTypeUsingGenericsAsync() | ||
{ | ||
// Arrange | ||
var kernel = new Kernel(); | ||
var args = new KernelArguments { { "param1", "value1" } }; | ||
|
||
// Act | ||
var plugin = KernelPluginFactory.CreateFromType<MyKernelFunctions>(); | ||
FunctionResult result = await plugin["Function1"].InvokeAsync(kernel, args); | ||
|
||
// Assert | ||
Assert.NotNull(plugin); | ||
Assert.Equal(3, plugin.FunctionCount); | ||
Assert.Equal("Function1: value1", result.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task ItCanCreateFromTypeAsync() | ||
{ | ||
// Arrange | ||
var kernel = new Kernel(); | ||
var args = new KernelArguments { { "param1", "value1" } }; | ||
var instanceType = typeof(MyKernelFunctions); | ||
|
||
// Act | ||
var plugin = KernelPluginFactory.CreateFromType(instanceType); | ||
FunctionResult result = await plugin["Function1"].InvokeAsync(kernel, args); | ||
|
||
// Assert | ||
Assert.NotNull(plugin); | ||
Assert.Equal(3, plugin.FunctionCount); | ||
Assert.Equal("Function1: value1", result.Value); | ||
} | ||
|
||
#region private | ||
private sealed class MyKernelFunctions | ||
{ | ||
[KernelFunction("Function1")] | ||
[Description("Description for function 1.")] | ||
public string Function1([Description("Description for parameter 1")] string param1) => $"Function1: {param1}"; | ||
|
||
[KernelFunction("Function2")] | ||
[Description("Description for function 2.")] | ||
public string Function2([Description("Description for parameter 1")] string param1) => $"Function2: {param1}"; | ||
|
||
[KernelFunction("Function3")] | ||
[Description("Description for function 3.")] | ||
public string Function3([Description("Description for parameter 1")] string param1) => $"Function3: {param1}"; | ||
} | ||
#endregion | ||
} |