Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net: Feat: adds support for Copilot Agent Plugins in dotnet and other fixes. #9436

Merged
merged 60 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
ee3312b
import implementation for TypeB
zengin May 1, 2024
8f9bd38
update the manifest package and address compiler warnings
zengin Jun 17, 2024
987c3bc
address compiler warnings
zengin Jun 18, 2024
b93e6ac
isolate runtimes in error handling
zengin Jun 18, 2024
b1320fe
Merge branch 'main' into chore/zengin-manifest
baywet Oct 22, 2024
177e126
chore: upgrades plugins library version
baywet Oct 22, 2024
99ac5cc
chore: updates api manifest dependency
baywet Oct 22, 2024
0a4fedd
Merge branch 'main' into chore/zengin-manifest
baywet Oct 22, 2024
f2ebca2
chore: formatting
baywet Oct 22, 2024
e33690a
chore: upgrades manifest lib to latest version
baywet Oct 22, 2024
6d462a8
Merge branch 'main' into chore/zengin-manifest
baywet Oct 24, 2024
a379579
ci: adds unit test infrastructure for microsoft manifest plugins
baywet Oct 24, 2024
c77eb72
ci: adds sample microsoft plugins
baywet Oct 24, 2024
20435c6
chore: adds kiota configuration for sample microsoft plugins
baywet Oct 24, 2024
8dd2906
fix: path to microsoft manifest plugin
baywet Oct 24, 2024
11d2391
fix: adds missing copy of microsoft manifests
baywet Oct 24, 2024
2c7cc8c
docs: adds link to microsoft manifest sample
baywet Oct 24, 2024
d47a812
fix: lookup path for the api and microsoft plugins
baywet Oct 24, 2024
c98cbcc
fix: loading of local microsoft manifest file
baywet Oct 24, 2024
529dc0d
fix: stream instead of string to load microsoft plugins
baywet Oct 24, 2024
d98ba29
fix: function name for microsoft plugins test data
baywet Oct 24, 2024
d435b51
fix: authentication for microsoft plugins
baywet Oct 25, 2024
65543ed
Merge branch 'main' into chore/zengin-manifest
baywet Oct 25, 2024
7fa549c
fix: restores wrongly deleted plugin in #6005
baywet Oct 25, 2024
814a45c
feat: adds astronomy plugin to kiota workspace configuration
baywet Oct 25, 2024
a6e9529
feat: adds astronomy plugin definition
baywet Oct 25, 2024
927723d
fix: nasa astronomy simple test
baywet Oct 25, 2024
882ed3b
feat: adds support for multiple microsoft plugins dependencies
baywet Oct 25, 2024
3e0c0c3
docs: adds experimental entry for Microsoft Manifests
baywet Oct 25, 2024
3471e31
fix: aligns experimental code with new numbering for api and microsof…
baywet Oct 25, 2024
2b7d722
chore: skip loading the json document ourselves
baywet Oct 25, 2024
b2c2ee4
fix: o(n) lookup to o(1) for operation ids to exclude
baywet Oct 25, 2024
0707600
fix: disposing response too early
baywet Oct 25, 2024
3b2c3c2
fix: multiple performance issues in API manifest loading
baywet Oct 25, 2024
5fdd657
fix: normalization operation id to avoid . in function names
baywet Oct 25, 2024
8871dcf
chore: linting
baywet Oct 25, 2024
93eb850
fix; netstandard2.0 build
baywet Oct 25, 2024
0fe5fa6
Merge branch 'main' into chore/zengin-manifest
baywet Oct 25, 2024
c8fa5fe
Merge branch 'main' into chore/zengin-manifest
baywet Nov 11, 2024
c554059
fix: wrong merge variable reference
baywet Nov 11, 2024
d571850
chore: post merge update of plugins manifest implementation
baywet Nov 11, 2024
a3650ba
fix: first wave of PR review comments
baywet Nov 11, 2024
43d044b
chore: fixes formatting
baywet Nov 11, 2024
f9d156a
Merge branch 'main' into chore/zengin-manifest
baywet Nov 13, 2024
79a9902
chore: moves kiota generation folder to a sub-directory
baywet Nov 13, 2024
907229b
chore: renames api and microsoft manifest tests
baywet Nov 13, 2024
0f991cc
chore: removes constructor for plugin parameters as per PR review gui…
baywet Nov 13, 2024
ff077f3
chore: updates namespace for api and microsoft manifest extensions
baywet Nov 13, 2024
cd6b2c6
chore: reverts formatting on csproj
baywet Nov 13, 2024
c50c22c
docs: adds doc comments to describe what tests do and how to run them
baywet Nov 13, 2024
5242e10
fix: local copy of nasa description since source is gone
baywet Nov 13, 2024
bfe2983
fix: disposal of response object
baywet Nov 13, 2024
5e4b31e
chore: fixes formatting
baywet Nov 13, 2024
f8b6501
Merge branch 'main' into chore/zengin-manifest
baywet Nov 13, 2024
ecbd60e
Merge branch 'main' into chore/zengin-manifest
baywet Nov 14, 2024
f6bcb2e
chore: replaces kiota workspace by generation instructions
baywet Nov 14, 2024
dd0112e
Merge branch 'main' into chore/zengin-manifest
baywet Nov 14, 2024
23474a3
chore: renames Microsoft Plugins to Copilot Agent Plugins
baywet Nov 14, 2024
bf3e1ec
fix: naming in doc comments
baywet Nov 14, 2024
635b595
Merge branch 'main' into chore/zengin-manifest
baywet Nov 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@
<PackageVersion Include="Microsoft.Graph" Version="[4.51.0, 5)" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="[2.28.0, )" />
<PackageVersion Include="Microsoft.OpenApi" Version="1.6.22" />
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="1.6.21" />
<PackageVersion Include="Microsoft.OpenApi.ApiManifest" Version="0.5.4-preview" />
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="1.6.22" />
<PackageVersion Include="Microsoft.OpenApi.ApiManifest" Version="0.5.5-preview" />
<PackageVersion Include="Microsoft.Plugins.Manifest" Version="1.0.0-preview3" />
<PackageVersion Include="Google.Apis.CustomSearchAPI.v1" Version="[1.60.0.3001, )" />
<PackageVersion Include="Grpc.Net.Client" Version="2.66.0" />
<PackageVersion Include="protobuf-net" Version="3.2.45" />
Expand Down
5 changes: 3 additions & 2 deletions dotnet/docs/EXPERIMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ You can use the following diagnostic IDs to ignore warnings or errors for a part
| SKEXP0040 | GRPC functions |
| SKEXP0040 | Markdown functions |
| SKEXP0040 | OpenAPI functions |
| SKEXP0040 | OpenAPI function extensions |
| SKEXP0040 | OpenAPI function extensions - API Manifest |
| SKEXP0040 | OpenAPI function extensions - Microsoft Manifest |
| SKEXP0040 | Prompty Format support |
| | | | | | | |
| SKEXP0050 | Core plugins |
Expand All @@ -86,4 +87,4 @@ You can use the following diagnostic IDs to ignore warnings or errors for a part
| | | | | | | |
| SKEXP0110 | Agent Framework |
| | | | | | | |
| SKEXP0120 | Native-AOT |
| SKEXP0120 | Native-AOT |
12 changes: 6 additions & 6 deletions dotnet/samples/Concepts/Concepts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@
</None>
</ItemGroup>
<ItemGroup>
<Content Include="Resources\Plugins\EventPlugin\openapiV1.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Resources\Plugins\EventPlugin\openapiV2.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="Resources\Plugins\MicrosoftManifestPlugins\**\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Resources\Plugins\MicrosoftManifestPlugins\**\*.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="Resources\Plugins\RepairServicePlugin\repair-service.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
Expand Down
61 changes: 51 additions & 10 deletions dotnet/samples/Concepts/Plugins/ApiManifestBasedPlugins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,69 @@

namespace Plugins;

// This example shows how to use the ApiManifest based plugins
/// <summary>
/// These examples demonstrate how to use API Manifest plugins to call Microsoft Graph and NASA APIs.
/// API Manifest plugins are created from the OpenAPI document and the manifest file.
/// The manifest file contains the API dependencies and their execution parameters.
/// The manifest file also contains the authentication information for the APIs, however this is not used by the extension method and MUST be setup separately at the moment, which the example demonstrates.
///
/// Important stages being demonstrated:
/// 1. Load APIManifest plugins
/// 2. Configure authentication for the APIs
/// 3. Call functions from the loaded plugins
///
/// Running this test requires the following configuration in `dotnet\samples\Concepts\bin\Debug\net8.0\appsettings.Development.json`:
///
/// ```json
/// {
/// "MSGraph": {
/// "ClientId": "clientId",
/// "TenantId": "tenantId",
/// "Scopes": [
/// "Calendars.Read",
/// "Contacts.Read",
/// "Files.Read.All",
/// "Mail.Read",
/// "User.Read"
/// ],
/// "RedirectUri": "http://localhost"
/// }
/// }
///```
///
/// Replace the clientId and TenantId by your own values.
///
/// To create the application registration:
/// 1. Go to https://aad.portal.azure.com
/// 2. Select create a new application registration
/// 3. Select new public client (add the redirect URI).
/// 4. Navigate to API access, add the listed Microsoft Graph delegated scopes.
/// 5. Grant consent after adding the scopes.
///
/// During the first run, your browser will open to get the token.
///
/// </summary>
/// <param name="output">The output helper to use to the test can emit status information</param>
public class ApiManifestBasedPlugins(ITestOutputHelper output) : BaseTest(output)
{
public static readonly IEnumerable<object[]> s_parameters =
[
// function names are sanitized operationIds from the OpenAPI document
["MessagesPlugin", "meListMessages", new KernelArguments { { "_top", "1" } }, "MessagesPlugin"],
["DriveItemPlugin", "driverootGetChildrenContent", new KernelArguments { { "driveItem-Id", "test.txt" } }, "DriveItemPlugin", "MessagesPlugin"],
["ContactsPlugin", "meListContacts", new KernelArguments() { { "_count", "true" } }, "ContactsPlugin", "MessagesPlugin"],
["CalendarPlugin", "mecalendarListEvents", new KernelArguments() { { "_top", "1" } }, "CalendarPlugin", "MessagesPlugin"],
["MessagesPlugin", "me_ListMessages", new KernelArguments { { "_top", "1" } }, "MessagesPlugin"],
["DriveItemPlugin", "drive_root_GetChildrenContent", new KernelArguments { { "driveItem-Id", "test.txt" } }, "DriveItemPlugin", "MessagesPlugin"],
["ContactsPlugin", "me_ListContacts", new KernelArguments() { { "_count", "true" } }, "ContactsPlugin", "MessagesPlugin"],
["CalendarPlugin", "me_calendar_ListEvents", new KernelArguments() { { "_top", "1" } }, "CalendarPlugin", "MessagesPlugin"],

#region Multiple API dependencies (multiple auth requirements) scenario within the same plugin
// Graph API uses MSAL
["AstronomyPlugin", "meListMessages", new KernelArguments { { "_top", "1" } }, "AstronomyPlugin"],
["AstronomyPlugin", "me_ListMessages", new KernelArguments { { "_top", "1" } }, "AstronomyPlugin"],
// Astronomy API uses API key authentication
["AstronomyPlugin", "apod", new KernelArguments { { "_date", "2022-02-02" } }, "AstronomyPlugin"],
#endregion
];

[Theory, MemberData(nameof(s_parameters))]
public async Task RunSampleWithPlannerAsync(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad)
public async Task RunApiManifestPluginAsync(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad)
{
WriteSampleHeadingToConsole(pluginToTest, functionToTest, arguments, pluginsToLoad);
var kernel = Kernel.CreateBuilder().Build();
Expand Down Expand Up @@ -70,7 +112,6 @@ private async Task AddApiManifestPluginsAsync(Kernel kernel, params string[] plu

BearerAuthenticationProviderWithCancellationToken authenticationProvider = new(() => Task.FromResult(token));
#pragma warning disable SKEXP0040
#pragma warning disable SKEXP0043

// Microsoft Graph API execution parameters
var graphOpenApiFunctionExecutionParameters = new OpenApiFunctionExecutionParameters(
Expand All @@ -94,6 +135,7 @@ private async Task AddApiManifestPluginsAsync(Kernel kernel, params string[] plu
{ "microsoft.graph", graphOpenApiFunctionExecutionParameters },
{ "nasa", nasaOpenApiFunctionExecutionParameters }
});
var manifestLookupDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "Resources", "Plugins", "ApiManifestPlugins");

foreach (var pluginName in pluginNames)
{
Expand All @@ -102,12 +144,11 @@ private async Task AddApiManifestPluginsAsync(Kernel kernel, params string[] plu
KernelPlugin plugin =
await kernel.ImportPluginFromApiManifestAsync(
pluginName,
$"Plugins/ApiManifestPlugins/{pluginName}/apimanifest.json",
Path.Combine(manifestLookupDirectory, pluginName, "apimanifest.json"),
apiManifestPluginParameters)
.ConfigureAwait(false);
Console.WriteLine($">> {pluginName} is created.");
#pragma warning restore SKEXP0040
#pragma warning restore SKEXP0043
}
catch (Exception ex)
{
Expand Down
157 changes: 157 additions & 0 deletions dotnet/samples/Concepts/Plugins/MicrosoftManifestBasedPlugins.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Web;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Plugins.MsGraph.Connectors.CredentialManagers;
using Microsoft.SemanticKernel.Plugins.OpenApi;
using Microsoft.SemanticKernel.Plugins.OpenApi.Extensions;

namespace Plugins;
/// <summary>
/// These examples demonstrate how to use MicrosoftManifest plugins to call Microsoft Graph and NASA APIs.
/// Microsoft Manifest plugins are created from the OpenAPI document and the manifest file.
/// The manifest file contains the API dependencies and their execution parameters.
/// The manifest file also contains the authentication information for the APIs, however this is not used by the extension method and MUST be setup separately at the moment, which the example demonstrates.
///
/// Important stages being demonstrated:
/// 1. Load MicrosoftManifest plugins
/// 2. Configure authentication for the APIs
/// 3. Call functions from the loaded plugins
///
/// Running this test requires the following configuration in `dotnet\samples\Concepts\bin\Debug\net8.0\appsettings.Development.json`:
///
/// ```json
/// {
/// "MSGraph": {
/// "ClientId": "clientId",
/// "TenantId": "tenantId",
/// "Scopes": [
/// "Calendars.Read",
/// "Contacts.Read",
/// "Files.Read.All",
/// "Mail.Read",
/// "User.Read"
/// ],
/// "RedirectUri": "http://localhost"
/// }
/// }
///```
///
/// Replace the clientId and TenantId by your own values.
///
/// To create the application registration:
/// 1. Go to https://aad.portal.azure.com
/// 2. Select create a new application registration
/// 3. Select new public client (add the redirect URI).
/// 4. Navigate to API access, add the listed Microsoft Graph delegated scopes.
/// 5. Grant consent after adding the scopes.
///
/// During the first run, your browser will open to get the token.
///
/// </summary>
/// <param name="output">The output helper to use to the test can emit status information</param>
public class MicrosoftManifestBasedPlugins(ITestOutputHelper output) : BaseTest(output)
SergeyMenshykh marked this conversation as resolved.
Show resolved Hide resolved
{
public static readonly IEnumerable<object[]> s_parameters =
[
// function names are sanitized operationIds from the OpenAPI document
["MessagesPlugin", "me_ListMessages", new KernelArguments { { "_top", "1" } }, "MessagesPlugin"],
["DriveItemPlugin", "drive_root_GetChildrenContent", new KernelArguments { { "driveItem-Id", "test.txt" } }, "DriveItemPlugin", "MessagesPlugin"],
["ContactsPlugin", "me_ListContacts", new KernelArguments() { { "_count", "true" } }, "ContactsPlugin", "MessagesPlugin"],
["CalendarPlugin", "me_calendar_ListEvents", new KernelArguments() { { "_top", "1" } }, "CalendarPlugin", "MessagesPlugin"],

// Multiple API dependencies (multiple auth requirements) scenario within the same plugin
// Graph API uses MSAL
["AstronomyPlugin", "me_ListMessages", new KernelArguments { { "_top", "1" } }, "AstronomyPlugin"],
// Astronomy API uses API key authentication
["AstronomyPlugin", "apod", new KernelArguments { { "_date", "2022-02-02" } }, "AstronomyPlugin"],
];
[Theory, MemberData(nameof(s_parameters))]
public async Task RunMicrosoftManifestPluginAsync(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad)
{
WriteSampleHeadingToConsole(pluginToTest, functionToTest, arguments, pluginsToLoad);
var kernel = new Kernel();
await AddMicrosoftManifestPluginsAsync(kernel, pluginsToLoad);

var result = await kernel.InvokeAsync(pluginToTest, functionToTest, arguments);
Console.WriteLine("--------------------");
Console.WriteLine($"\nResult:\n{result}\n");
Console.WriteLine("--------------------");
}

private void WriteSampleHeadingToConsole(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad)
baywet marked this conversation as resolved.
Show resolved Hide resolved
{
Console.WriteLine();
Console.WriteLine("======== [MicrosoftManifest Plugins Sample] ========");
Console.WriteLine($"======== Loading Plugins: {string.Join(" ", pluginsToLoad)} ========");
Console.WriteLine($"======== Calling Plugin Function: {pluginToTest}.{functionToTest} with parameters {arguments?.Select(x => x.Key + " = " + x.Value).Aggregate((x, y) => x + ", " + y)} ========");
Console.WriteLine();
}
private async Task AddMicrosoftManifestPluginsAsync(Kernel kernel, params string[] pluginNames)
{
#pragma warning disable SKEXP0050
if (TestConfiguration.MSGraph.Scopes is 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 SKEXP0050

BearerAuthenticationProviderWithCancellationToken authenticationProvider = new(() => Task.FromResult(token));
#pragma warning disable SKEXP0040

// Microsoft Graph API execution parameters
var graphOpenApiFunctionExecutionParameters = new OpenApiFunctionExecutionParameters(
authCallback: authenticationProvider.AuthenticateRequestAsync,
serverUrlOverride: new Uri("https://graph.microsoft.com/v1.0"));

// NASA API execution parameters
var nasaOpenApiFunctionExecutionParameters = new OpenApiFunctionExecutionParameters(
authCallback: async (request, cancellationToken) =>
{
var uriBuilder = new UriBuilder(request.RequestUri ?? throw new InvalidOperationException("The request URI is null."));
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query["api_key"] = "DEMO_KEY";
uriBuilder.Query = query.ToString();
request.RequestUri = uriBuilder.Uri;
});

var apiManifestPluginParameters = new MicrosoftManifestPluginParameters
{
FunctionExecutionParameters = new()
{
{ "https://graph.microsoft.com/v1.0", graphOpenApiFunctionExecutionParameters },
{ "https://api.nasa.gov/planetary", nasaOpenApiFunctionExecutionParameters }
}
};
var manifestLookupDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "Resources", "Plugins", "MicrosoftManifestPlugins");

foreach (var pluginName in pluginNames)
{
try
{
#pragma warning disable CA1308 // Normalize strings to uppercase
await kernel.ImportPluginFromMicrosoftManifestAsync(
pluginName,
Path.Combine(manifestLookupDirectory, pluginName, $"{pluginName[..^6].ToLowerInvariant()}-apiplugin.json"),
apiManifestPluginParameters)
.ConfigureAwait(false);
#pragma warning restore CA1308 // Normalize strings to uppercase
Console.WriteLine($">> {pluginName} is created.");
#pragma warning restore SKEXP0040
}
catch (Exception ex)
{
Console.WriteLine("Plugin creation failed. Message: {0}", ex.Message);
throw new AggregateException($"Plugin creation failed for {pluginName}", ex);
}
}
}
}
1 change: 1 addition & 0 deletions dotnet/samples/Concepts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ dotnet test -l "console;verbosity=detailed" --filter "FullyQualifiedName=ChatCom
- [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)
- [TransformPlugin](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/TransformPlugin.cs)
- [MicrosoftManifestBasedPlugins](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/MicrosoftManifestBasedPlugins.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
Loading
Loading