Skip to content

Commit

Permalink
.Net: Deprecate OpenAI plugins (microsoft#6907)
Browse files Browse the repository at this point in the history
### Motivation and Context
As OpenAI ChatGPT plugins have been deprecated, SK no longer needs to
maintain code for working with them.

### Description
This PR annotates all OpenAI ChatGPT plugin-related code with the
obsolete attribute to notify potential consumers of the API that the
plugins will be deprecated.

Addresses the first step from the task:
microsoft#6881

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄
  • Loading branch information
SergeyMenshykh authored Jun 24, 2024
1 parent f3269f7 commit 616d6a9
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Plugins;

[Obsolete("OpenAI plugins are deprecated and will be removed in a future version.")]
public class CreatePluginFromOpenAI_AzureKeyVault(ITestOutputHelper output) : BaseTest(output)
{
private const string SecretName = "Foo";
Expand Down Expand Up @@ -118,6 +119,7 @@ private async Task GetSecretFromAzureKeyVaultWithRetryAsync(Kernel kernel, Kerne
/// <summary>
/// Provides authentication for HTTP requests to OpenAI using OAuth or verification tokens.
/// </summary>
[Obsolete("OpenAI plugins are deprecated and will be removed in a future version.")]
internal sealed class OpenAIAuthenticationProvider(Dictionary<string, Dictionary<string, string>>? oAuthValues = null, Dictionary<string, string>? credentials = null)
{
private readonly Dictionary<string, Dictionary<string, string>> _oAuthValues = oAuthValues ?? [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task RunOpenAIPluginWithMetadataAsync()
WriteStringToStream(schemaStream, schema);

// Import an Open API plugin from a stream.
var plugin = await kernel.CreatePluginFromOpenApiAsync("GithubVersionsApi", schemaStream, new OpenAIFunctionExecutionParameters(httpClient));
var plugin = await kernel.CreatePluginFromOpenApiAsync("GithubVersionsApi", schemaStream, new OpenApiFunctionExecutionParameters(httpClient));

// Get the function to be invoked and its metadata and extension properties.
var function = plugin["getVersions"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@

namespace Plugins;

public class OpenAIPlugins(ITestOutputHelper output) : BaseTest(output)
public class CreatePluginFromOpenApiSpec_Klarna(ITestOutputHelper output) : BaseTest(output)
{
/// <summary>
/// This sample shows how to invoke an OpenAI plugin.
/// This sample shows how to invoke an OpenApi plugin.
/// </summary>
/// <remarks>
/// You must provide the plugin name and a URI to the Open API manifest before running this sample.
/// </remarks>
[Fact(Skip = "Run it only after filling the template below")]
public async Task InvokeOpenAIPluginAsync()
public async Task InvokeOpenApiPluginAsync()
{
Kernel kernel = new();

// This HTTP client is optional. SK will fallback to a default internal one if omitted.
using HttpClient httpClient = new();

// Import an Open AI plugin via URI
var plugin = await kernel.ImportPluginFromOpenAIAsync("<plugin name>", new Uri("<OpenAI-plugin>"), new OpenAIFunctionExecutionParameters(httpClient));
var plugin = await kernel.ImportPluginFromOpenApiAsync("<plugin name>", new Uri("<OpenApi-plugin>"), new OpenApiFunctionExecutionParameters(httpClient));

// Add arguments for required parameters, arguments for optional ones can be skipped.
var arguments = new KernelArguments { ["<parameter-name>"] = "<parameter-value>" };
Expand All @@ -39,11 +39,11 @@ public async Task InvokeOpenAIPluginAsync()
/// This sample shows how to invoke the Klarna Get Products function as an OpenAPI plugin.
/// </summary>
[Fact]
public async Task InvokeKlarnaGetProductsAsOpenAPIPluginAsync()
public async Task InvokeKlarnaGetProductsAsOpenApiPluginAsync()
{
Kernel kernel = new();

var plugin = await kernel.ImportPluginFromOpenAIAsync("Klarna", new Uri("https://www.klarna.com/.well-known/ai-plugin.json"));
var plugin = await kernel.ImportPluginFromOpenApiAsync("Klarna", new Uri("https://www.klarna.com/us/shopping/public/openai/v0/api-docs/"));

var arguments = new KernelArguments
{
Expand All @@ -70,15 +70,15 @@ public async Task InvokeKlarnaGetProductsAsOpenAPIPluginAsync()
/// The <see cref="OpenApiKernelFunctionContext"/> contains the <see cref="Kernel"/>, <see cref="KernelFunction"/> and <see cref="KernelArguments"/>.
/// </remarks>
[Fact]
public async Task UseDelegatingHandlerWhenInvokingAnOpenAPIFunctionAsync()
public async Task UseDelegatingHandlerWhenInvokingAnOpenApiFunctionAsync()
{
using var httpHandler = new HttpClientHandler();
using var customHandler = new CustomHandler(httpHandler);
using HttpClient httpClient = new(customHandler);

Kernel kernel = new();

var plugin = await kernel.ImportPluginFromOpenAIAsync("Klarna", new Uri("https://www.klarna.com/.well-known/ai-plugin.json"), new OpenAIFunctionExecutionParameters(httpClient));
var plugin = await kernel.ImportPluginFromOpenApiAsync("Klarna", new Uri("https://www.klarna.com/us/shopping/public/openai/v0/api-docs/"), new OpenApiFunctionExecutionParameters(httpClient));

var arguments = new KernelArguments
{
Expand Down
4 changes: 2 additions & 2 deletions dotnet/samples/Concepts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ Down below you can find the code snippets that demonstrate the usage of many Sem

- [ApiManifestBasedPlugins](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/ApiManifestBasedPlugins.cs)
- [ConversationSummaryPlugin](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/ConversationSummaryPlugin.cs)
- [CreatePluginFromOpenAI_AzureKeyVault](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CreatePluginFromOpenAI_AzureKeyVault.cs)
- [CreatePluginFromOpenAI_AzureKeyVault](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CreatePluginFromOpenAI_AzureKeyVault.cs)(Deprecated)
- [CreatePluginFromOpenApiSpec_Github](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CreatePluginFromOpenApiSpec_Github.cs)
- [CreatePluginFromOpenApiSpec_Jira](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CreatePluginFromOpenApiSpec_Jira.cs)
- [CreatePluginFromOpenApiSpec_Klarna](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CreatePluginFromOpenApiSpec_Klarna.cs)
- [CustomMutablePlugin](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CustomMutablePlugin.cs)
- [DescribeAllPluginsAndFunctions](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/DescribeAllPluginsAndFunctions.cs)
- [GroundednessChecks](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/GroundednessChecks.cs)
- [ImportPluginFromGrpc](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/ImportPluginFromGrpc.cs)
- [OpenAIPlugins](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/OpenAIPlugins.cs)

## PromptTemplates - Using [`Templates`](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel.Abstractions/PromptTemplate/IPromptTemplate.cs) with parametrization for `Prompt` rendering

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Microsoft.SemanticKernel.Plugins.OpenApi;
/// <summary>
/// Provides extension methods for importing plugins exposed through OpenAI's ChatGPT format.
/// </summary>
[Obsolete("This class is deprecated and will be removed in a future version.")]
public static class OpenAIPluginKernelExtensions
{
private static readonly JsonSerializerOptions s_jsonOptionsCache =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -14,4 +15,5 @@ namespace Microsoft.SemanticKernel.Plugins.OpenApi;
/// <param name="openAIAuthConfig">The <see cref="OpenAIAuthenticationConfig"/> used to authenticate.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[Obsolete("This delegate is deprecated and will be removed in a future version.")]
public delegate Task OpenAIAuthenticateRequestAsyncCallback(HttpRequestMessage request, string pluginName, OpenAIAuthenticationConfig openAIAuthConfig, CancellationToken cancellationToken = default);
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.SemanticKernel.Plugins.OpenApi;
/// <summary>
/// Represents the authentication section for an OpenAI plugin.
/// </summary>
[Obsolete("This class is deprecated and will be removed in a future version.")]
public class OpenAIAuthenticationConfig
{
/// <summary>
Expand Down Expand Up @@ -57,6 +58,7 @@ public class OpenAIAuthenticationConfig
/// <summary>
/// Represents the type of authentication for an OpenAI plugin.
/// </summary>
[Obsolete("This enum is deprecated and will be removed in a future version.")]
public enum OpenAIAuthenticationType
{
/// <summary>
Expand All @@ -83,6 +85,7 @@ public enum OpenAIAuthenticationType
/// <summary>
/// Represents the type of authorization for an OpenAI plugin.
/// </summary>
[Obsolete("This enum is deprecated and will be removed in a future version.")]
public enum OpenAIAuthorizationType
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.SemanticKernel.Plugins.OpenApi;
/// <summary>
/// OpenAI function execution parameters
/// </summary>
[Obsolete("This class is deprecated and will be removed in a future version.")]
public class OpenAIFunctionExecutionParameters : OpenApiFunctionExecutionParameters
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

namespace SemanticKernel.Functions.UnitTests.OpenApi.OpenAI;

[Obsolete("OpenAI plugins are deprecated and will be removed in a future version.")]
public sealed class KernelOpenAIPluginExtensionsTests : IDisposable
{
/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions dotnet/src/IntegrationTests/IntegrationTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@
<Content Include="CrossLanguage\Data\SimplePromptTest.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Plugins\instacart-ai-plugin.json">
<Content Include="Plugins\OpenApi\instacart-service.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Plugins\repair-service.json">
<Content Include="Plugins\OpenApi\repair-service.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,10 @@
using Microsoft.SemanticKernel.Plugins.OpenApi;
using Xunit;

namespace SemanticKernel.IntegrationTests.Plugins;
namespace SemanticKernel.IntegrationTests.Plugins.OpenApi;

public class PluginTests
{
[Theory]
[InlineData("https://www.klarna.com/.well-known/ai-plugin.json", "Klarna", "productsUsingGET", "Laptop", 3, 200, "US")]
public async Task QueryKlarnaOpenAIPluginAsync(
string pluginEndpoint,
string name,
string functionName,
string query,
int size,
int budget,
string countryCode)
{
// Arrange
var kernel = new Kernel();
using HttpClient httpClient = new();

var plugin = await kernel.ImportPluginFromOpenAIAsync(
name,
new Uri(pluginEndpoint),
new OpenAIFunctionExecutionParameters(httpClient));

var arguments = new KernelArguments
{
["q"] = query,
["size"] = size,
["max_price"] = budget,
["countryCode"] = countryCode
};

// Act
await plugin[functionName].InvokeAsync(kernel, arguments);
}

[Theory]
[InlineData("https://www.klarna.com/us/shopping/public/openai/v0/api-docs/", "Klarna", "productsUsingGET", "Laptop", 3, 200, "US")]
public async Task QueryKlarnaOpenApiPluginAsync(
string pluginEndpoint,
string name,
string functionName,
string query,
int size,
int budget,
string countryCode)
{
// Arrange
var kernel = new Kernel();
using HttpClient httpClient = new();

var plugin = await kernel.ImportPluginFromOpenApiAsync(
name,
new Uri(pluginEndpoint),
new OpenApiFunctionExecutionParameters(httpClient));

var arguments = new KernelArguments
{
["q"] = query,
["size"] = size.ToString(System.Globalization.CultureInfo.InvariantCulture),
["max_price"] = budget,
["countryCode"] = countryCode
};

// Act
await plugin[functionName].InvokeAsync(kernel, arguments);
}

[Theory]
[InlineData("https://www.klarna.com/us/shopping/public/openai/v0/api-docs/", "Klarna", "productsUsingGET", "Laptop", 3, 200, "US")]
public async Task QueryKlarnaOpenApiPluginRunAsync(
Expand All @@ -99,7 +35,7 @@ public async Task QueryKlarnaOpenApiPluginRunAsync(
{
["q"] = query,
["size"] = size,
["budget"] = budget.ToString(System.Globalization.CultureInfo.InvariantCulture),
["max_price"] = budget.ToString(System.Globalization.CultureInfo.InvariantCulture),
["countryCode"] = countryCode
};

Expand All @@ -114,38 +50,7 @@ public async Task QueryKlarnaOpenApiPluginRunAsync(
}

[Theory]
[InlineData("https://raw.githubusercontent.com/sisbell/chatgpt-plugin-store/main/manifests/instacart.com.json",
"Instacart",
"create",
"""{"title":"Shopping List", "ingredients": ["Flour"], "question": "what ingredients do I need to make chocolate cookies?", "partner_name": "OpenAI" }"""
)]
public async Task QueryInstacartPluginAsync(
string pluginEndpoint,
string name,
string functionName,
string payload)
{
// Arrange
var kernel = new Kernel();
using HttpClient httpClient = new();

//note that this plugin is not compliant according to the underlying validator in SK
var plugin = await kernel.ImportPluginFromOpenAIAsync(
name,
new Uri(pluginEndpoint),
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });

var arguments = new KernelArguments
{
["payload"] = payload
};

// Act
await plugin[functionName].InvokeAsync(kernel, arguments);
}

[Theory]
[InlineData("Plugins/instacart-ai-plugin.json",
[InlineData("Plugins/OpenApi/instacart-service.yaml",
"Instacart",
"create",
"""{"title":"Shopping List", "ingredients": ["Flour"], "question": "what ingredients do I need to make chocolate cookies?", "partner_name": "OpenAI" }"""
Expand All @@ -162,10 +67,10 @@ public async Task QueryInstacartPluginFromStreamAsync(
var kernel = new Kernel();

// note that this plugin is not compliant according to the underlying validator in SK
var plugin = await kernel.ImportPluginFromOpenAIAsync(
var plugin = await kernel.ImportPluginFromOpenApiAsync(
name,
stream,
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });
new OpenApiFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });

var arguments = new KernelArguments
{
Expand All @@ -177,7 +82,7 @@ public async Task QueryInstacartPluginFromStreamAsync(
}

[Theory]
[InlineData("Plugins/instacart-ai-plugin.json",
[InlineData("Plugins/OpenApi/instacart-service.yaml",
"Instacart",
"create",
"""{"title":"Shopping List", "ingredients": ["Flour"], "question": "what ingredients do I need to make chocolate cookies?", "partner_name": "OpenAI" }"""
Expand All @@ -193,10 +98,10 @@ public async Task QueryInstacartPluginUsingRelativeFilePathAsync(
using HttpClient httpClient = new();

// note that this plugin is not compliant according to the underlying validator in SK
var plugin = await kernel.ImportPluginFromOpenAIAsync(
var plugin = await kernel.ImportPluginFromOpenApiAsync(
name,
pluginFilePath,
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });
new OpenApiFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });

var arguments = new KernelArguments
{
Expand All @@ -208,7 +113,7 @@ public async Task QueryInstacartPluginUsingRelativeFilePathAsync(
}

[Theory]
[InlineData("Plugins/instacart-ai-plugin.json", "Instacart", "create")]
[InlineData("Plugins/OpenApi/instacart-service.yaml", "Instacart", "create")]
public async Task QueryInstacartPluginWithDynamicPayloadAsync(
string pluginFilePath,
string name,
Expand All @@ -220,10 +125,10 @@ public async Task QueryInstacartPluginWithDynamicPayloadAsync(
var kernel = new Kernel();

// note that this plugin is not compliant according to the underlying validator in SK
var plugin = await kernel.ImportPluginFromOpenAIAsync(
var plugin = await kernel.ImportPluginFromOpenApiAsync(
name,
stream,
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = true });
new OpenApiFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = true });

var arguments = new KernelArguments
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Microsoft.SemanticKernel.Plugins.OpenApi;
using Xunit;

namespace SemanticKernel.IntegrationTests.Plugins;
namespace SemanticKernel.IntegrationTests.Plugins.OpenApi;

public class RepairServiceTests
{
Expand All @@ -23,7 +23,7 @@ public async Task ValidateInvokingRepairServicePluginAsync()
var plugin = await kernel.ImportPluginFromOpenApiAsync(
"RepairService",
stream,
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });
new OpenApiFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });

var arguments = new KernelArguments
{
Expand Down Expand Up @@ -79,7 +79,7 @@ public async Task HttpOperationExceptionIncludeRequestInfoAsync()
var plugin = await kernel.ImportPluginFromOpenApiAsync(
"RepairService",
stream,
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });
new OpenApiFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });

var arguments = new KernelArguments
{
Expand Down Expand Up @@ -121,7 +121,7 @@ public async Task UseDelegatingHandlerAsync()
var plugin = await kernel.ImportPluginFromOpenApiAsync(
"RepairService",
stream,
new OpenAIFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });
new OpenApiFunctionExecutionParameters(httpClient) { IgnoreNonCompliantErrors = true, EnableDynamicPayload = false });

// List All Repairs
var result = await plugin["listRepairs"].InvokeAsync(kernel);
Expand Down
Loading

0 comments on commit 616d6a9

Please sign in to comment.