// Copyright (c) Microsoft. All rights reserved.
using System;
using System.ComponentModel;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Xunit;
using Xunit.Abstractions;
namespace Examples;
/// <summary>
/// This example shows how to create a plugin class and interact with as described at
/// https://learn.microsoft.com/semantic-kernel/overview/
/// This sample uses function calling, so it only works on models newer than 0613.
/// </summary>
public class Plugin : BaseTest
{
[Fact]
public async Task RunAsync()
{
WriteLine("======== Plugin ========");
// Create kernel
// <KernelCreation>
var builder = Kernel.CreateBuilder();
builder.Services.AddOpenAIChatCompletion("qwen-max", "sk-one-api-token");
builder.Services.ConfigureHttpClientDefaults(b =>
b.ConfigurePrimaryHttpMessageHandler(() => new OneApiRedirectingHandler()));
builder.Plugins.AddFromType<LightPlugin>();
Kernel kernel = builder.Build();
// </KernelCreation>
// <Chat>
// Create chat history
var history = new ChatHistory();
// Get chat completion service
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// Start the conversation
Write("User > ");
string? userInput;
while ((userInput = ReadLine()) != null)
{
// Add user input
history.AddUserMessage(userInput);
// Enable auto function calling
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
// Get the response from the AI
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
// Print the results
WriteLine("Assistant > " + result);
// Add the message from the agent to the chat history
history.AddMessage(result.Role, result.Content ?? string.Empty);
// Get user input again
Write("User > ");
}
// </Chat>
}
public Plugin(ITestOutputHelper output) : base(output)
{
SimulatedInputText = [
"Hello",
"Can you turn on the lights"];
}
}
// <LightPlugin>
public class LightPlugin
{
public bool IsOn { get; set; } = false;
#pragma warning disable CA1024 // Use properties where appropriate
[KernelFunction]
[Description("Gets the state of the light.")]
public string GetState() => IsOn ? "on" : "off";
#pragma warning restore CA1024 // Use properties where appropriate
[KernelFunction]
[Description("Changes the state of the light.'")]
public string ChangeState(bool newState)
{
this.IsOn = newState;
var state = GetState();
// Print the state to the console
Console.WriteLine($"[Light is now {state}]");
return state;
}
}
// </LightPlugin>
public class OneApiRedirectingHandler() : DelegatingHandler(new HttpClientHandler())
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.RequestUri = new UriBuilder(request.RequestUri!) { Scheme = "http", Host = "one-api", Port = 3000 }.Uri;
return base.SendAsync(request, cancellationToken);
}
}