Files
semantic-kernel/dotnet/samples/KernelSyntaxExamples/Example83_ApiManifest.cs
T
Mark Wallace 0a60d9cddc .Net: Fix kernel syntax sample numbering (#5031)
### Motivation and Context

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

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

- [ ] The code builds clean without any errors or warnings
- [ ] 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
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄
2024-02-15 13:57:15 +00:00

127 lines
5.3 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Plugins.MsGraph.Connectors.CredentialManagers;
using Microsoft.SemanticKernel.Plugins.OpenApi;
using Microsoft.SemanticKernel.Plugins.OpenApi.Extensions;
using Xunit;
using Xunit.Abstractions;
namespace Examples;
// This example shows how to use the ApiManifest based plugins
public class Example83_ApiManifest : BaseTest
{
public Example83_ApiManifest(ITestOutputHelper output) : base(output)
{
}
public static readonly IEnumerable<object[]> s_parameters = new List<object[]>
{
// function names are sanitized operationIds from the OpenAPI document
new object[] { "MessagesPlugin", "meListMessages", new KernelArguments { { "_top", "1" } }, "MessagesPlugin" },
};
[Theory, MemberData(nameof(s_parameters))]
public async Task RunSampleWithPlannerAsync(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad)
{
WriteSampleHeadingToConsole(pluginToTest, functionToTest, arguments, pluginsToLoad);
var kernel = Kernel.CreateBuilder().Build();
await AddApiManifestPluginsAsync(kernel, pluginsToLoad);
var result = await kernel.InvokeAsync(pluginToTest, functionToTest, arguments);
this.WriteLine("--------------------");
this.WriteLine($"\nResult:\n{result}\n");
this.WriteLine("--------------------");
}
private void WriteSampleHeadingToConsole(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad)
{
this.WriteLine();
this.WriteLine("======== [ApiManifest Plugins Sample] ========");
this.WriteLine($"======== Loading Plugins: {string.Join(" ", pluginsToLoad)} ========");
this.WriteLine($"======== Calling Plugin Function: {pluginToTest}.{functionToTest} with parameters {arguments?.Select(x => x.Key + " = " + x.Value).Aggregate((x, y) => x + ", " + y)} ========");
this.WriteLine();
}
private async Task AddApiManifestPluginsAsync(Kernel kernel, params string[] pluginNames)
{
#pragma warning disable SKEXP0053
if (TestConfiguration.MSGraph.Scopes == null)
{
throw new InvalidOperationException("Missing Scopes configuration for Microsoft Graph API.");
}
LocalUserMSALCredentialManager credentialManager = await LocalUserMSALCredentialManager.CreateAsync().ConfigureAwait(false);
var token = await credentialManager.GetTokenAsync(
TestConfiguration.MSGraph.ClientId,
TestConfiguration.MSGraph.TenantId,
TestConfiguration.MSGraph.Scopes.ToArray(),
TestConfiguration.MSGraph.RedirectUri).ConfigureAwait(false);
#pragma warning restore SKEXP0053
BearerAuthenticationProviderWithCancellationToken authenticationProvider = new(() => Task.FromResult(token));
foreach (var pluginName in pluginNames)
{
try
{
#pragma warning disable SKEXP0042
#pragma warning disable SKEXP0043
KernelPlugin plugin =
await kernel.ImportPluginFromApiManifestAsync(
pluginName,
$"Plugins/ApiManifestPlugins/{pluginName}/apimanifest.json",
new OpenApiFunctionExecutionParameters(authCallback: authenticationProvider.AuthenticateRequestAsync
, serverUrlOverride: new Uri("https://graph.microsoft.com/v1.0")))
.ConfigureAwait(false);
this.WriteLine($">> {pluginName} is created.");
#pragma warning restore SKEXP0042
#pragma warning restore SKEXP0043
}
catch (Exception ex)
{
kernel.LoggerFactory.CreateLogger("Plugin Creation").LogError(ex, "Plugin creation failed. Message: {0}", ex.Message);
throw new AggregateException($"Plugin creation failed for {pluginName}", ex);
}
}
}
}
/// <summary>
/// Retrieves a token via the provided delegate and applies it to HTTP requests using the
/// "bearer" authentication scheme.
/// </summary>
public class BearerAuthenticationProviderWithCancellationToken
{
private readonly Func<Task<string>> _bearerToken;
/// <summary>
/// Creates an instance of the <see cref="BearerAuthenticationProviderWithCancellationToken"/> class.
/// </summary>
/// <param name="bearerToken">Delegate to retrieve the bearer token.</param>
public BearerAuthenticationProviderWithCancellationToken(Func<Task<string>> bearerToken)
{
this._bearerToken = bearerToken;
}
/// <summary>
/// Applies the token to the provided HTTP request message.
/// </summary>
/// <param name="request">The HTTP request message.</param>
/// <param name="cancellationToken"></param>
public async Task AuthenticateRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken = default)
{
var token = await this._bearerToken().ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
}