// Copyright (c) Microsoft. All rights reserved. using Microsoft.Extensions.DependencyInjection; using Microsoft.SemanticKernel; using Resources; namespace GettingStarted; /// /// This example shows how to load an Open API instance. /// public sealed class Step9_OpenAPI_Plugins(ITestOutputHelper output) : BaseTest(output) { /// /// Shows how to load an Open API instance. /// [Fact] public async Task AddOpenAPIPlugins() { // Create a kernel with OpenAI chat completion IKernelBuilder kernelBuilder = Kernel.CreateBuilder(); kernelBuilder.AddOpenAIChatClient( modelId: TestConfiguration.OpenAI.ChatModelId, apiKey: TestConfiguration.OpenAI.ApiKey); Kernel kernel = kernelBuilder.Build(); // Load OpenAPI plugin var stream = EmbeddedResource.ReadStream("repair-service.json"); var plugin = await kernel.ImportPluginFromOpenApiAsync("RepairService", stream!); PromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }; Console.WriteLine(await kernel.InvokePromptAsync("List all of the repairs .", new(settings))); } /// /// Shows how to transform an Open API instance to support dependency injection with ChatClient. /// [Fact] public async Task TransformOpenAPIPlugins() { // Create a kernel with ChatClient and dependency injection var serviceProvider = BuildServiceProvider(); var kernel = serviceProvider.GetRequiredService(); // Load OpenAPI plugin var stream = EmbeddedResource.ReadStream("repair-service.json"); var plugin = await kernel.CreatePluginFromOpenApiAsync("RepairService", stream!); // Transform the plugin to use IMechanicService via dependency injection kernel.Plugins.Add(TransformPlugin(plugin)); PromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }; Console.WriteLine(await kernel.InvokePromptAsync("Book an appointment to drain the old engine oil and replace it with fresh oil.", new(settings))); } /// /// Build a ServiceProvider that can be used to resolve services. /// private ServiceProvider BuildServiceProvider() { var collection = new ServiceCollection(); collection.AddSingleton(new FakeMechanicService()); // Add ChatClient using OpenAI collection.AddOpenAIChatClient( modelId: TestConfiguration.OpenAI.ChatModelId, apiKey: TestConfiguration.OpenAI.ApiKey); var kernelBuilder = collection.AddKernel(); return collection.BuildServiceProvider(); } /// /// Transform the plugin to change the behavior of the createRepair function. /// public static KernelPlugin TransformPlugin(KernelPlugin plugin) { List? functions = []; foreach (KernelFunction function in plugin) { if (function.Name == "createRepair") { functions.Add(CreateRepairFunction(function)); } else { functions.Add(function); } } return KernelPluginFactory.CreateFromFunctions(plugin.Name, plugin.Description, functions); } /// /// Create a instance for the createRepair operation which only takes /// the title, description parameters and has a delegate which uses the IMechanicService to get the /// assignedTo. /// private static KernelFunction CreateRepairFunction(KernelFunction function) { var method = ( Kernel kernel, KernelFunction currentFunction, KernelArguments arguments, [FromKernelServices] IMechanicService mechanicService, CancellationToken cancellationToken) => { arguments.Add("assignedTo", mechanicService.GetMechanic()); arguments.Add("date", DateTime.UtcNow.ToString("R")); return function.InvokeAsync(kernel, arguments, cancellationToken); }; var options = new KernelFunctionFromMethodOptions() { FunctionName = function.Name, Description = function.Description, Parameters = function.Metadata.Parameters.Where(p => p.Name is "title" or "description").ToList(), ReturnParameter = function.Metadata.ReturnParameter, }; return KernelFunctionFactory.CreateFromMethod(method, options); } /// /// Interface for a service to get the mechanic to assign to the next job. /// public interface IMechanicService { /// /// Return the name of the mechanic to assign the next job to. /// string GetMechanic(); } /// /// Fake implementation of /// public class FakeMechanicService : IMechanicService { /// public string GetMechanic() => "Bob"; } }