< Summary

Information
Class: NexusLabs.Needlr.SemanticKernel.SemanticKernelSyringeExtensions
Assembly: NexusLabs.Needlr.SemanticKernel
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.SemanticKernel/SemanticKernelSyringeExtensions.cs
Line coverage
82%
Covered lines: 48
Uncovered lines: 10
Coverable lines: 58
Total lines: 199
Line coverage: 82.7%
Branch coverage
85%
Covered branches: 12
Total branches: 14
Branch coverage: 85.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.SemanticKernel/SemanticKernelSyringeExtensions.cs

#LineLine coverage
 1using Microsoft.Extensions.DependencyInjection;
 2using Microsoft.SemanticKernel;
 3
 4using NexusLabs.Needlr.SemanticKernel.PluginScanners;
 5
 6using System.Diagnostics.CodeAnalysis;
 7using System.Reflection;
 8
 9namespace NexusLabs.Needlr.SemanticKernel;
 10
 11/// <summary>
 12/// Extension methods for <see cref="SemanticKernelSyringe"/> providing fluent configuration of Semantic Kernel integrat
 13/// </summary>
 14public static class SemanticKernelSyringeExtensions
 15{
 16    public static SemanticKernelSyringe Configure(
 17        this SemanticKernelSyringe syringe,
 18        Action<KernelFactoryOptions> configure)
 19    {
 320        ArgumentNullException.ThrowIfNull(syringe);
 321        ArgumentNullException.ThrowIfNull(configure);
 22
 323        return syringe with
 324        {
 325            ConfigureKernelFactory = (syringe.ConfigureKernelFactory ?? []).Append(configure).ToList()
 326        };
 27    }
 28
 29    public static SemanticKernelSyringe AddSemanticKernelPlugin<T>(
 30        this SemanticKernelSyringe syringe)
 31    {
 1332        ArgumentNullException.ThrowIfNull(syringe);
 33
 1334        return syringe.AddSemanticKernelPlugins([typeof(T)]);
 35    }
 36
 37    /// <summary>
 38    /// Adds SemanticKernel plugins from a pre-discovered list of types.
 39    /// This is the recommended approach for AOT/trimmed applications.
 40    /// </summary>
 41    /// <param name="syringe">The SemanticKernel syringe to configure.</param>
 42    /// <param name="pluginTypes">
 43    /// Pre-discovered plugin types, typically from the generated
 44    /// <c>NexusLabs.Needlr.Generated.SemanticKernelPlugins.AllPluginTypes</c>.
 45    /// </param>
 46    /// <returns>The configured syringe.</returns>
 47    /// <remarks>
 48    /// Example usage with source-generated types:
 49    /// <code>
 50    /// syringe.AddSemanticKernelPluginsFromGenerated(
 51    ///     NexusLabs.Needlr.Generated.SemanticKernelPlugins.AllPluginTypes);
 52    /// </code>
 53    /// </remarks>
 54    public static SemanticKernelSyringe AddSemanticKernelPluginsFromGenerated(
 55        this SemanticKernelSyringe syringe,
 56        IReadOnlyList<Type> pluginTypes)
 57    {
 058        ArgumentNullException.ThrowIfNull(syringe);
 059        ArgumentNullException.ThrowIfNull(pluginTypes);
 60
 061        var scanner = new GeneratedSemanticKernelPluginScanner(pluginTypes);
 062        return syringe.AddSemanticKernelPluginsFromScanner(scanner);
 63    }
 64
 65    /// <summary>
 66    /// Adds SemanticKernel plugins from a custom scanner.
 67    /// </summary>
 68    /// <param name="syringe">The SemanticKernel syringe to configure.</param>
 69    /// <param name="scanner">The scanner to use for plugin discovery.</param>
 70    /// <param name="includeInstancePlugins">Whether to include instance plugins.</param>
 71    /// <param name="includeStaticPlugins">Whether to include static plugins.</param>
 72    /// <returns>The configured syringe.</returns>
 73    public static SemanticKernelSyringe AddSemanticKernelPluginsFromScanner(
 74        this SemanticKernelSyringe syringe,
 75        ISemanticKernelPluginScanner scanner,
 76        bool includeInstancePlugins = true,
 77        bool includeStaticPlugins = true)
 78    {
 079        ArgumentNullException.ThrowIfNull(syringe);
 080        ArgumentNullException.ThrowIfNull(scanner);
 81
 82        // This method doesn't require reflection for scanning since the scanner provides the types
 83        // However, the AddSemanticKernelPlugins method still uses reflection for type inspection
 084        return syringe.AddSemanticKernelPlugins(
 085            scanner,
 086            includeInstancePlugins: includeInstancePlugins,
 087            includeStaticPlugins: includeStaticPlugins);
 88    }
 89
 90    [RequiresUnreferencedCode("Assembly scanning uses reflection to discover types with [KernelFunction] methods.")]
 91    [RequiresDynamicCode("Assembly scanning uses reflection APIs that may require dynamic code generation.")]
 92    public static SemanticKernelSyringe AddSemanticKernelPluginsFromAssemblies(
 93        this SemanticKernelSyringe syringe,
 94        bool includeInstancePlugins = true,
 95        bool includeStaticPlugins = true)
 96    {
 997        ArgumentNullException.ThrowIfNull(syringe);
 98
 999        var assemblies = syringe.ServiceProvider.GetRequiredService<IReadOnlyList<Assembly>>();
 9100        return syringe.AddSemanticKernelPluginsFromAssemblies(
 9101            assemblies,
 9102            includeInstancePlugins: includeInstancePlugins,
 9103            includeStaticPlugins: includeStaticPlugins);
 104    }
 105
 106    [RequiresUnreferencedCode("Assembly scanning uses reflection to discover types with [KernelFunction] methods.")]
 107    [RequiresDynamicCode("Assembly scanning uses reflection APIs that may require dynamic code generation.")]
 108    public static SemanticKernelSyringe AddSemanticKernelPluginsFromAssemblies(
 109        this SemanticKernelSyringe syringe,
 110        IReadOnlyList<Assembly> asssemblies,
 111        bool includeInstancePlugins = true,
 112        bool includeStaticPlugins = true)
 113    {
 9114        ArgumentNullException.ThrowIfNull(syringe);
 9115        ArgumentNullException.ThrowIfNull(asssemblies);
 116
 9117        var scanner = new AssemblySemanticKernelPluginScanner(asssemblies);
 9118        return syringe.AddSemanticKernelPlugins(
 9119            scanner,
 9120            includeInstancePlugins: includeInstancePlugins,
 9121            includeStaticPlugins: includeStaticPlugins);
 122    }
 123
 124    [RequiresUnreferencedCode("Service provider scanning uses reflection to discover types with [KernelFunction] methods
 125    [RequiresDynamicCode("Service provider scanning uses reflection APIs that may require dynamic code generation.")]
 126    public static SemanticKernelSyringe AddSemanticKernelPluginsFromProvider(
 127        this SemanticKernelSyringe syringe)
 128    {
 4129        ArgumentNullException.ThrowIfNull(syringe);
 130
 4131        var scanner = new ServiceProviderSemanticKernelPluginScanner(syringe.ServiceProvider);
 4132        return syringe.AddSemanticKernelPlugins(scanner);
 133    }
 134
 135    [RequiresUnreferencedCode("Plugin scanning uses reflection to discover types with [KernelFunction] methods.")]
 136    [RequiresDynamicCode("Plugin scanning uses reflection APIs that may require dynamic code generation.")]
 137    public static SemanticKernelSyringe AddSemanticKernelPlugins(
 138        this SemanticKernelSyringe syringe,
 139        ISemanticKernelPluginScanner scanner,
 140        bool includeInstancePlugins = true,
 141        bool includeStaticPlugins = true)
 142    {
 13143        ArgumentNullException.ThrowIfNull(syringe);
 13144        ArgumentNullException.ThrowIfNull(scanner);
 145
 13146        var pluginTypes = scanner.ScanForPluginTypes();
 13147        return syringe.AddSemanticKernelPlugins(
 13148            pluginTypes,
 13149            includeInstancePlugins: includeInstancePlugins,
 13150            includeStaticPlugins: includeStaticPlugins);
 151    }
 152
 153    [RequiresUnreferencedCode("Plugin type inspection uses reflection to check for [KernelFunction] methods.")]
 154    [RequiresDynamicCode("Plugin type inspection uses reflection APIs that may require dynamic code generation.")]
 155    public static SemanticKernelSyringe AddSemanticKernelPlugins(
 156        this SemanticKernelSyringe syringe,
 157        IReadOnlyList<Type> pluginTypes,
 158        bool includeInstancePlugins = true,
 159        bool includeStaticPlugins = true)
 160    {
 26161        ArgumentNullException.ThrowIfNull(syringe);
 26162        ArgumentNullException.ThrowIfNull(pluginTypes);
 163
 26164        List<Type> typesToAdd = [];
 165
 392166        foreach (var pluginType in pluginTypes)
 167        {
 170168            if (pluginType.IsStatic())
 169            {
 27170                if (!includeStaticPlugins)
 171                {
 172                    continue;
 173                }
 174
 24175                if (!pluginType
 24176                    .GetMethods(BindingFlags.Public | BindingFlags.Static)
 48177                    .Any(m => m.IsDefined(typeof(KernelFunctionAttribute), inherit: true)))
 178                {
 179                    continue;
 180                }
 181
 24182                typesToAdd.Add(pluginType);
 24183                continue;
 184            }
 185
 143186            if (!includeInstancePlugins)
 187            {
 188                continue;
 189            }
 190
 123191            typesToAdd.Add(pluginType);
 192        }
 193
 26194        return syringe with
 26195        {
 26196            PluginTypes = (syringe.PluginTypes ?? []).Concat(typesToAdd).Distinct().ToList()
 26197        };
 198    }
 199}