diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index 05a06f7c9901..c0993a9e8cd0 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -96,8 +96,9 @@ - - + + + diff --git a/dotnet/docs/EXPERIMENTS.md b/dotnet/docs/EXPERIMENTS.md index f03f831e5847..99fd9b56afb4 100644 --- a/dotnet/docs/EXPERIMENTS.md +++ b/dotnet/docs/EXPERIMENTS.md @@ -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 - Copilot Agent Plugin | | SKEXP0040 | Prompty Format support | | | | | | | | | | SKEXP0050 | Core plugins | @@ -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 | \ No newline at end of file +| SKEXP0120 | Native-AOT | diff --git a/dotnet/samples/Concepts/Concepts.csproj b/dotnet/samples/Concepts/Concepts.csproj index 941b3fa68c6e..01e4d56099f9 100644 --- a/dotnet/samples/Concepts/Concepts.csproj +++ b/dotnet/samples/Concepts/Concepts.csproj @@ -106,12 +106,12 @@ - - Always - - - Always - + + PreserveNewest + + + PreserveNewest + Always diff --git a/dotnet/samples/Concepts/Plugins/ApiManifestBasedPlugins.cs b/dotnet/samples/Concepts/Plugins/ApiManifestBasedPlugins.cs index 180cab3f68e6..e7788345f535 100644 --- a/dotnet/samples/Concepts/Plugins/ApiManifestBasedPlugins.cs +++ b/dotnet/samples/Concepts/Plugins/ApiManifestBasedPlugins.cs @@ -10,27 +10,69 @@ namespace Plugins; -// This example shows how to use the ApiManifest based plugins +/// +/// 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. +/// +/// +/// The output helper to use to the test can emit status information public class ApiManifestBasedPlugins(ITestOutputHelper output) : BaseTest(output) { public static readonly IEnumerable 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(); @@ -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( @@ -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) { @@ -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) { diff --git a/dotnet/samples/Concepts/Plugins/CopilotAgentBasedPlugins.cs b/dotnet/samples/Concepts/Plugins/CopilotAgentBasedPlugins.cs new file mode 100644 index 000000000000..f025902e2701 --- /dev/null +++ b/dotnet/samples/Concepts/Plugins/CopilotAgentBasedPlugins.cs @@ -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; +/// +/// These examples demonstrate how to use Copilot Agent plugins to call Microsoft Graph and NASA APIs. +/// Copilot Agent 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 Copilot Agent 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. +/// +/// +/// The output helper to use to the test can emit status information +public class CopilotAgentBasedPlugins(ITestOutputHelper output) : BaseTest(output) +{ + public static readonly IEnumerable 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 RunCopilotAgentPluginAsync(string pluginToTest, string functionToTest, KernelArguments? arguments, params string[] pluginsToLoad) + { + WriteSampleHeadingToConsole(pluginToTest, functionToTest, arguments, pluginsToLoad); + var kernel = new Kernel(); + await AddCopilotAgentPluginsAsync(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) + { + Console.WriteLine(); + Console.WriteLine("======== [CopilotAgent 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 AddCopilotAgentPluginsAsync(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 CopilotAgentPluginParameters + { + FunctionExecutionParameters = new() + { + { "https://graph.microsoft.com/v1.0", graphOpenApiFunctionExecutionParameters }, + { "https://api.nasa.gov/planetary", nasaOpenApiFunctionExecutionParameters } + } + }; + var manifestLookupDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "Resources", "Plugins", "CopilotAgentPlugins"); + + foreach (var pluginName in pluginNames) + { + try + { +#pragma warning disable CA1308 // Normalize strings to uppercase + await kernel.ImportPluginFromCopilotAgentPluginAsync( + 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); + } + } + } +} diff --git a/dotnet/samples/Concepts/README.md b/dotnet/samples/Concepts/README.md index 7e5a36927021..374b11358f14 100644 --- a/dotnet/samples/Concepts/README.md +++ b/dotnet/samples/Concepts/README.md @@ -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) +- [CopilotAgentBasedPlugins](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Plugins/CopilotAgentBasedPlugins.cs) ### PromptTemplates - Using [`Templates`](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel.Abstractions/PromptTemplate/IPromptTemplate.cs) with parametrization for `Prompt` rendering diff --git a/dotnet/samples/Concepts/Resources/Plugins/ApiManifestPlugins/AstronomyPlugin/apimanifest.json b/dotnet/samples/Concepts/Resources/Plugins/ApiManifestPlugins/AstronomyPlugin/apimanifest.json new file mode 100644 index 000000000000..2739318f701d --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/ApiManifestPlugins/AstronomyPlugin/apimanifest.json @@ -0,0 +1,38 @@ +{ + "applicationName": "Astronomy Plugin", + "description": "This plugin accesses Nasa API to get Astronomy Picture of the Day and Microsoft Graph to get email messages from the user's mailbox.", + "publisher": { + "name": "publisher-name", + "contactEmail": "publisher-email@example.com" + }, + "apiDependencies": { + "microsoft.graph": { + "apiDescriptionUrl": "https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/openapi/v1.0/graphexplorer.yaml", + "requests": [ + { + "method": "Get", + "uriTemplate": "/me/messages" + } + ] + }, + "nasa": { + "apiDescriptionUrl": "https://raw.githubusercontent.com/zengin/openapi-directory/zengin/nasa/APIs/nasa.gov/apod/1.0.0/openapi.yaml", + "authorizationRequirements": { + "clientIdentifier": "some-uuid-here", + "access": [ + { + "type": "api_key", + "content": { + } + } + ] + }, + "requests": [ + { + "method": "Get", + "uriTemplate": "/apod" + } + ] + } + } +} \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/astronomy-apiplugin.json b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/astronomy-apiplugin.json new file mode 100644 index 000000000000..1d4eb5049091 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/astronomy-apiplugin.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.1/schema.json", + "schema_version": "v2.1", + "name_for_human": "APOD", + "description_for_human": "This endpoint structures the APOD imagery and associated metadata so that it can be repurposed for other applications. In addition, if the concept_tags parameter is set to True, then keywords derived from the image explanation are returned. These keywords could be used as auto-generated hashtags for twitter or instagram feeds; but generally help with discoverability of relevant imagery", + "description_for_model": "This endpoint structures the APOD imagery and associated metadata so that it can be repurposed for other applications. In addition, if the concept_tags parameter is set to True, then keywords derived from the image explanation are returned. These keywords could be used as auto-generated hashtags for twitter or instagram feeds; but generally help with discoverability of relevant imagery", + "contact_email": "evan.t.yates@nasa.gov", + "namespace": "Astronomy", + "capabilities": { + "conversation_starters": [ + { + "text": "Returns images" + } + ] + }, + "functions": [ + { + "name": "apod", + "description": "Returns the picture of the day" + }, + { + "name": "me_ListMessages", + "description": "Get an open extension (openTypeExtension object) identified by name or fully qualified name. The table in the Permissions section lists the resources that support open extensions. The following table lists the three scenarios where you can get an open extension from a supported resource instance." + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "ApiKeyPluginVault", + "reference_id": "{api_key_REGISTRATION_ID}" + }, + "spec": { + "url": "astronomy-openapi.yml" + }, + "run_for_functions": ["apod"] + }, + { + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "messages-openapi.yml" + }, + "run_for_functions": ["me_ListMessages"] + } + ] +} diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/astronomy-openapi.yml b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/astronomy-openapi.yml new file mode 100644 index 000000000000..3781f5a999f4 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/astronomy-openapi.yml @@ -0,0 +1,54 @@ +openapi: 3.0.1 +info: + title: APOD - Subset + description: 'This endpoint structures the APOD imagery and associated metadata so that it can be repurposed for other applications. In addition, if the concept_tags parameter is set to True, then keywords derived from the image explanation are returned. These keywords could be used as auto-generated hashtags for twitter or instagram feeds; but generally help with discoverability of relevant imagery' + contact: + email: evan.t.yates@nasa.gov + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +servers: + - url: https://api.nasa.gov/planetary + - url: http://api.nasa.gov/planetary +paths: + /apod: + get: + tags: + - request tag + summary: Returns images + description: Returns the picture of the day + operationId: apod + parameters: + - name: date + in: query + description: The date of the APOD image to retrieve + style: form + explode: false + schema: + type: string + - name: hd + in: query + description: Retrieve the URL for the high resolution image + style: form + explode: false + schema: + type: boolean + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: { } + '400': + description: 'Date must be between Jun 16, 1995 and Mar 28, 2019.' + security: + - api_key: [ ] +components: + securitySchemes: + api_key: + type: apiKey + name: api_key + in: query \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/messages-openapi.yml b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/messages-openapi.yml new file mode 100644 index 000000000000..f9c7b11e712b --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/AstronomyPlugin/messages-openapi.yml @@ -0,0 +1,678 @@ +openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph - Subset + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: v1.0 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /me/messages: + get: + tags: + - me.message + summary: Get open extension + description: Get an open extension (openTypeExtension object) identified by name or fully qualified name. The table in the Permissions section lists the resources that support open extensions. The following table lists the three scenarios where you can get an open extension from a supported resource instance. + externalDocs: + description: Find more info here + url: https://learn.microsoft.com/graph/api/opentypeextension-get?view=graph-rest-1.0 + operationId: me_ListMessages + parameters: + - name: includeHiddenMessages + in: query + description: Include Hidden Messages + style: form + explode: false + schema: + type: string + - $ref: '#/components/parameters/top' + - $ref: '#/components/parameters/skip' + - $ref: '#/components/parameters/search' + - $ref: '#/components/parameters/filter' + - $ref: '#/components/parameters/count' + - name: $orderby + in: query + description: Order items by property values + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - id desc + - categories + - categories desc + - changeKey + - changeKey desc + - createdDateTime + - createdDateTime desc + - lastModifiedDateTime + - lastModifiedDateTime desc + - bccRecipients + - bccRecipients desc + - body + - body desc + - bodyPreview + - bodyPreview desc + - ccRecipients + - ccRecipients desc + - conversationId + - conversationId desc + - conversationIndex + - conversationIndex desc + - flag + - flag desc + - from + - from desc + - hasAttachments + - hasAttachments desc + - importance + - importance desc + - inferenceClassification + - inferenceClassification desc + - internetMessageHeaders + - internetMessageHeaders desc + - internetMessageId + - internetMessageId desc + - isDeliveryReceiptRequested + - isDeliveryReceiptRequested desc + - isDraft + - isDraft desc + - isRead + - isRead desc + - isReadReceiptRequested + - isReadReceiptRequested desc + - parentFolderId + - parentFolderId desc + - receivedDateTime + - receivedDateTime desc + - replyTo + - replyTo desc + - sender + - sender desc + - sentDateTime + - sentDateTime desc + - subject + - subject desc + - toRecipients + - toRecipients desc + - uniqueBody + - uniqueBody desc + - webLink + - webLink desc + type: string + - name: $select + in: query + description: Select properties to be returned + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - categories + - changeKey + - createdDateTime + - lastModifiedDateTime + - bccRecipients + - body + - bodyPreview + - ccRecipients + - conversationId + - conversationIndex + - flag + - from + - hasAttachments + - importance + - inferenceClassification + - internetMessageHeaders + - internetMessageId + - isDeliveryReceiptRequested + - isDraft + - isRead + - isReadReceiptRequested + - parentFolderId + - receivedDateTime + - replyTo + - sender + - sentDateTime + - subject + - toRecipients + - uniqueBody + - webLink + - attachments + - extensions + - multiValueExtendedProperties + - singleValueExtendedProperties + type: string + - name: $expand + in: query + description: Expand related entities + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - '*' + - attachments + - extensions + - multiValueExtendedProperties + - singleValueExtendedProperties + type: string + responses: + '200': + $ref: '#/components/responses/microsoft.graph.messageCollectionResponse' + default: + $ref: '#/components/responses/error' + x-ms-pageable: + nextLinkName: '@odata.nextLink' + operationName: listMore + itemName: value + post: + tags: + - me.message + summary: Create open extension + description: 'Create an open extension (openTypeExtension object) and add custom properties in a new or existing instance of a resource. You can create an open extension in a resource instance and store custom data to it all in the same operation, except for specific resources. The table in the Permissions section lists the resources that support open extensions.' + externalDocs: + description: Find more info here + url: https://learn.microsoft.com/graph/api/opentypeextension-post-opentypeextension?view=graph-rest-1.0 + operationId: me_CreateMessages + requestBody: + description: New navigation property + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.outlookItem' + required: true + responses: + '201': + description: Created navigation property. + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.message' + default: + $ref: '#/components/responses/error' +components: + schemas: + microsoft.graph.message: + allOf: + - $ref: '#/components/schemas/microsoft.graph.outlookItem' + - title: message + type: object + properties: + bccRecipients: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: 'The Bcc: recipients for the message.' + body: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.itemBody' + - type: object + nullable: true + description: The body of the message. It can be in HTML or text format. Find out about safe HTML in a message body. + bodyPreview: + type: string + description: The first 255 characters of the message body. It is in text format. + nullable: true + ccRecipients: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: 'The Cc: recipients for the message.' + conversationId: + type: string + description: The ID of the conversation the email belongs to. + nullable: true + conversationIndex: + type: string + description: Indicates the position of the message within the conversation. + format: base64url + nullable: true + flag: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.followupFlag' + - type: object + nullable: true + description: 'The flag value that indicates the status, start date, due date, or completion date for the message.' + from: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recipient' + - type: object + nullable: true + description: 'The owner of the mailbox from which the message is sent. In most cases, this value is the same as the sender property, except for sharing or delegation scenarios. The value must correspond to the actual mailbox used. Find out more about setting the from and sender properties of a message.' + hasAttachments: + type: boolean + description: 'Indicates whether the message has attachments. This property doesn''t include inline attachments, so if a message contains only inline attachments, this property is false. To verify the existence of inline attachments, parse the body property to look for a src attribute, such as .' + nullable: true + importance: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.importance' + - type: object + nullable: true + description: 'The importance of the message. The possible values are: low, normal, and high.' + inferenceClassification: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.inferenceClassificationType' + - type: object + nullable: true + description: 'The classification of the message for the user, based on inferred relevance or importance, or on an explicit override. The possible values are: focused or other.' + internetMessageHeaders: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.internetMessageHeader' + description: A collection of message headers defined by RFC5322. The set includes message headers indicating the network path taken by a message from the sender to the recipient. It can also contain custom message headers that hold app data for the message. Returned only on applying a $select query option. Read-only. + internetMessageId: + type: string + description: The message ID in the format specified by RFC2822. + nullable: true + isDeliveryReceiptRequested: + type: boolean + description: Indicates whether a read receipt is requested for the message. + nullable: true + isDraft: + type: boolean + description: Indicates whether the message is a draft. A message is a draft if it hasn't been sent yet. + nullable: true + isRead: + type: boolean + description: Indicates whether the message has been read. + nullable: true + isReadReceiptRequested: + type: boolean + description: Indicates whether a read receipt is requested for the message. + nullable: true + parentFolderId: + type: string + description: The unique identifier for the message's parent mailFolder. + nullable: true + receivedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The date and time the message was received. The date and time information uses ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z.' + format: date-time + nullable: true + replyTo: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: The email addresses to use when replying. + sender: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recipient' + - type: object + nullable: true + description: 'The account that is actually used to generate the message. In most cases, this value is the same as the from property. You can set this property to a different value when sending a message from a shared mailbox, for a shared calendar, or as a delegate. In any case, the value must correspond to the actual mailbox used. Find out more about setting the from and sender properties of a message.' + sentDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The date and time the message was sent. The date and time information uses ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z.' + format: date-time + nullable: true + subject: + type: string + description: The subject of the message. + nullable: true + toRecipients: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: 'The To: recipients for the message.' + uniqueBody: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.itemBody' + - type: object + nullable: true + description: The part of the body of the message that is unique to the current message. uniqueBody is not returned by default but can be retrieved for a given message by use of the ?$select=uniqueBody query. It can be in HTML or text format. + webLink: + type: string + description: 'The URL to open the message in Outlook on the web.You can append an ispopout argument to the end of the URL to change how the message is displayed. If ispopout is not present or if it is set to 1, then the message is shown in a popout window. If ispopout is set to 0, the browser shows the message in the Outlook on the web review pane.The message opens in the browser if you are signed in to your mailbox via Outlook on the web. You are prompted to sign in if you are not already signed in with the browser.This URL cannot be accessed from within an iFrame.' + nullable: true + attachments: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.attachment' + description: The fileAttachment and itemAttachment attachments for the message. + extensions: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.extension' + description: The collection of open extensions defined for the message. Nullable. + multiValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.multiValueLegacyExtendedProperty' + description: The collection of multi-value extended properties defined for the message. Nullable. + singleValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.singleValueLegacyExtendedProperty' + description: The collection of single-value extended properties defined for the message. Nullable. + microsoft.graph.outlookItem: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: outlookItem + type: object + properties: + categories: + type: array + items: + type: string + nullable: true + description: The categories associated with the item + changeKey: + type: string + description: 'Identifies the version of the item. Every time the item is changed, changeKey changes as well. This allows Exchange to apply changes to the correct version of the object. Read-only.' + nullable: true + createdDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + microsoft.graph.recipient: + title: recipient + type: object + properties: + emailAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.emailAddress' + - type: object + nullable: true + description: The recipient's email address. + microsoft.graph.itemBody: + title: itemBody + type: object + properties: + content: + type: string + description: The content of the item. + nullable: true + contentType: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.bodyType' + - type: object + nullable: true + description: The type of the content. Possible values are text and html. + microsoft.graph.followupFlag: + title: followupFlag + type: object + properties: + completedDateTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: The date and time that the follow-up was finished. + dueDateTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: 'The date and time that the follow-up is to be finished. Note: To set the due date, you must also specify the startDateTime; otherwise, you get a 400 Bad Request response.' + flagStatus: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.followupFlagStatus' + - type: object + nullable: true + description: 'The status for follow-up for an item. Possible values are notFlagged, complete, and flagged.' + startDateTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: The date and time that the follow-up is to begin. + microsoft.graph.importance: + title: importance + enum: + - low + - normal + - high + type: string + microsoft.graph.inferenceClassificationType: + title: inferenceClassificationType + enum: + - focused + - other + type: string + microsoft.graph.internetMessageHeader: + title: internetMessageHeader + type: object + properties: + name: + type: string + description: Represents the key in a key-value pair. + nullable: true + value: + type: string + description: The value in a key-value pair. + nullable: true + microsoft.graph.attachment: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: attachment + type: object + properties: + contentType: + type: string + description: The MIME type. + nullable: true + isInline: + type: boolean + description: 'true if the attachment is an inline attachment; otherwise, false.' + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + name: + type: string + description: The attachment's file name. + nullable: true + size: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The length of the attachment in bytes. + format: int32 + microsoft.graph.extension: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: extension + type: object + microsoft.graph.multiValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: multiValueLegacyExtendedProperty + type: object + properties: + value: + type: array + items: + type: string + nullable: true + description: A collection of property values. + microsoft.graph.singleValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: singleValueLegacyExtendedProperty + type: object + properties: + value: + type: string + description: A property value. + nullable: true + microsoft.graph.messageCollectionResponse: + title: Collection of message + type: object + allOf: + - $ref: '#/components/schemas/BaseCollectionPaginationCountResponse' + - type: object + properties: + value: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.message' + microsoft.graph.ODataErrors.ODataError: + required: + - error + type: object + properties: + error: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.MainError' + microsoft.graph.entity: + title: entity + type: object + properties: + id: + type: string + description: The unique identifier for an entity. Read-only. + microsoft.graph.emailAddress: + title: emailAddress + type: object + properties: + address: + type: string + description: The email address of the person or entity. + nullable: true + name: + type: string + description: The display name of the person or entity. + nullable: true + microsoft.graph.bodyType: + title: bodyType + enum: + - text + - html + type: string + microsoft.graph.dateTimeTimeZone: + title: dateTimeTimeZone + type: object + properties: + dateTime: + type: string + description: 'A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).' + timeZone: + type: string + description: 'Represents a time zone, for example, ''Pacific Standard Time''. See below for more possible values.' + nullable: true + microsoft.graph.followupFlagStatus: + title: followupFlagStatus + enum: + - notFlagged + - complete + - flagged + type: string + BaseCollectionPaginationCountResponse: + title: Base collection pagination and count responses + type: object + properties: + '@odata.nextLink': + type: string + nullable: true + microsoft.graph.ODataErrors.MainError: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + x-ms-primary-error-message: true + target: + type: string + nullable: true + details: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ErrorDetails' + innerError: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.InnerError' + microsoft.graph.ODataErrors.ErrorDetails: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + target: + type: string + nullable: true + microsoft.graph.ODataErrors.InnerError: + type: object + description: The structure of this object is service-specific + responses: + microsoft.graph.messageCollectionResponse: + description: Retrieved collection + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.messageCollectionResponse' + error: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ODataError' + parameters: + top: + name: $top + in: query + description: Show only the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + example: 50 + skip: + name: $skip + in: query + description: Skip the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + search: + name: $search + in: query + description: Search items by search phrases + style: form + explode: false + schema: + type: string + filter: + name: $filter + in: query + description: Filter items by property values + style: form + explode: false + schema: + type: string + count: + name: $count + in: query + description: Include count of items + style: form + explode: false + schema: + type: boolean \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/CalendarPlugin/calendar-apiplugin.json b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/CalendarPlugin/calendar-apiplugin.json new file mode 100644 index 000000000000..8264a87f44ca --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/CalendarPlugin/calendar-apiplugin.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.1/schema.json", + "schema_version": "v2.1", + "name_for_human": "OData Service for namespace microsoft.graph", + "description_for_human": "This OData service is located at https://graph.microsoft.com/v1.0", + "description_for_model": "This OData service is located at https://graph.microsoft.com/v1.0", + "contact_email": "publisher-email@example.com", + "namespace": "Calendar", + "capabilities": { + "conversation_starters": [ + { + "text": "List events" + } + ] + }, + "functions": [ + { + "name": "me_calendar_ListEvents", + "description": "Retrieve a list of events in a calendar. The calendar can be one for a user, or the default calendar of a Microsoft 365 group. The list of events contains single instance meetings and series masters. To get expanded event instances, you can get the calendar view, or\nget the instances of an event." + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "calendar-openapi.yml" + }, + "run_for_functions": [ + "me_calendar_ListEvents" + ] + } + ] +} \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/CalendarPlugin/calendar-openapi.yml b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/CalendarPlugin/calendar-openapi.yml new file mode 100644 index 000000000000..38fd3f979c17 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/CalendarPlugin/calendar-openapi.yml @@ -0,0 +1,1291 @@ +openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph - Subset + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: v1.0 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /me/calendar/events: + get: + tags: + - me.calendar + summary: List events + description: "Retrieve a list of events in a calendar. The calendar can be one for a user, or the default calendar of a Microsoft 365 group. The list of events contains single instance meetings and series masters. To get expanded event instances, you can get the calendar view, or\nget the instances of an event." + externalDocs: + description: Find more info here + url: https://learn.microsoft.com/graph/api/calendar-list-events?view=graph-rest-1.0 + operationId: me_calendar_ListEvents + parameters: + - $ref: '#/components/parameters/top' + - $ref: '#/components/parameters/skip' + - $ref: '#/components/parameters/search' + - $ref: '#/components/parameters/filter' + - $ref: '#/components/parameters/count' + - name: $orderby + in: query + description: Order items by property values + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - id desc + - categories + - categories desc + - changeKey + - changeKey desc + - createdDateTime + - createdDateTime desc + - lastModifiedDateTime + - lastModifiedDateTime desc + - allowNewTimeProposals + - allowNewTimeProposals desc + - attendees + - attendees desc + - body + - body desc + - bodyPreview + - bodyPreview desc + - end + - end desc + - hasAttachments + - hasAttachments desc + - hideAttendees + - hideAttendees desc + - iCalUId + - iCalUId desc + - importance + - importance desc + - isAllDay + - isAllDay desc + - isCancelled + - isCancelled desc + - isDraft + - isDraft desc + - isOnlineMeeting + - isOnlineMeeting desc + - isOrganizer + - isOrganizer desc + - isReminderOn + - isReminderOn desc + - location + - location desc + - locations + - locations desc + - onlineMeeting + - onlineMeeting desc + - onlineMeetingProvider + - onlineMeetingProvider desc + - onlineMeetingUrl + - onlineMeetingUrl desc + - organizer + - organizer desc + - originalEndTimeZone + - originalEndTimeZone desc + - originalStart + - originalStart desc + - originalStartTimeZone + - originalStartTimeZone desc + - recurrence + - recurrence desc + - reminderMinutesBeforeStart + - reminderMinutesBeforeStart desc + - responseRequested + - responseRequested desc + - responseStatus + - responseStatus desc + - sensitivity + - sensitivity desc + - seriesMasterId + - seriesMasterId desc + - showAs + - showAs desc + - start + - start desc + - subject + - subject desc + - transactionId + - transactionId desc + - type + - type desc + - webLink + - webLink desc + type: string + - name: $select + in: query + description: Select properties to be returned + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - categories + - changeKey + - createdDateTime + - lastModifiedDateTime + - allowNewTimeProposals + - attendees + - body + - bodyPreview + - end + - hasAttachments + - hideAttendees + - iCalUId + - importance + - isAllDay + - isCancelled + - isDraft + - isOnlineMeeting + - isOrganizer + - isReminderOn + - location + - locations + - onlineMeeting + - onlineMeetingProvider + - onlineMeetingUrl + - organizer + - originalEndTimeZone + - originalStart + - originalStartTimeZone + - recurrence + - reminderMinutesBeforeStart + - responseRequested + - responseStatus + - sensitivity + - seriesMasterId + - showAs + - start + - subject + - transactionId + - type + - webLink + - attachments + - calendar + - extensions + - instances + - multiValueExtendedProperties + - singleValueExtendedProperties + type: string + - name: $expand + in: query + description: Expand related entities + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - '*' + - attachments + - calendar + - extensions + - instances + - multiValueExtendedProperties + - singleValueExtendedProperties + type: string + responses: + '200': + $ref: '#/components/responses/microsoft.graph.eventCollectionResponse' + default: + $ref: '#/components/responses/error' + x-ms-pageable: + nextLinkName: '@odata.nextLink' + operationName: listMore + itemName: value +components: + schemas: + microsoft.graph.eventCollectionResponse: + title: Collection of event + type: object + allOf: + - $ref: '#/components/schemas/BaseCollectionPaginationCountResponse' + - type: object + properties: + value: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.event' + microsoft.graph.ODataErrors.ODataError: + required: + - error + type: object + properties: + error: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.MainError' + BaseCollectionPaginationCountResponse: + title: Base collection pagination and count responses + type: object + properties: + '@odata.nextLink': + type: string + nullable: true + microsoft.graph.event: + allOf: + - $ref: '#/components/schemas/microsoft.graph.outlookItem' + - title: event + type: object + properties: + allowNewTimeProposals: + type: boolean + description: 'true if the meeting organizer allows invitees to propose a new time when responding; otherwise, false. Optional. Default is true.' + nullable: true + attendees: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.attendee' + description: The collection of attendees for the event. + body: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.itemBody' + - type: object + nullable: true + description: The body of the message associated with the event. It can be in HTML or text format. + bodyPreview: + type: string + description: The preview of the message associated with the event. It is in text format. + nullable: true + end: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: 'The date, time, and time zone that the event ends. By default, the end time is in UTC.' + hasAttachments: + type: boolean + description: Set to true if the event has attachments. + nullable: true + hideAttendees: + type: boolean + description: 'When set to true, each attendee only sees themselves in the meeting request and meeting Tracking list. Default is false.' + nullable: true + iCalUId: + type: string + description: A unique identifier for an event across calendars. This ID is different for each occurrence in a recurring series. Read-only. + nullable: true + importance: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.importance' + - type: object + nullable: true + description: 'The importance of the event. The possible values are: low, normal, high.' + isAllDay: + type: boolean + description: 'Set to true if the event lasts all day. If true, regardless of whether it''s a single-day or multi-day event, start and end time must be set to midnight and be in the same time zone.' + nullable: true + isCancelled: + type: boolean + description: Set to true if the event has been canceled. + nullable: true + isDraft: + type: boolean + description: 'Set to true if the user has updated the meeting in Outlook but has not sent the updates to attendees. Set to false if all changes have been sent, or if the event is an appointment without any attendees.' + nullable: true + isOnlineMeeting: + type: boolean + description: 'True if this event has online meeting information (that is, onlineMeeting points to an onlineMeetingInfo resource), false otherwise. Default is false (onlineMeeting is null). Optional. After you set isOnlineMeeting to true, Microsoft Graph initializes onlineMeeting. Subsequently Outlook ignores any further changes to isOnlineMeeting, and the meeting remains available online.' + nullable: true + isOrganizer: + type: boolean + description: Set to true if the calendar owner (specified by the owner property of the calendar) is the organizer of the event (specified by the organizer property of the event). This also applies if a delegate organized the event on behalf of the owner. + nullable: true + isReminderOn: + type: boolean + description: Set to true if an alert is set to remind the user of the event. + nullable: true + location: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.location' + - type: object + nullable: true + description: The location of the event. + locations: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.location' + description: 'The locations where the event is held or attended from. The location and locations properties always correspond with each other. If you update the location property, any prior locations in the locations collection would be removed and replaced by the new location value.' + onlineMeeting: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.onlineMeetingInfo' + - type: object + nullable: true + description: 'Details for an attendee to join the meeting online. Default is null. Read-only. After you set the isOnlineMeeting and onlineMeetingProvider properties to enable a meeting online, Microsoft Graph initializes onlineMeeting. When set, the meeting remains available online, and you cannot change the isOnlineMeeting, onlineMeetingProvider, and onlneMeeting properties again.' + onlineMeetingProvider: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.onlineMeetingProviderType' + - type: object + nullable: true + description: 'Represents the online meeting service provider. By default, onlineMeetingProvider is unknown. The possible values are unknown, teamsForBusiness, skypeForBusiness, and skypeForConsumer. Optional. After you set onlineMeetingProvider, Microsoft Graph initializes onlineMeeting. Subsequently you cannot change onlineMeetingProvider again, and the meeting remains available online.' + onlineMeetingUrl: + type: string + description: 'A URL for an online meeting. The property is set only when an organizer specifies in Outlook that an event is an online meeting such as Skype. Read-only.To access the URL to join an online meeting, use joinUrl which is exposed via the onlineMeeting property of the event. The onlineMeetingUrl property will be deprecated in the future.' + nullable: true + organizer: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recipient' + - type: object + nullable: true + description: The organizer of the event. + originalEndTimeZone: + type: string + description: The end time zone that was set when the event was created. A value of tzone://Microsoft/Custom indicates that a legacy custom time zone was set in desktop Outlook. + nullable: true + originalStart: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'Represents the start time of an event when it is initially created as an occurrence or exception in a recurring series. This property is not returned for events that are single instances. Its date and time information is expressed in ISO 8601 format and is always in UTC. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + originalStartTimeZone: + type: string + description: The start time zone that was set when the event was created. A value of tzone://Microsoft/Custom indicates that a legacy custom time zone was set in desktop Outlook. + nullable: true + recurrence: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.patternedRecurrence' + - type: object + nullable: true + description: The recurrence pattern for the event. + reminderMinutesBeforeStart: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The number of minutes before the event start time that the reminder alert occurs. + format: int32 + nullable: true + responseRequested: + type: boolean + description: 'Default is true, which represents the organizer would like an invitee to send a response to the event.' + nullable: true + responseStatus: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.responseStatus' + - type: object + nullable: true + description: Indicates the type of response sent in response to an event message. + sensitivity: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.sensitivity' + - type: object + nullable: true + description: 'Possible values are: normal, personal, private, confidential.' + seriesMasterId: + type: string + description: 'The ID for the recurring series master item, if this event is part of a recurring series.' + nullable: true + showAs: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.freeBusyStatus' + - type: object + nullable: true + description: 'The status to show. Possible values are: free, tentative, busy, oof, workingElsewhere, unknown.' + start: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: 'The start date, time, and time zone of the event. By default, the start time is in UTC.' + subject: + type: string + description: The text of the event's subject line. + nullable: true + transactionId: + type: string + description: 'A custom identifier specified by a client app for the server to avoid redundant POST operations in case of client retries to create the same event. This is useful when low network connectivity causes the client to time out before receiving a response from the server for the client''s prior create-event request. After you set transactionId when creating an event, you cannot change transactionId in a subsequent update. This property is only returned in a response payload if an app has set it. Optional.' + nullable: true + type: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.eventType' + - type: object + nullable: true + description: 'The event type. Possible values are: singleInstance, occurrence, exception, seriesMaster. Read-only' + webLink: + type: string + description: 'The URL to open the event in Outlook on the web.Outlook on the web opens the event in the browser if you are signed in to your mailbox. Otherwise, Outlook on the web prompts you to sign in.This URL cannot be accessed from within an iFrame.' + nullable: true + attachments: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.attachment' + description: 'The collection of FileAttachment, ItemAttachment, and referenceAttachment attachments for the event. Navigation property. Read-only. Nullable.' + calendar: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.calendar' + - type: object + nullable: true + description: The calendar that contains the event. Navigation property. Read-only. + extensions: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.extension' + description: The collection of open extensions defined for the event. Nullable. + instances: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.event' + description: 'The occurrences of a recurring series, if the event is a series master. This property includes occurrences that are part of the recurrence pattern, and exceptions that have been modified, but does not include occurrences that have been cancelled from the series. Navigation property. Read-only. Nullable.' + multiValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.multiValueLegacyExtendedProperty' + description: The collection of multi-value extended properties defined for the event. Read-only. Nullable. + singleValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.singleValueLegacyExtendedProperty' + description: The collection of single-value extended properties defined for the event. Read-only. Nullable. + microsoft.graph.ODataErrors.MainError: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + x-ms-primary-error-message: true + target: + type: string + nullable: true + details: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ErrorDetails' + innerError: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.InnerError' + microsoft.graph.outlookItem: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: outlookItem + type: object + properties: + categories: + type: array + items: + type: string + nullable: true + description: The categories associated with the item + changeKey: + type: string + description: 'Identifies the version of the item. Every time the item is changed, changeKey changes as well. This allows Exchange to apply changes to the correct version of the object. Read-only.' + nullable: true + createdDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + microsoft.graph.attendee: + allOf: + - $ref: '#/components/schemas/microsoft.graph.attendeeBase' + - title: attendee + type: object + properties: + proposedNewTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.timeSlot' + - type: object + nullable: true + description: 'An alternate date/time proposed by the attendee for a meeting request to start and end. If the attendee hasn''t proposed another time, then this property isn''t included in a response of a GET event.' + status: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.responseStatus' + - type: object + nullable: true + description: 'The attendee''s response (none, accepted, declined, etc.) for the event and date-time that the response was sent.' + microsoft.graph.itemBody: + title: itemBody + type: object + properties: + content: + type: string + description: The content of the item. + nullable: true + contentType: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.bodyType' + - type: object + nullable: true + description: The type of the content. Possible values are text and html. + microsoft.graph.dateTimeTimeZone: + title: dateTimeTimeZone + type: object + properties: + dateTime: + type: string + description: 'A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).' + timeZone: + type: string + description: 'Represents a time zone, for example, ''Pacific Standard Time''. See below for more possible values.' + nullable: true + microsoft.graph.importance: + title: importance + enum: + - low + - normal + - high + type: string + microsoft.graph.location: + title: location + type: object + properties: + address: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.physicalAddress' + - type: object + nullable: true + description: The street address of the location. + coordinates: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.outlookGeoCoordinates' + - type: object + nullable: true + description: The geographic coordinates and elevation of the location. + displayName: + type: string + description: The name associated with the location. + nullable: true + locationEmailAddress: + type: string + description: Optional email address of the location. + nullable: true + locationType: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.locationType' + - type: object + nullable: true + description: 'The type of location. The possible values are: default, conferenceRoom, homeAddress, businessAddress,geoCoordinates, streetAddress, hotel, restaurant, localBusiness, postalAddress. Read-only.' + locationUri: + type: string + description: Optional URI representing the location. + nullable: true + uniqueId: + type: string + description: For internal use only. + nullable: true + uniqueIdType: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.locationUniqueIdType' + - type: object + nullable: true + description: For internal use only. + microsoft.graph.onlineMeetingInfo: + title: onlineMeetingInfo + type: object + properties: + conferenceId: + type: string + description: The ID of the conference. + nullable: true + joinUrl: + type: string + description: The external link that launches the online meeting. This is a URL that clients launch into a browser and will redirect the user to join the meeting. + nullable: true + phones: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.phone' + description: All of the phone numbers associated with this conference. + quickDial: + type: string + description: The preformatted quick dial for this call. + nullable: true + tollFreeNumbers: + type: array + items: + type: string + nullable: true + description: The toll free numbers that can be used to join the conference. + tollNumber: + type: string + description: The toll number that can be used to join the conference. + nullable: true + microsoft.graph.onlineMeetingProviderType: + title: onlineMeetingProviderType + enum: + - unknown + - skypeForBusiness + - skypeForConsumer + - teamsForBusiness + type: string + microsoft.graph.recipient: + title: recipient + type: object + properties: + emailAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.emailAddress' + - type: object + nullable: true + description: The recipient's email address. + microsoft.graph.patternedRecurrence: + title: patternedRecurrence + type: object + properties: + pattern: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recurrencePattern' + - type: object + nullable: true + description: 'The frequency of an event. For access reviews: Do not specify this property for a one-time access review. Only interval, dayOfMonth, and type (weekly, absoluteMonthly) properties of recurrencePattern are supported.' + range: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recurrenceRange' + - type: object + nullable: true + description: The duration of an event. + microsoft.graph.responseStatus: + title: responseStatus + type: object + properties: + response: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.responseType' + - type: object + nullable: true + description: 'The response type. Possible values are: none, organizer, tentativelyAccepted, accepted, declined, notResponded.To differentiate between none and notResponded: none – from organizer''s perspective. This value is used when the status of an attendee/participant is reported to the organizer of a meeting. notResponded – from attendee''s perspective. Indicates the attendee has not responded to the meeting request. Clients can treat notResponded == none. As an example, if attendee Alex hasn''t responded to a meeting request, getting Alex'' response status for that event in Alex'' calendar returns notResponded. Getting Alex'' response from the calendar of any other attendee or the organizer''s returns none. Getting the organizer''s response for the event in anybody''s calendar also returns none.' + time: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The date and time when the response was returned. It uses ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + microsoft.graph.sensitivity: + title: sensitivity + enum: + - normal + - personal + - private + - confidential + type: string + microsoft.graph.freeBusyStatus: + title: freeBusyStatus + enum: + - unknown + - free + - tentative + - busy + - oof + - workingElsewhere + type: string + microsoft.graph.eventType: + title: eventType + enum: + - singleInstance + - occurrence + - exception + - seriesMaster + type: string + microsoft.graph.attachment: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: attachment + type: object + properties: + contentType: + type: string + description: The MIME type. + nullable: true + isInline: + type: boolean + description: 'true if the attachment is an inline attachment; otherwise, false.' + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + name: + type: string + description: The attachment's file name. + nullable: true + size: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The length of the attachment in bytes. + format: int32 + microsoft.graph.calendar: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: calendar + type: object + properties: + allowedOnlineMeetingProviders: + type: array + items: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.onlineMeetingProviderType' + - type: object + nullable: true + description: 'Represent the online meeting service providers that can be used to create online meetings in this calendar. Possible values are: unknown, skypeForBusiness, skypeForConsumer, teamsForBusiness.' + canEdit: + type: boolean + description: 'true if the user can write to the calendar, false otherwise. This property is true for the user who created the calendar. This property is also true for a user who has been shared a calendar and granted write access.' + nullable: true + canShare: + type: boolean + description: 'true if the user has the permission to share the calendar, false otherwise. Only the user who created the calendar can share it.' + nullable: true + canViewPrivateItems: + type: boolean + description: 'true if the user can read calendar items that have been marked private, false otherwise.' + nullable: true + changeKey: + type: string + description: 'Identifies the version of the calendar object. Every time the calendar is changed, changeKey changes as well. This allows Exchange to apply changes to the correct version of the object. Read-only.' + nullable: true + color: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.calendarColor' + - type: object + nullable: true + description: 'Specifies the color theme to distinguish the calendar from other calendars in a UI. The property values are: auto, lightBlue, lightGreen, lightOrange, lightGray, lightYellow, lightTeal, lightPink, lightBrown, lightRed, maxColor.' + defaultOnlineMeetingProvider: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.onlineMeetingProviderType' + - type: object + nullable: true + description: 'The default online meeting provider for meetings sent from this calendar. Possible values are: unknown, skypeForBusiness, skypeForConsumer, teamsForBusiness.' + hexColor: + type: string + description: 'The calendar color, expressed in a hex color code of three hexadecimal values, each ranging from 00 to FF and representing the red, green, or blue components of the color in the RGB color space. If the user has never explicitly set a color for the calendar, this property is empty. Read-only.' + nullable: true + isDefaultCalendar: + type: boolean + description: 'true if this is the default calendar where new events are created by default, false otherwise.' + nullable: true + isRemovable: + type: boolean + description: Indicates whether this user calendar can be deleted from the user mailbox. + nullable: true + isTallyingResponses: + type: boolean + description: Indicates whether this user calendar supports tracking of meeting responses. Only meeting invites sent from users' primary calendars support tracking of meeting responses. + nullable: true + name: + type: string + description: The calendar name. + nullable: true + owner: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.emailAddress' + - type: object + nullable: true + description: 'If set, this represents the user who created or added the calendar. For a calendar that the user created or added, the owner property is set to the user. For a calendar shared with the user, the owner property is set to the person who shared that calendar with the user.' + calendarPermissions: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.calendarPermission' + description: The permissions of the users with whom the calendar is shared. + calendarView: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.event' + description: The calendar view for the calendar. Navigation property. Read-only. + events: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.event' + description: The events in the calendar. Navigation property. Read-only. + multiValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.multiValueLegacyExtendedProperty' + description: The collection of multi-value extended properties defined for the calendar. Read-only. Nullable. + singleValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.singleValueLegacyExtendedProperty' + description: The collection of single-value extended properties defined for the calendar. Read-only. Nullable. + microsoft.graph.extension: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: extension + type: object + microsoft.graph.multiValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: multiValueLegacyExtendedProperty + type: object + properties: + value: + type: array + items: + type: string + nullable: true + description: A collection of property values. + microsoft.graph.singleValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: singleValueLegacyExtendedProperty + type: object + properties: + value: + type: string + description: A property value. + nullable: true + microsoft.graph.ODataErrors.ErrorDetails: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + target: + type: string + nullable: true + microsoft.graph.ODataErrors.InnerError: + type: object + description: The structure of this object is service-specific + microsoft.graph.entity: + title: entity + type: object + properties: + id: + type: string + description: The unique identifier for an entity. Read-only. + microsoft.graph.attendeeBase: + allOf: + - $ref: '#/components/schemas/microsoft.graph.recipient' + - title: attendeeBase + type: object + properties: + type: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.attendeeType' + - type: object + nullable: true + description: 'The type of attendee. The possible values are: required, optional, resource. Currently if the attendee is a person, findMeetingTimes always considers the person is of the Required type.' + microsoft.graph.timeSlot: + title: timeSlot + type: object + properties: + end: + $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + start: + $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + microsoft.graph.bodyType: + title: bodyType + enum: + - text + - html + type: string + microsoft.graph.physicalAddress: + title: physicalAddress + type: object + properties: + city: + type: string + description: The city. + nullable: true + countryOrRegion: + type: string + description: 'The country or region. It''s a free-format string value, for example, ''United States''.' + nullable: true + postalCode: + type: string + description: The postal code. + nullable: true + state: + type: string + description: The state. + nullable: true + street: + type: string + description: The street. + nullable: true + microsoft.graph.outlookGeoCoordinates: + title: outlookGeoCoordinates + type: object + properties: + accuracy: + oneOf: + - type: number + format: double + nullable: true + - type: string + nullable: true + - $ref: '#/components/schemas/ReferenceNumeric' + description: 'The accuracy of the latitude and longitude. As an example, the accuracy can be measured in meters, such as the latitude and longitude are accurate to within 50 meters.' + altitude: + oneOf: + - type: number + format: double + nullable: true + - type: string + nullable: true + - $ref: '#/components/schemas/ReferenceNumeric' + description: The altitude of the location. + altitudeAccuracy: + oneOf: + - type: number + format: double + nullable: true + - type: string + nullable: true + - $ref: '#/components/schemas/ReferenceNumeric' + description: The accuracy of the altitude. + latitude: + oneOf: + - type: number + format: double + nullable: true + - type: string + nullable: true + - $ref: '#/components/schemas/ReferenceNumeric' + description: The latitude of the location. + longitude: + oneOf: + - type: number + format: double + nullable: true + - type: string + nullable: true + - $ref: '#/components/schemas/ReferenceNumeric' + description: The longitude of the location. + microsoft.graph.locationType: + title: locationType + enum: + - default + - conferenceRoom + - homeAddress + - businessAddress + - geoCoordinates + - streetAddress + - hotel + - restaurant + - localBusiness + - postalAddress + type: string + microsoft.graph.locationUniqueIdType: + title: locationUniqueIdType + enum: + - unknown + - locationStore + - directory + - private + - bing + type: string + microsoft.graph.phone: + title: phone + type: object + properties: + language: + type: string + nullable: true + number: + type: string + description: The phone number. + nullable: true + region: + type: string + nullable: true + type: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.phoneType' + - type: object + nullable: true + description: 'The type of phone number. The possible values are: home, business, mobile, other, assistant, homeFax, businessFax, otherFax, pager, radio.' + microsoft.graph.emailAddress: + title: emailAddress + type: object + properties: + address: + type: string + description: The email address of the person or entity. + nullable: true + name: + type: string + description: The display name of the person or entity. + nullable: true + microsoft.graph.recurrencePattern: + title: recurrencePattern + type: object + properties: + dayOfMonth: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The day of the month on which the event occurs. Required if type is absoluteMonthly or absoluteYearly. + format: int32 + daysOfWeek: + type: array + items: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dayOfWeek' + - type: object + nullable: true + description: 'A collection of the days of the week on which the event occurs. The possible values are: sunday, monday, tuesday, wednesday, thursday, friday, saturday. If type is relativeMonthly or relativeYearly, and daysOfWeek specifies more than one day, the event falls on the first day that satisfies the pattern. Required if type is weekly, relativeMonthly, or relativeYearly.' + firstDayOfWeek: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dayOfWeek' + - type: object + nullable: true + description: 'The first day of the week. The possible values are: sunday, monday, tuesday, wednesday, thursday, friday, saturday. Default is sunday. Required if type is weekly.' + index: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.weekIndex' + - type: object + nullable: true + description: 'Specifies on which instance of the allowed days specified in daysOfWeek the event occurs, counted from the first instance in the month. The possible values are: first, second, third, fourth, last. Default is first. Optional and used if type is relativeMonthly or relativeYearly.' + interval: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: 'The number of units between occurrences, where units can be in days, weeks, months, or years, depending on the type. Required.' + format: int32 + month: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The month in which the event occurs. This is a number from 1 to 12. + format: int32 + type: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recurrencePatternType' + - type: object + nullable: true + description: 'The recurrence pattern type: daily, weekly, absoluteMonthly, relativeMonthly, absoluteYearly, relativeYearly. Required. For more information, see values of type property.' + microsoft.graph.recurrenceRange: + title: recurrenceRange + type: object + properties: + endDate: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$' + type: string + description: 'The date to stop applying the recurrence pattern. Depending on the recurrence pattern of the event, the last occurrence of the meeting may not be this date. Required if type is endDate.' + format: date + nullable: true + numberOfOccurrences: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The number of times to repeat the event. Required and must be positive if type is numbered. + format: int32 + recurrenceTimeZone: + type: string + description: 'Time zone for the startDate and endDate properties. Optional. If not specified, the time zone of the event is used.' + nullable: true + startDate: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$' + type: string + description: 'The date to start applying the recurrence pattern. The first occurrence of the meeting may be this date or later, depending on the recurrence pattern of the event. Must be the same value as the start property of the recurring event. Required.' + format: date + nullable: true + type: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recurrenceRangeType' + - type: object + nullable: true + description: 'The recurrence range. The possible values are: endDate, noEnd, numbered. Required.' + microsoft.graph.responseType: + title: responseType + enum: + - none + - organizer + - tentativelyAccepted + - accepted + - declined + - notResponded + type: string + microsoft.graph.calendarColor: + title: calendarColor + enum: + - auto + - lightBlue + - lightGreen + - lightOrange + - lightGray + - lightYellow + - lightTeal + - lightPink + - lightBrown + - lightRed + - maxColor + type: string + microsoft.graph.calendarPermission: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: calendarPermission + type: object + properties: + allowedRoles: + type: array + items: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.calendarRoleType' + - type: object + nullable: true + description: 'List of allowed sharing or delegating permission levels for the calendar. Possible values are: none, freeBusyRead, limitedRead, read, write, delegateWithoutPrivateEventAccess, delegateWithPrivateEventAccess, custom.' + emailAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.emailAddress' + - type: object + nullable: true + description: 'Represents a share recipient or delegate who has access to the calendar. For the ''My Organization'' share recipient, the address property is null. Read-only.' + isInsideOrganization: + type: boolean + description: True if the user in context (recipient or delegate) is inside the same organization as the calendar owner. + nullable: true + isRemovable: + type: boolean + description: 'True if the user can be removed from the list of recipients or delegates for the specified calendar, false otherwise. The ''My organization'' user determines the permissions other people within your organization have to the given calendar. You can''t remove ''My organization'' as a share recipient to a calendar.' + nullable: true + role: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.calendarRoleType' + - type: object + nullable: true + description: Current permission level of the calendar share recipient or delegate. + microsoft.graph.attendeeType: + title: attendeeType + enum: + - required + - optional + - resource + type: string + ReferenceNumeric: + enum: + - '-INF' + - INF + - NaN + type: string + nullable: true + microsoft.graph.phoneType: + title: phoneType + enum: + - home + - business + - mobile + - other + - assistant + - homeFax + - businessFax + - otherFax + - pager + - radio + type: string + microsoft.graph.dayOfWeek: + title: dayOfWeek + enum: + - sunday + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday + type: string + microsoft.graph.weekIndex: + title: weekIndex + enum: + - first + - second + - third + - fourth + - last + type: string + microsoft.graph.recurrencePatternType: + title: recurrencePatternType + enum: + - daily + - weekly + - absoluteMonthly + - relativeMonthly + - absoluteYearly + - relativeYearly + type: string + microsoft.graph.recurrenceRangeType: + title: recurrenceRangeType + enum: + - endDate + - noEnd + - numbered + type: string + microsoft.graph.calendarRoleType: + title: calendarRoleType + enum: + - none + - freeBusyRead + - limitedRead + - read + - write + - delegateWithoutPrivateEventAccess + - delegateWithPrivateEventAccess + - custom + type: string + responses: + microsoft.graph.eventCollectionResponse: + description: Retrieved collection + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.eventCollectionResponse' + error: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ODataError' + parameters: + top: + name: $top + in: query + description: Show only the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + example: 50 + skip: + name: $skip + in: query + description: Skip the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + search: + name: $search + in: query + description: Search items by search phrases + style: form + explode: false + schema: + type: string + filter: + name: $filter + in: query + description: Filter items by property values + style: form + explode: false + schema: + type: string + count: + name: $count + in: query + description: Include count of items + style: form + explode: false + schema: + type: boolean \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/ContactsPlugin/contacts-apiplugin.json b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/ContactsPlugin/contacts-apiplugin.json new file mode 100644 index 000000000000..28386d843fa5 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/ContactsPlugin/contacts-apiplugin.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.1/schema.json", + "schema_version": "v2.1", + "name_for_human": "OData Service for namespace microsoft.graph", + "description_for_human": "This OData service is located at https://graph.microsoft.com/v1.0", + "description_for_model": "This OData service is located at https://graph.microsoft.com/v1.0", + "contact_email": "publisher-email@example.com", + "namespace": "Contacts", + "capabilities": { + "conversation_starters": [ + { + "text": "List contacts" + } + ] + }, + "functions": [ + { + "name": "me_ListContacts", + "description": "Get a contact collection from the default contacts folder of the signed-in user. There are two scenarios where an app can get contacts in another user\u0026apos;s contact folder:" + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "contacts-openapi.yml" + }, + "run_for_functions": [ + "me_ListContacts" + ] + } + ] +} \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/ContactsPlugin/contacts-openapi.yml b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/ContactsPlugin/contacts-openapi.yml new file mode 100644 index 000000000000..695a3232015b --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/ContactsPlugin/contacts-openapi.yml @@ -0,0 +1,603 @@ +openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph - Subset + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: v1.0 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /me/contacts: + get: + tags: + - me.contact + summary: List contacts + description: 'Get a contact collection from the default contacts folder of the signed-in user. There are two scenarios where an app can get contacts in another user''s contact folder:' + externalDocs: + description: Find more info here + url: https://learn.microsoft.com/graph/api/user-list-contacts?view=graph-rest-1.0 + operationId: me_ListContacts + parameters: + - $ref: '#/components/parameters/top' + - $ref: '#/components/parameters/skip' + - $ref: '#/components/parameters/search' + - $ref: '#/components/parameters/filter' + - $ref: '#/components/parameters/count' + - name: $orderby + in: query + description: Order items by property values + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - id desc + - categories + - categories desc + - changeKey + - changeKey desc + - createdDateTime + - createdDateTime desc + - lastModifiedDateTime + - lastModifiedDateTime desc + - assistantName + - assistantName desc + - birthday + - birthday desc + - businessAddress + - businessAddress desc + - businessHomePage + - businessHomePage desc + - businessPhones + - businessPhones desc + - children + - children desc + - companyName + - companyName desc + - department + - department desc + - displayName + - displayName desc + - emailAddresses + - emailAddresses desc + - fileAs + - fileAs desc + - generation + - generation desc + - givenName + - givenName desc + - homeAddress + - homeAddress desc + - homePhones + - homePhones desc + - imAddresses + - imAddresses desc + - initials + - initials desc + - jobTitle + - jobTitle desc + - manager + - manager desc + - middleName + - middleName desc + - mobilePhone + - mobilePhone desc + - nickName + - nickName desc + - officeLocation + - officeLocation desc + - otherAddress + - otherAddress desc + - parentFolderId + - parentFolderId desc + - personalNotes + - personalNotes desc + - profession + - profession desc + - spouseName + - spouseName desc + - surname + - surname desc + - title + - title desc + - yomiCompanyName + - yomiCompanyName desc + - yomiGivenName + - yomiGivenName desc + - yomiSurname + - yomiSurname desc + type: string + - name: $select + in: query + description: Select properties to be returned + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - categories + - changeKey + - createdDateTime + - lastModifiedDateTime + - assistantName + - birthday + - businessAddress + - businessHomePage + - businessPhones + - children + - companyName + - department + - displayName + - emailAddresses + - fileAs + - generation + - givenName + - homeAddress + - homePhones + - imAddresses + - initials + - jobTitle + - manager + - middleName + - mobilePhone + - nickName + - officeLocation + - otherAddress + - parentFolderId + - personalNotes + - profession + - spouseName + - surname + - title + - yomiCompanyName + - yomiGivenName + - yomiSurname + - extensions + - multiValueExtendedProperties + - photo + - singleValueExtendedProperties + type: string + - name: $expand + in: query + description: Expand related entities + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - '*' + - extensions + - multiValueExtendedProperties + - photo + - singleValueExtendedProperties + type: string + responses: + '200': + $ref: '#/components/responses/microsoft.graph.contactCollectionResponse' + default: + $ref: '#/components/responses/error' + x-ms-pageable: + nextLinkName: '@odata.nextLink' + operationName: listMore + itemName: value +components: + schemas: + microsoft.graph.contactCollectionResponse: + title: Collection of contact + type: object + allOf: + - $ref: '#/components/schemas/BaseCollectionPaginationCountResponse' + - type: object + properties: + value: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.contact' + microsoft.graph.ODataErrors.ODataError: + required: + - error + type: object + properties: + error: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.MainError' + BaseCollectionPaginationCountResponse: + title: Base collection pagination and count responses + type: object + properties: + '@odata.nextLink': + type: string + nullable: true + microsoft.graph.contact: + allOf: + - $ref: '#/components/schemas/microsoft.graph.outlookItem' + - title: contact + type: object + properties: + assistantName: + type: string + description: The name of the contact's assistant. + nullable: true + birthday: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The contact''s birthday. The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + businessAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.physicalAddress' + - type: object + nullable: true + description: The contact's business address. + businessHomePage: + type: string + description: The business home page of the contact. + nullable: true + businessPhones: + type: array + items: + type: string + nullable: true + description: The contact's business phone numbers. + children: + type: array + items: + type: string + nullable: true + description: The names of the contact's children. + companyName: + type: string + description: The name of the contact's company. + nullable: true + department: + type: string + description: The contact's department. + nullable: true + displayName: + type: string + description: 'The contact''s display name. You can specify the display name in a create or update operation. Note that later updates to other properties may cause an automatically generated value to overwrite the displayName value you have specified. To preserve a pre-existing value, always include it as displayName in an update operation.' + nullable: true + emailAddresses: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.emailAddress' + description: The contact's email addresses. + fileAs: + type: string + description: The name the contact is filed under. + nullable: true + generation: + type: string + description: The contact's suffix. + nullable: true + givenName: + type: string + description: The contact's given name. + nullable: true + homeAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.physicalAddress' + - type: object + nullable: true + description: The contact's home address. + homePhones: + type: array + items: + type: string + nullable: true + description: The contact's home phone numbers. + imAddresses: + type: array + items: + type: string + nullable: true + description: The contact's instant messaging (IM) addresses. + initials: + type: string + description: The contact's initials. + nullable: true + jobTitle: + type: string + description: The contact’s job title. + nullable: true + manager: + type: string + description: The name of the contact's manager. + nullable: true + middleName: + type: string + description: The contact's middle name. + nullable: true + mobilePhone: + type: string + description: The contact's mobile phone number. + nullable: true + nickName: + type: string + description: The contact's nickname. + nullable: true + officeLocation: + type: string + description: The location of the contact's office. + nullable: true + otherAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.physicalAddress' + - type: object + nullable: true + description: Other addresses for the contact. + parentFolderId: + type: string + description: The ID of the contact's parent folder. + nullable: true + personalNotes: + type: string + description: The user's notes about the contact. + nullable: true + profession: + type: string + description: The contact's profession. + nullable: true + spouseName: + type: string + description: The name of the contact's spouse/partner. + nullable: true + surname: + type: string + description: The contact's surname. + nullable: true + title: + type: string + description: The contact's title. + nullable: true + yomiCompanyName: + type: string + description: The phonetic Japanese company name of the contact. + nullable: true + yomiGivenName: + type: string + description: The phonetic Japanese given name (first name) of the contact. + nullable: true + yomiSurname: + type: string + description: The phonetic Japanese surname (last name) of the contact. + nullable: true + extensions: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.extension' + description: The collection of open extensions defined for the contact. Read-only. Nullable. + multiValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.multiValueLegacyExtendedProperty' + description: The collection of multi-value extended properties defined for the contact. Read-only. Nullable. + photo: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.profilePhoto' + - type: object + nullable: true + description: Optional contact picture. You can get or set a photo for a contact. + singleValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.singleValueLegacyExtendedProperty' + description: The collection of single-value extended properties defined for the contact. Read-only. Nullable. + microsoft.graph.ODataErrors.MainError: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + x-ms-primary-error-message: true + target: + type: string + nullable: true + details: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ErrorDetails' + innerError: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.InnerError' + microsoft.graph.outlookItem: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: outlookItem + type: object + properties: + categories: + type: array + items: + type: string + nullable: true + description: The categories associated with the item + changeKey: + type: string + description: 'Identifies the version of the item. Every time the item is changed, changeKey changes as well. This allows Exchange to apply changes to the correct version of the object. Read-only.' + nullable: true + createdDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + microsoft.graph.physicalAddress: + title: physicalAddress + type: object + properties: + city: + type: string + description: The city. + nullable: true + countryOrRegion: + type: string + description: 'The country or region. It''s a free-format string value, for example, ''United States''.' + nullable: true + postalCode: + type: string + description: The postal code. + nullable: true + state: + type: string + description: The state. + nullable: true + street: + type: string + description: The street. + nullable: true + microsoft.graph.emailAddress: + title: emailAddress + type: object + properties: + address: + type: string + description: The email address of the person or entity. + nullable: true + name: + type: string + description: The display name of the person or entity. + nullable: true + microsoft.graph.extension: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: extension + type: object + microsoft.graph.multiValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: multiValueLegacyExtendedProperty + type: object + properties: + value: + type: array + items: + type: string + nullable: true + description: A collection of property values. + microsoft.graph.profilePhoto: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: profilePhoto + type: object + properties: + height: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The height of the photo. Read-only. + format: int32 + nullable: true + width: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The width of the photo. Read-only. + format: int32 + nullable: true + microsoft.graph.singleValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: singleValueLegacyExtendedProperty + type: object + properties: + value: + type: string + description: A property value. + nullable: true + microsoft.graph.ODataErrors.ErrorDetails: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + target: + type: string + nullable: true + microsoft.graph.ODataErrors.InnerError: + type: object + description: The structure of this object is service-specific + microsoft.graph.entity: + title: entity + type: object + properties: + id: + type: string + description: The unique identifier for an entity. Read-only. + responses: + microsoft.graph.contactCollectionResponse: + description: Retrieved collection + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.contactCollectionResponse' + error: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ODataError' + parameters: + top: + name: $top + in: query + description: Show only the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + example: 50 + skip: + name: $skip + in: query + description: Skip the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + search: + name: $search + in: query + description: Search items by search phrases + style: form + explode: false + schema: + type: string + filter: + name: $filter + in: query + description: Filter items by property values + style: form + explode: false + schema: + type: string + count: + name: $count + in: query + description: Include count of items + style: form + explode: false + schema: + type: boolean \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/DriveItemPlugin/driveitem-apiplugin.json b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/DriveItemPlugin/driveitem-apiplugin.json new file mode 100644 index 000000000000..e421c6c2e23a --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/DriveItemPlugin/driveitem-apiplugin.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.1/schema.json", + "schema_version": "v2.1", + "name_for_human": "OData Service for namespace microsoft.graph", + "description_for_human": "This OData service is located at https://graph.microsoft.com/v1.0", + "description_for_model": "This OData service is located at https://graph.microsoft.com/v1.0", + "contact_email": "publisher-email@example.com", + "namespace": "DriveItem", + "capabilities": { + "conversation_starters": [ + { + "text": "Get content for the navigation property children f" + } + ] + }, + "functions": [ + { + "name": "drive_root_GetChildrenContent", + "description": "The content stream, if the item represents a file." + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "driveitem-openapi.yml" + }, + "run_for_functions": [ + "drive_root_GetChildrenContent" + ] + } + ] +} \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/DriveItemPlugin/driveitem-openapi.yml b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/DriveItemPlugin/driveitem-openapi.yml new file mode 100644 index 000000000000..9814212c23d5 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/DriveItemPlugin/driveitem-openapi.yml @@ -0,0 +1,92 @@ +openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph - Subset + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: v1.0 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + '/drive/root/children/{driveItem-id}/content': + get: + tags: + - drive.driveItem + summary: Get content for the navigation property children from drive + description: 'The content stream, if the item represents a file.' + operationId: drive_root_GetChildrenContent + parameters: + - name: driveItem-id + in: path + description: The unique identifier of driveItem + required: true + style: simple + schema: + type: string + - name: $format + in: query + description: Format of the content + style: form + explode: false + schema: + type: string + responses: + '200': + description: Retrieved media content + content: + application/octet-stream: + schema: + type: string + format: binary + default: + $ref: '#/components/responses/error' +components: + schemas: + microsoft.graph.ODataErrors.ODataError: + required: + - error + type: object + properties: + error: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.MainError' + microsoft.graph.ODataErrors.MainError: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + x-ms-primary-error-message: true + target: + type: string + nullable: true + details: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ErrorDetails' + innerError: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.InnerError' + microsoft.graph.ODataErrors.ErrorDetails: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + target: + type: string + nullable: true + microsoft.graph.ODataErrors.InnerError: + type: object + description: The structure of this object is service-specific + responses: + error: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ODataError' \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/MessagesPlugin/messages-apiplugin.json b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/MessagesPlugin/messages-apiplugin.json new file mode 100644 index 000000000000..ecf9a10c0782 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/MessagesPlugin/messages-apiplugin.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/copilot/plugin/v2.1/schema.json", + "schema_version": "v2.1", + "name_for_human": "OData Service for namespace microsoft.graph", + "description_for_human": "This OData service is located at https://graph.microsoft.com/v1.0", + "description_for_model": "This OData service is located at https://graph.microsoft.com/v1.0", + "contact_email": "publisher-email@example.com", + "namespace": "Messages", + "capabilities": { + "conversation_starters": [ + { + "text": "Get open extension" + }, + { + "text": "Create open extension" + } + ] + }, + "functions": [ + { + "name": "me_CreateMessages", + "description": "Create an open extension (openTypeExtension object) and add custom properties in a new or existing instance of a resource. You can create an open extension in a resource instance and store custom data to it all in the same operation, except for specific resources. The table in the Permissions section lists the resources that support open extensions." + }, + { + "name": "me_ListMessages", + "description": "Get an open extension (openTypeExtension object) identified by name or fully qualified name. The table in the Permissions section lists the resources that support open extensions. The following table lists the three scenarios where you can get an open extension from a supported resource instance." + } + ], + "runtimes": [ + { + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "messages-openapi.yml" + }, + "run_for_functions": [ + "me_ListMessages", + "me_CreateMessages" + ] + } + ] +} \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/MessagesPlugin/messages-openapi.yml b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/MessagesPlugin/messages-openapi.yml new file mode 100644 index 000000000000..f9c7b11e712b --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/MessagesPlugin/messages-openapi.yml @@ -0,0 +1,678 @@ +openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph - Subset + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: v1.0 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /me/messages: + get: + tags: + - me.message + summary: Get open extension + description: Get an open extension (openTypeExtension object) identified by name or fully qualified name. The table in the Permissions section lists the resources that support open extensions. The following table lists the three scenarios where you can get an open extension from a supported resource instance. + externalDocs: + description: Find more info here + url: https://learn.microsoft.com/graph/api/opentypeextension-get?view=graph-rest-1.0 + operationId: me_ListMessages + parameters: + - name: includeHiddenMessages + in: query + description: Include Hidden Messages + style: form + explode: false + schema: + type: string + - $ref: '#/components/parameters/top' + - $ref: '#/components/parameters/skip' + - $ref: '#/components/parameters/search' + - $ref: '#/components/parameters/filter' + - $ref: '#/components/parameters/count' + - name: $orderby + in: query + description: Order items by property values + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - id desc + - categories + - categories desc + - changeKey + - changeKey desc + - createdDateTime + - createdDateTime desc + - lastModifiedDateTime + - lastModifiedDateTime desc + - bccRecipients + - bccRecipients desc + - body + - body desc + - bodyPreview + - bodyPreview desc + - ccRecipients + - ccRecipients desc + - conversationId + - conversationId desc + - conversationIndex + - conversationIndex desc + - flag + - flag desc + - from + - from desc + - hasAttachments + - hasAttachments desc + - importance + - importance desc + - inferenceClassification + - inferenceClassification desc + - internetMessageHeaders + - internetMessageHeaders desc + - internetMessageId + - internetMessageId desc + - isDeliveryReceiptRequested + - isDeliveryReceiptRequested desc + - isDraft + - isDraft desc + - isRead + - isRead desc + - isReadReceiptRequested + - isReadReceiptRequested desc + - parentFolderId + - parentFolderId desc + - receivedDateTime + - receivedDateTime desc + - replyTo + - replyTo desc + - sender + - sender desc + - sentDateTime + - sentDateTime desc + - subject + - subject desc + - toRecipients + - toRecipients desc + - uniqueBody + - uniqueBody desc + - webLink + - webLink desc + type: string + - name: $select + in: query + description: Select properties to be returned + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - id + - categories + - changeKey + - createdDateTime + - lastModifiedDateTime + - bccRecipients + - body + - bodyPreview + - ccRecipients + - conversationId + - conversationIndex + - flag + - from + - hasAttachments + - importance + - inferenceClassification + - internetMessageHeaders + - internetMessageId + - isDeliveryReceiptRequested + - isDraft + - isRead + - isReadReceiptRequested + - parentFolderId + - receivedDateTime + - replyTo + - sender + - sentDateTime + - subject + - toRecipients + - uniqueBody + - webLink + - attachments + - extensions + - multiValueExtendedProperties + - singleValueExtendedProperties + type: string + - name: $expand + in: query + description: Expand related entities + style: form + explode: false + schema: + uniqueItems: true + type: array + items: + enum: + - '*' + - attachments + - extensions + - multiValueExtendedProperties + - singleValueExtendedProperties + type: string + responses: + '200': + $ref: '#/components/responses/microsoft.graph.messageCollectionResponse' + default: + $ref: '#/components/responses/error' + x-ms-pageable: + nextLinkName: '@odata.nextLink' + operationName: listMore + itemName: value + post: + tags: + - me.message + summary: Create open extension + description: 'Create an open extension (openTypeExtension object) and add custom properties in a new or existing instance of a resource. You can create an open extension in a resource instance and store custom data to it all in the same operation, except for specific resources. The table in the Permissions section lists the resources that support open extensions.' + externalDocs: + description: Find more info here + url: https://learn.microsoft.com/graph/api/opentypeextension-post-opentypeextension?view=graph-rest-1.0 + operationId: me_CreateMessages + requestBody: + description: New navigation property + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.outlookItem' + required: true + responses: + '201': + description: Created navigation property. + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.message' + default: + $ref: '#/components/responses/error' +components: + schemas: + microsoft.graph.message: + allOf: + - $ref: '#/components/schemas/microsoft.graph.outlookItem' + - title: message + type: object + properties: + bccRecipients: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: 'The Bcc: recipients for the message.' + body: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.itemBody' + - type: object + nullable: true + description: The body of the message. It can be in HTML or text format. Find out about safe HTML in a message body. + bodyPreview: + type: string + description: The first 255 characters of the message body. It is in text format. + nullable: true + ccRecipients: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: 'The Cc: recipients for the message.' + conversationId: + type: string + description: The ID of the conversation the email belongs to. + nullable: true + conversationIndex: + type: string + description: Indicates the position of the message within the conversation. + format: base64url + nullable: true + flag: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.followupFlag' + - type: object + nullable: true + description: 'The flag value that indicates the status, start date, due date, or completion date for the message.' + from: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recipient' + - type: object + nullable: true + description: 'The owner of the mailbox from which the message is sent. In most cases, this value is the same as the sender property, except for sharing or delegation scenarios. The value must correspond to the actual mailbox used. Find out more about setting the from and sender properties of a message.' + hasAttachments: + type: boolean + description: 'Indicates whether the message has attachments. This property doesn''t include inline attachments, so if a message contains only inline attachments, this property is false. To verify the existence of inline attachments, parse the body property to look for a src attribute, such as .' + nullable: true + importance: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.importance' + - type: object + nullable: true + description: 'The importance of the message. The possible values are: low, normal, and high.' + inferenceClassification: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.inferenceClassificationType' + - type: object + nullable: true + description: 'The classification of the message for the user, based on inferred relevance or importance, or on an explicit override. The possible values are: focused or other.' + internetMessageHeaders: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.internetMessageHeader' + description: A collection of message headers defined by RFC5322. The set includes message headers indicating the network path taken by a message from the sender to the recipient. It can also contain custom message headers that hold app data for the message. Returned only on applying a $select query option. Read-only. + internetMessageId: + type: string + description: The message ID in the format specified by RFC2822. + nullable: true + isDeliveryReceiptRequested: + type: boolean + description: Indicates whether a read receipt is requested for the message. + nullable: true + isDraft: + type: boolean + description: Indicates whether the message is a draft. A message is a draft if it hasn't been sent yet. + nullable: true + isRead: + type: boolean + description: Indicates whether the message has been read. + nullable: true + isReadReceiptRequested: + type: boolean + description: Indicates whether a read receipt is requested for the message. + nullable: true + parentFolderId: + type: string + description: The unique identifier for the message's parent mailFolder. + nullable: true + receivedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The date and time the message was received. The date and time information uses ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z.' + format: date-time + nullable: true + replyTo: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: The email addresses to use when replying. + sender: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.recipient' + - type: object + nullable: true + description: 'The account that is actually used to generate the message. In most cases, this value is the same as the from property. You can set this property to a different value when sending a message from a shared mailbox, for a shared calendar, or as a delegate. In any case, the value must correspond to the actual mailbox used. Find out more about setting the from and sender properties of a message.' + sentDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The date and time the message was sent. The date and time information uses ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z.' + format: date-time + nullable: true + subject: + type: string + description: The subject of the message. + nullable: true + toRecipients: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.recipient' + description: 'The To: recipients for the message.' + uniqueBody: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.itemBody' + - type: object + nullable: true + description: The part of the body of the message that is unique to the current message. uniqueBody is not returned by default but can be retrieved for a given message by use of the ?$select=uniqueBody query. It can be in HTML or text format. + webLink: + type: string + description: 'The URL to open the message in Outlook on the web.You can append an ispopout argument to the end of the URL to change how the message is displayed. If ispopout is not present or if it is set to 1, then the message is shown in a popout window. If ispopout is set to 0, the browser shows the message in the Outlook on the web review pane.The message opens in the browser if you are signed in to your mailbox via Outlook on the web. You are prompted to sign in if you are not already signed in with the browser.This URL cannot be accessed from within an iFrame.' + nullable: true + attachments: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.attachment' + description: The fileAttachment and itemAttachment attachments for the message. + extensions: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.extension' + description: The collection of open extensions defined for the message. Nullable. + multiValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.multiValueLegacyExtendedProperty' + description: The collection of multi-value extended properties defined for the message. Nullable. + singleValueExtendedProperties: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.singleValueLegacyExtendedProperty' + description: The collection of single-value extended properties defined for the message. Nullable. + microsoft.graph.outlookItem: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: outlookItem + type: object + properties: + categories: + type: array + items: + type: string + nullable: true + description: The categories associated with the item + changeKey: + type: string + description: 'Identifies the version of the item. Every time the item is changed, changeKey changes as well. This allows Exchange to apply changes to the correct version of the object. Read-only.' + nullable: true + createdDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + microsoft.graph.recipient: + title: recipient + type: object + properties: + emailAddress: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.emailAddress' + - type: object + nullable: true + description: The recipient's email address. + microsoft.graph.itemBody: + title: itemBody + type: object + properties: + content: + type: string + description: The content of the item. + nullable: true + contentType: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.bodyType' + - type: object + nullable: true + description: The type of the content. Possible values are text and html. + microsoft.graph.followupFlag: + title: followupFlag + type: object + properties: + completedDateTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: The date and time that the follow-up was finished. + dueDateTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: 'The date and time that the follow-up is to be finished. Note: To set the due date, you must also specify the startDateTime; otherwise, you get a 400 Bad Request response.' + flagStatus: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.followupFlagStatus' + - type: object + nullable: true + description: 'The status for follow-up for an item. Possible values are notFlagged, complete, and flagged.' + startDateTime: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dateTimeTimeZone' + - type: object + nullable: true + description: The date and time that the follow-up is to begin. + microsoft.graph.importance: + title: importance + enum: + - low + - normal + - high + type: string + microsoft.graph.inferenceClassificationType: + title: inferenceClassificationType + enum: + - focused + - other + type: string + microsoft.graph.internetMessageHeader: + title: internetMessageHeader + type: object + properties: + name: + type: string + description: Represents the key in a key-value pair. + nullable: true + value: + type: string + description: The value in a key-value pair. + nullable: true + microsoft.graph.attachment: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: attachment + type: object + properties: + contentType: + type: string + description: The MIME type. + nullable: true + isInline: + type: boolean + description: 'true if the attachment is an inline attachment; otherwise, false.' + lastModifiedDateTime: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + description: 'The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z' + format: date-time + nullable: true + name: + type: string + description: The attachment's file name. + nullable: true + size: + maximum: 2147483647 + minimum: -2147483648 + type: number + description: The length of the attachment in bytes. + format: int32 + microsoft.graph.extension: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: extension + type: object + microsoft.graph.multiValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: multiValueLegacyExtendedProperty + type: object + properties: + value: + type: array + items: + type: string + nullable: true + description: A collection of property values. + microsoft.graph.singleValueLegacyExtendedProperty: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: singleValueLegacyExtendedProperty + type: object + properties: + value: + type: string + description: A property value. + nullable: true + microsoft.graph.messageCollectionResponse: + title: Collection of message + type: object + allOf: + - $ref: '#/components/schemas/BaseCollectionPaginationCountResponse' + - type: object + properties: + value: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.message' + microsoft.graph.ODataErrors.ODataError: + required: + - error + type: object + properties: + error: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.MainError' + microsoft.graph.entity: + title: entity + type: object + properties: + id: + type: string + description: The unique identifier for an entity. Read-only. + microsoft.graph.emailAddress: + title: emailAddress + type: object + properties: + address: + type: string + description: The email address of the person or entity. + nullable: true + name: + type: string + description: The display name of the person or entity. + nullable: true + microsoft.graph.bodyType: + title: bodyType + enum: + - text + - html + type: string + microsoft.graph.dateTimeTimeZone: + title: dateTimeTimeZone + type: object + properties: + dateTime: + type: string + description: 'A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).' + timeZone: + type: string + description: 'Represents a time zone, for example, ''Pacific Standard Time''. See below for more possible values.' + nullable: true + microsoft.graph.followupFlagStatus: + title: followupFlagStatus + enum: + - notFlagged + - complete + - flagged + type: string + BaseCollectionPaginationCountResponse: + title: Base collection pagination and count responses + type: object + properties: + '@odata.nextLink': + type: string + nullable: true + microsoft.graph.ODataErrors.MainError: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + x-ms-primary-error-message: true + target: + type: string + nullable: true + details: + type: array + items: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ErrorDetails' + innerError: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.InnerError' + microsoft.graph.ODataErrors.ErrorDetails: + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + target: + type: string + nullable: true + microsoft.graph.ODataErrors.InnerError: + type: object + description: The structure of this object is service-specific + responses: + microsoft.graph.messageCollectionResponse: + description: Retrieved collection + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.messageCollectionResponse' + error: + description: error + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.ODataErrors.ODataError' + parameters: + top: + name: $top + in: query + description: Show only the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + example: 50 + skip: + name: $skip + in: query + description: Skip the first n items + style: form + explode: false + schema: + minimum: 0 + type: integer + search: + name: $search + in: query + description: Search items by search phrases + style: form + explode: false + schema: + type: string + filter: + name: $filter + in: query + description: Filter items by property values + style: form + explode: false + schema: + type: string + count: + name: $count + in: query + description: Include count of items + style: form + explode: false + schema: + type: boolean \ No newline at end of file diff --git a/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/README.md b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/README.md new file mode 100644 index 000000000000..693a71349a77 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins/README.md @@ -0,0 +1,74 @@ +# Copilot Agent Plugins + +## Generation + +These plugins have been generated thanks to [kiota](https://aka.ms/kiota) and can be regenerated if needed. + +```shell +cd dotnet/samples/Concepts/Resources/Plugins/CopilotAgentPlugins +``` + +### Calendar plugin + +Microsoft Graph calendar events listing API for the current user. + +```shell +kiota plugin add -t APIPlugin -d https://aka.ms/graph/v1.0/openapi.yaml -i /me/calendar/events#GET -o CopilotAgentPlugins/CalendarPlugin +``` + +### Contacts plugin + +Microsoft Graph contacts listing API for the current user. + +```shell +kiota plugin add -t APIPlugin -d https://aka.ms/graph/v1.0/openapi.yaml -i /me/contacts#GET -o CopilotAgentPlugins/ContactsPlugin +``` + +### DriveItem plugin + +Microsoft Graph download a drive item for the current user. + +```shell +kiota plugin add -t APIPlugin -d https://aka.ms/graph/v1.0/openapi.yaml -i /drive/root/children/{driveItem-id}/content#GET -o CopilotAgentPlugins/DriveItemPlugin +``` + +### Messages plugin + +Microsoft Graph list message and create a draft message for the current user. + +```shell +kiota plugin add -t APIPlugin -d https://aka.ms/graph/v1.0/openapi.yaml -i /me/messages#GET -i /me/messages#POST -o CopilotAgentPlugins/MessagesPlugin +``` + +### Astronomy plugin + +NASA Astronomy Picture of the day endpoint mixed with Microsoft Graph messages to demonstrate a plugin with multiple APIs. + +```shell +kiota plugin add -t APIPlugin -d ../OpenAPI/NASA/apod.yaml -i /apod#GET -o CopilotAgentPlugins/AstronomyPlugin +cp CopilotAgentPlugins/MessagesPlugin/messages-openapi.yml CopilotAgentPlugins/AstronomyPlugin +``` + +Add this snippet under runtimes + +```json +{ + "type": "OpenApi", + "auth": { + "type": "None" + }, + "spec": { + "url": "messages-openapi.yml" + }, + "run_for_functions": ["me_ListMessages"] +} +``` + +And this snippet under functions + +```json +{ + "name": "me_ListMessages", + "description": "Get an open extension (openTypeExtension object) identified by name or fully qualified name. The table in the Permissions section lists the resources that support open extensions. The following table lists the three scenarios where you can get an open extension from a supported resource instance." +} +``` diff --git a/dotnet/samples/Concepts/Resources/Plugins/OpenAPI/NASA/apod.yaml b/dotnet/samples/Concepts/Resources/Plugins/OpenAPI/NASA/apod.yaml new file mode 100644 index 000000000000..b1ae4e632975 --- /dev/null +++ b/dotnet/samples/Concepts/Resources/Plugins/OpenAPI/NASA/apod.yaml @@ -0,0 +1,73 @@ +openapi: 3.0.0 +servers: + - url: https://api.nasa.gov/planetary + - url: http://api.nasa.gov/planetary +info: + contact: + email: evan.t.yates@nasa.gov + description: This endpoint structures the APOD imagery and associated metadata + so that it can be repurposed for other applications. In addition, if the + concept_tags parameter is set to True, then keywords derived from the image + explanation are returned. These keywords could be used as auto-generated + hashtags for twitter or instagram feeds; but generally help with + discoverability of relevant imagery + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + title: APOD + version: 1.0.0 + x-apisguru-categories: + - media + - open_data + x-origin: + - format: swagger + url: https://raw.githubusercontent.com/nasa/api-docs/gh-pages/assets/json/APOD + version: "2.0" + x-providerName: nasa.gov + x-serviceName: apod +tags: + - description: An example tag + externalDocs: + description: Here's a link + url: https://example.com + name: request tag +paths: + /apod: + get: + description: Returns the picture of the day + parameters: + - description: The date of the APOD image to retrieve + in: query + name: date + required: false + schema: + type: string + - description: Retrieve the URL for the high resolution image + in: query + name: hd + required: false + schema: + type: boolean + responses: + "200": + content: + application/json: + schema: + items: + x-thing: ok + type: array + description: successful operation + "400": + description: Date must be between Jun 16, 1995 and Mar 28, 2019. + security: + - api_key: [] + summary: Returns images + tags: + - request tag + operationId: apod +components: + securitySchemes: + api_key: + in: query + name: api_key + type: apiKey diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/AssemblyInfo.cs b/dotnet/src/Functions/Functions.OpenApi.Extensions/AssemblyInfo.cs index 2da0381da9f6..a7534ccf9f38 100644 --- a/dotnet/src/Functions/Functions.OpenApi.Extensions/AssemblyInfo.cs +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/AssemblyInfo.cs @@ -3,4 +3,4 @@ using System.Diagnostics.CodeAnalysis; // This assembly is currently experimental. -[assembly: Experimental("SKEXP0043")] +[assembly: Experimental("SKEXP0040")] diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestKernelExtensions.cs b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestKernelExtensions.cs index c4c73d5a0441..dd2447b501a4 100644 --- a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestKernelExtensions.cs +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestKernelExtensions.cs @@ -15,8 +15,10 @@ using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Services; using Microsoft.SemanticKernel.Http; +using Microsoft.SemanticKernel.Plugins.OpenApi; +using Microsoft.SemanticKernel.Plugins.OpenApi.Extensions; -namespace Microsoft.SemanticKernel.Plugins.OpenApi.Extensions; +namespace Microsoft.SemanticKernel; /// /// Provides extension methods for the class related to OpenAPI functionality. /// @@ -73,14 +75,14 @@ public static async Task CreatePluginFromApiManifestAsync( var loggerFactory = kernel.LoggerFactory; var logger = loggerFactory.CreateLogger(typeof(ApiManifestKernelExtensions)) ?? NullLogger.Instance; - string apiManifestFileJsonContents = await DocumentLoader.LoadDocumentFromFilePathAsync(filePath, - logger, - cancellationToken).ConfigureAwait(false); - JsonDocument jsonDocument = JsonDocument.Parse(apiManifestFileJsonContents); + using var apiManifestFileJsonContents = DocumentLoader.LoadDocumentFromFilePathAsStream(filePath, + logger); + JsonDocument jsonDocument = await JsonDocument.ParseAsync(apiManifestFileJsonContents, cancellationToken: cancellationToken).ConfigureAwait(false); ApiManifestDocument document = ApiManifestDocument.Load(jsonDocument.RootElement); var functions = new List(); + var documentWalker = new OpenApiWalker(new OperationIdNormalizationOpenApiVisitor()); foreach (var apiDependency in document.ApiDependencies) { var apiName = apiDependency.Key; @@ -93,19 +95,29 @@ public static async Task CreatePluginFromApiManifestAsync( continue; } - var openApiDocumentString = await DocumentLoader.LoadDocumentFromUriAsync(new Uri(apiDescriptionUrl), - logger, - httpClient, - authCallback: null, - pluginParameters?.UserAgent, - cancellationToken).ConfigureAwait(false); - - OpenApiDiagnostic diagnostic = new(); - var openApiDocument = new OpenApiStringReader(new() + var (parsedDescriptionUrl, isOnlineDescription) = Uri.TryCreate(apiDescriptionUrl, UriKind.Absolute, out var result) ? + (result, true) : + (new Uri(Path.Combine(Path.GetDirectoryName(filePath) ?? string.Empty, apiDescriptionUrl)), false); + + using var openApiDocumentStream = isOnlineDescription ? + await DocumentLoader.LoadDocumentFromUriAsStreamAsync(new Uri(apiDescriptionUrl), + logger, + httpClient, + authCallback: null, + pluginParameters?.UserAgent, + cancellationToken).ConfigureAwait(false) : + DocumentLoader.LoadDocumentFromFilePathAsStream(parsedDescriptionUrl.LocalPath, + logger); + + var documentReadResult = await new OpenApiStreamReader(new() { BaseUrl = new(apiDescriptionUrl) } - ).Read(openApiDocumentString, out diagnostic); + ).ReadAsync(openApiDocumentStream, cancellationToken).ConfigureAwait(false); + var openApiDocument = documentReadResult.OpenApiDocument; + var openApiDiagnostic = documentReadResult.OpenApiDiagnostic; + + documentWalker.Walk(openApiDocument); var requestUrls = new Dictionary>(StringComparer.OrdinalIgnoreCase); var pathMethodPairs = apiDependencyDetails.Requests.Select(request => (request.UriTemplate, request.Method?.ToUpperInvariant())); @@ -128,8 +140,8 @@ public static async Task CreatePluginFromApiManifestAsync( var predicate = OpenApiFilterService.CreatePredicate(null, null, requestUrls, openApiDocument); var filteredOpenApiDocument = OpenApiFilterService.CreateFilteredDocument(openApiDocument, predicate); - var openApiFunctionExecutionParameters = pluginParameters?.FunctionExecutionParameters?.ContainsKey(apiName) == true - ? pluginParameters.FunctionExecutionParameters[apiName] + var openApiFunctionExecutionParameters = pluginParameters?.FunctionExecutionParameters?.TryGetValue(apiName, out var parameters) == true + ? parameters : null; #pragma warning disable CA2000 // Dispose objects before losing scope. No need to dispose the Http client here. It can either be an internal client using NonDisposableHttpClientHandler or an external client managed by the calling code, which should handle its disposal. @@ -144,33 +156,31 @@ public static async Task CreatePluginFromApiManifestAsync( openApiFunctionExecutionParameters?.EnablePayloadNamespacing ?? false); var server = filteredOpenApiDocument.Servers.FirstOrDefault(); - if (server?.Url is not null) + if (server?.Url is null) + { + logger.LogWarning("Server URI not found. Plugin: {0}", pluginName); + continue; + } + var info = OpenApiDocumentParser.ExtractRestApiInfo(filteredOpenApiDocument); + var security = OpenApiDocumentParser.CreateRestApiOperationSecurityRequirements(filteredOpenApiDocument.SecurityRequirements); + foreach (var path in filteredOpenApiDocument.Paths) { - var info = OpenApiDocumentParser.ExtractRestApiInfo(filteredOpenApiDocument); - var security = OpenApiDocumentParser.CreateRestApiOperationSecurityRequirements(filteredOpenApiDocument.SecurityRequirements); - foreach (var path in filteredOpenApiDocument.Paths) + var operations = OpenApiDocumentParser.CreateRestApiOperations(filteredOpenApiDocument, path.Key, path.Value, null, logger); + foreach (RestApiOperation operation in operations) { - var operations = OpenApiDocumentParser.CreateRestApiOperations(filteredOpenApiDocument, path.Key, path.Value, null, logger); - foreach (RestApiOperation operation in operations) + try { - try - { - logger.LogTrace("Registering Rest function {0}.{1}", pluginName, operation.Id); - functions.Add(OpenApiKernelPluginFactory.CreateRestApiFunction(pluginName, runner, info, security, operation, openApiFunctionExecutionParameters, new Uri(server.Url), loggerFactory)); - } - catch (Exception ex) when (!ex.IsCriticalException()) - { - //Logging the exception and keep registering other Rest functions - logger.LogWarning(ex, "Something went wrong while rendering the Rest function. Function: {0}.{1}. Error: {2}", - pluginName, operation.Id, ex.Message); - } + logger.LogTrace("Registering Rest function {0}.{1}", pluginName, operation.Id); + functions.Add(OpenApiKernelPluginFactory.CreateRestApiFunction(pluginName, runner, info, security, operation, openApiFunctionExecutionParameters, new Uri(server.Url), loggerFactory)); + } + catch (Exception ex) when (!ex.IsCriticalException()) + { + //Logging the exception and keep registering other Rest functions + logger.LogWarning(ex, "Something went wrong while rendering the Rest function. Function: {0}.{1}. Error: {2}", + pluginName, operation.Id, ex.Message); } } } - else - { - logger.LogWarning("Server URI not found. Plugin: {0}", pluginName); - } } return KernelPluginFactory.CreateFromFunctions(pluginName, null, functions); diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestPluginParameters.cs b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestPluginParameters.cs index ec86f2e6d14d..07cc11819eea 100644 --- a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestPluginParameters.cs +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestPluginParameters.cs @@ -7,7 +7,7 @@ namespace Microsoft.SemanticKernel.Plugins.OpenApi.Extensions; /// /// API manifest plugin parameters. /// -public class ApiManifestPluginParameters +public sealed class ApiManifestPluginParameters { /// /// Gets the HTTP client to be used in plugin initialization phase. diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/CopilotAgentPluginKernelExtensions.cs b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/CopilotAgentPluginKernelExtensions.cs new file mode 100644 index 000000000000..e9e401ff2960 --- /dev/null +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/CopilotAgentPluginKernelExtensions.cs @@ -0,0 +1,189 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.OpenApi.Readers; +using Microsoft.OpenApi.Services; +using Microsoft.Plugins.Manifest; +using Microsoft.SemanticKernel.Http; +using Microsoft.SemanticKernel.Plugins.OpenApi; +using Microsoft.SemanticKernel.Plugins.OpenApi.Extensions; + +namespace Microsoft.SemanticKernel; +/// +/// Provides extension methods for the class related to OpenAPI functionality. +/// +public static class CopilotAgentPluginKernelExtensions +{ + /// + /// Imports a plugin from an Copilot Agent Plugin asynchronously. + /// + /// The kernel instance. + /// The name of the plugin. + /// The file path of the Copilot Agent Plugin. + /// Optional parameters for the plugin setup. + /// Optional cancellation token. + /// The imported plugin. + public static async Task ImportPluginFromCopilotAgentPluginAsync( + this Kernel kernel, + string pluginName, + string filePath, + CopilotAgentPluginParameters? pluginParameters = null, + CancellationToken cancellationToken = default) + { + KernelPlugin plugin = await kernel.CreatePluginFromCopilotAgentPluginAsync(pluginName, filePath, pluginParameters, cancellationToken).ConfigureAwait(false); + kernel.Plugins.Add(plugin); + return plugin; + } + + /// + /// Creates a kernel plugin from an Copilot Agent Plugin file asynchronously. + /// + /// The kernel instance. + /// The name of the plugin. + /// The file path of the Copilot Agent Plugin. + /// Optional parameters for the plugin setup. + /// Optional cancellation token. + /// A task that represents the asynchronous operation. The task result contains the created kernel plugin. + public static async Task CreatePluginFromCopilotAgentPluginAsync( + this Kernel kernel, + string pluginName, + string filePath, + CopilotAgentPluginParameters? pluginParameters = null, + CancellationToken cancellationToken = default) + { + Verify.NotNull(kernel); + Verify.ValidPluginName(pluginName, kernel.Plugins); + +#pragma warning disable CA2000 // Dispose objects before losing scope. No need to dispose the Http client here. It can either be an internal client using NonDisposableHttpClientHandler or an external client managed by the calling code, which should handle its disposal. + var httpClient = HttpClientProvider.GetHttpClient(pluginParameters?.HttpClient ?? kernel.Services.GetService()); +#pragma warning restore CA2000 + + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"CopilotAgent file not found: {filePath}"); + } + + var loggerFactory = kernel.LoggerFactory; + var logger = loggerFactory.CreateLogger(typeof(CopilotAgentPluginKernelExtensions)) ?? NullLogger.Instance; + using var CopilotAgentFileJsonContents = DocumentLoader.LoadDocumentFromFilePathAsStream(filePath, + logger); + + var results = await PluginManifestDocument.LoadAsync(CopilotAgentFileJsonContents, new ReaderOptions + { + ValidationRules = new() // Disable validation rules + }).ConfigureAwait(false); + + if (!results.IsValid) + { + var messages = results.Problems.Select(p => p.Message).Aggregate((a, b) => $"{a}, {b}"); + throw new InvalidOperationException($"Error loading the manifest: {messages}"); + } + + var document = results.Document; + var openAPIRuntimes = document?.Runtimes?.Where(runtime => runtime.Type == RuntimeType.OpenApi).ToList(); + if (openAPIRuntimes is null || openAPIRuntimes.Count == 0) + { + throw new InvalidOperationException("No OpenAPI runtimes found in the manifest."); + } + + var functions = new List(); + var documentWalker = new OpenApiWalker(new OperationIdNormalizationOpenApiVisitor()); + foreach (var runtime in openAPIRuntimes) + { + var manifestFunctions = document?.Functions?.Where(f => runtime.RunForFunctions.Contains(f.Name)).ToList(); + if (manifestFunctions is null || manifestFunctions.Count == 0) + { + logger.LogWarning("No functions found in the runtime object."); + continue; + } + + var openApiRuntime = runtime as OpenApiRuntime; + var apiDescriptionUrl = openApiRuntime?.Spec?.Url ?? string.Empty; + if (apiDescriptionUrl.Length == 0) + { + logger.LogWarning("No API description URL found in the runtime object."); + continue; + } + + var (parsedDescriptionUrl, isOnlineDescription) = Uri.TryCreate(apiDescriptionUrl, UriKind.Absolute, out var result) ? + (result, true) : + (new Uri(Path.Combine(Path.GetDirectoryName(filePath) ?? string.Empty, apiDescriptionUrl)), false); + + using var openApiDocumentStream = isOnlineDescription ? + await DocumentLoader.LoadDocumentFromUriAsStreamAsync(parsedDescriptionUrl, + logger, + httpClient, + authCallback: null, + pluginParameters?.UserAgent, + cancellationToken).ConfigureAwait(false) : + DocumentLoader.LoadDocumentFromFilePathAsStream(parsedDescriptionUrl.LocalPath, + logger); + + var documentReadResult = await new OpenApiStreamReader(new() + { + BaseUrl = parsedDescriptionUrl + } + ).ReadAsync(openApiDocumentStream, cancellationToken).ConfigureAwait(false); + var openApiDocument = documentReadResult.OpenApiDocument; + var openApiDiagnostic = documentReadResult.OpenApiDiagnostic; + + documentWalker.Walk(openApiDocument); + + var predicate = OpenApiFilterService.CreatePredicate(string.Join(",", manifestFunctions.Select(static f => f.Name)), null, null, openApiDocument); + var filteredOpenApiDocument = OpenApiFilterService.CreateFilteredDocument(openApiDocument, predicate); + + var server = filteredOpenApiDocument.Servers.FirstOrDefault(); + if (server?.Url is null) + { + logger.LogWarning("Server URI not found. Plugin: {0}", pluginName); + continue; + } + + var openApiFunctionExecutionParameters = pluginParameters?.FunctionExecutionParameters?.TryGetValue(server.Url, out var parameters) == true + ? parameters + : null; + +#pragma warning disable CA2000 // Dispose objects before losing scope. No need to dispose the Http client here. It can either be an internal client using NonDisposableHttpClientHandler or an external client managed by the calling code, which should handle its disposal. + var operationRunnerHttpClient = HttpClientProvider.GetHttpClient(openApiFunctionExecutionParameters?.HttpClient ?? kernel.Services.GetService()); +#pragma warning restore CA2000 + + var runner = new RestApiOperationRunner( + operationRunnerHttpClient, + openApiFunctionExecutionParameters?.AuthCallback, + openApiFunctionExecutionParameters?.UserAgent, + openApiFunctionExecutionParameters?.EnableDynamicPayload ?? true, + openApiFunctionExecutionParameters?.EnablePayloadNamespacing ?? false); + + var info = OpenApiDocumentParser.ExtractRestApiInfo(filteredOpenApiDocument); + var security = OpenApiDocumentParser.CreateRestApiOperationSecurityRequirements(filteredOpenApiDocument.SecurityRequirements); + foreach (var path in filteredOpenApiDocument.Paths) + { + var operations = OpenApiDocumentParser.CreateRestApiOperations(filteredOpenApiDocument, path.Key, path.Value, null, logger); + foreach (RestApiOperation operation in operations) + { + try + { + logger.LogTrace("Registering Rest function {0}.{1}", pluginName, operation.Id); + functions.Add(OpenApiKernelPluginFactory.CreateRestApiFunction(pluginName, runner, info, security, operation, openApiFunctionExecutionParameters, new Uri(server.Url), loggerFactory)); + } + catch (Exception ex) when (!ex.IsCriticalException()) + { + //Logging the exception and keep registering other Rest functions + logger.LogWarning(ex, "Something went wrong while rendering the Rest function. Function: {0}.{1}. Error: {2}", + pluginName, operation.Id, ex.Message); + } + } + } + } + return KernelPluginFactory.CreateFromFunctions(pluginName, null, functions); + } +} diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/CopilotAgentPluginParameters.cs b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/CopilotAgentPluginParameters.cs new file mode 100644 index 000000000000..7c352a1a6f87 --- /dev/null +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/CopilotAgentPluginParameters.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Collections.Generic; +using System.Net.Http; + +namespace Microsoft.SemanticKernel.Plugins.OpenApi.Extensions; + +/// +/// Copilot Agent Plugin parameters. +/// +public sealed class CopilotAgentPluginParameters +{ + /// + /// Gets the HTTP client to be used in plugin initialization phase. + /// + public HttpClient? HttpClient { get; init; } + + /// + /// Gets the user agent to be used in plugin initialization phase. + /// + public string? UserAgent { get; init; } + + /// + /// A map of function execution parameters, where the key is the api dependency key from api manifest + /// and the value is OpenApiFunctionExecutionParameters specific to that dependency. + /// + public Dictionary? FunctionExecutionParameters { get; init; } +} diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/OperationIdNormalizationOpenApiVisitor.cs b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/OperationIdNormalizationOpenApiVisitor.cs new file mode 100644 index 000000000000..e8ed169db7c2 --- /dev/null +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/OperationIdNormalizationOpenApiVisitor.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Services; + +namespace Microsoft.SemanticKernel.Plugins.OpenApi.Extensions; + +/// +/// An OpenAPI visitor that normalizes the operation IDs by replacing dots with underscores. +/// So that the operation IDs can be used as function names in semantic kernel. +/// +internal sealed class OperationIdNormalizationOpenApiVisitor : OpenApiVisitorBase +{ + public override void Visit(OpenApiOperation operation) + { + if (operation is null || operation.OperationId is null) + { + return; + } + operation.OperationId = operation.OperationId.Replace('.', '_'); + } +} diff --git a/dotnet/src/Functions/Functions.OpenApi.Extensions/Functions.OpenApi.Extensions.csproj b/dotnet/src/Functions/Functions.OpenApi.Extensions/Functions.OpenApi.Extensions.csproj index 8f0d11b0f09a..28a8ef5136b0 100644 --- a/dotnet/src/Functions/Functions.OpenApi.Extensions/Functions.OpenApi.Extensions.csproj +++ b/dotnet/src/Functions/Functions.OpenApi.Extensions/Functions.OpenApi.Extensions.csproj @@ -15,6 +15,7 @@ + diff --git a/dotnet/src/Functions/Functions.OpenApi/DocumentLoader.cs b/dotnet/src/Functions/Functions.OpenApi/DocumentLoader.cs index 9fbafff79ca3..5138066f6711 100644 --- a/dotnet/src/Functions/Functions.OpenApi/DocumentLoader.cs +++ b/dotnet/src/Functions/Functions.OpenApi/DocumentLoader.cs @@ -20,6 +20,32 @@ internal static async Task LoadDocumentFromUriAsync( AuthenticateRequestAsyncCallback? authCallback, string? userAgent, CancellationToken cancellationToken) + { + using var response = await LoadDocumentResponseFromUriAsync(uri, logger, httpClient, authCallback, userAgent, cancellationToken).ConfigureAwait(false); + return await response.Content.ReadAsStringWithExceptionMappingAsync().ConfigureAwait(false); + } + + internal static async Task LoadDocumentFromUriAsStreamAsync( + Uri uri, + ILogger logger, + HttpClient httpClient, + AuthenticateRequestAsyncCallback? authCallback, + string? userAgent, + CancellationToken cancellationToken) + { + //disposing the response disposes the stream + var response = await LoadDocumentResponseFromUriAsync(uri, logger, httpClient, authCallback, userAgent, cancellationToken).ConfigureAwait(false); + var stream = await response.Content.ReadAsStreamAndTranslateExceptionAsync().ConfigureAwait(false); + return new HttpResponseStream(stream, response); + } + + private static async Task LoadDocumentResponseFromUriAsync( + Uri uri, + ILogger logger, + HttpClient httpClient, + AuthenticateRequestAsyncCallback? authCallback, + string? userAgent, + CancellationToken cancellationToken) { using var request = new HttpRequestMessage(HttpMethod.Get, uri.ToString()); request.Headers.UserAgent.Add(ProductInfoHeaderValue.Parse(userAgent ?? HttpHeaderConstant.Values.UserAgent)); @@ -31,8 +57,7 @@ internal static async Task LoadDocumentFromUriAsync( logger.LogTrace("Importing document from '{Uri}'", uri); - using var response = await httpClient.SendWithSuccessCheckAsync(request, cancellationToken).ConfigureAwait(false); - return await response.Content.ReadAsStringWithExceptionMappingAsync().ConfigureAwait(false); + return await httpClient.SendWithSuccessCheckAsync(request, cancellationToken).ConfigureAwait(false); } internal static async Task LoadDocumentFromFilePathAsync( @@ -42,14 +67,7 @@ internal static async Task LoadDocumentFromFilePathAsync( { cancellationToken.ThrowIfCancellationRequested(); - var pluginJson = string.Empty; - - if (!File.Exists(filePath)) - { - var exception = new FileNotFoundException($"Invalid file path. The specified path '{filePath}' does not exist."); - logger.LogError(exception, "Invalid file path. The specified path '{FilePath}' does not exist.", filePath); - throw exception; - } + CheckIfFileExists(filePath, logger); logger.LogTrace("Importing document from '{FilePath}'", filePath); @@ -61,9 +79,36 @@ internal static async Task LoadDocumentFromFilePathAsync( ).ConfigureAwait(false); } - internal static async Task LoadDocumentFromStreamAsync(Stream stream) + private static void CheckIfFileExists(string filePath, ILogger logger) + { + if (!File.Exists(filePath)) + { + var exception = new FileNotFoundException($"Invalid file path. The specified path '{filePath}' does not exist."); + logger.LogError(exception, "Invalid file path. The specified path '{FilePath}' does not exist.", filePath); + throw exception; + } + } + + internal static Stream LoadDocumentFromFilePathAsStream( + string filePath, + ILogger logger) + { + CheckIfFileExists(filePath, logger); + + logger.LogTrace("Importing document from {0}", filePath); + + return File.OpenRead(filePath); + } + + internal static async Task LoadDocumentFromStreamAsync( + Stream stream, + CancellationToken cancellationToken) { using StreamReader reader = new(stream); +#if NET7_0_OR_GREATER + return await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); +#else return await reader.ReadToEndAsync().ConfigureAwait(false); +#endif } } diff --git a/dotnet/src/Functions/Functions.OpenApi/Extensions/OpenApiKernelExtensions.cs b/dotnet/src/Functions/Functions.OpenApi/Extensions/OpenApiKernelExtensions.cs index 41e32e0ae7a6..48f72a697a4a 100644 --- a/dotnet/src/Functions/Functions.OpenApi/Extensions/OpenApiKernelExtensions.cs +++ b/dotnet/src/Functions/Functions.OpenApi/Extensions/OpenApiKernelExtensions.cs @@ -207,7 +207,7 @@ public static async Task CreatePluginFromOpenApiAsync( var httpClient = HttpClientProvider.GetHttpClient(executionParameters?.HttpClient ?? kernel.Services.GetService()); #pragma warning restore CA2000 - var openApiSpec = await DocumentLoader.LoadDocumentFromStreamAsync(stream).ConfigureAwait(false); + var openApiSpec = await DocumentLoader.LoadDocumentFromStreamAsync(stream, cancellationToken).ConfigureAwait(false); return await CreateOpenApiPluginAsync( kernel, diff --git a/dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs b/dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs index 317f9c809ca2..49f42451ee40 100644 --- a/dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs +++ b/dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs @@ -189,6 +189,7 @@ internal static List CreateRestApiOperations(OpenApiDocument d try { var operations = new List(); + var operationServers = CreateRestApiOperationServers(document.Servers); foreach (var operationPair in pathItem.Operations) { @@ -204,13 +205,13 @@ internal static List CreateRestApiOperations(OpenApiDocument d var operation = new RestApiOperation( id: operationItem.OperationId, - servers: CreateRestApiOperationServers(document.Servers), + servers: operationServers, path: path, method: new HttpMethod(method), description: string.IsNullOrEmpty(operationItem.Description) ? operationItem.Summary : operationItem.Description, parameters: CreateRestApiOperationParameters(operationItem.OperationId, operationItem.Parameters), payload: CreateRestApiOperationPayload(operationItem.OperationId, operationItem.RequestBody), - responses: CreateRestApiOperationExpectedResponses(operationItem.Responses).ToDictionary(item => item.Item1, item => item.Item2), + responses: CreateRestApiOperationExpectedResponses(operationItem.Responses).ToDictionary(static item => item.Item1, static item => item.Item2), securityRequirements: CreateRestApiOperationSecurityRequirements(operationItem.Security) ) { diff --git a/dotnet/src/Functions/Functions.OpenApi/OpenApiKernelPluginFactory.cs b/dotnet/src/Functions/Functions.OpenApi/OpenApiKernelPluginFactory.cs index 5432368c6e71..f46d39e681f2 100644 --- a/dotnet/src/Functions/Functions.OpenApi/OpenApiKernelPluginFactory.cs +++ b/dotnet/src/Functions/Functions.OpenApi/OpenApiKernelPluginFactory.cs @@ -121,7 +121,7 @@ public static async Task CreateFromOpenApiAsync( var httpClient = HttpClientProvider.GetHttpClient(executionParameters?.HttpClient); #pragma warning restore CA2000 - var openApiSpec = await DocumentLoader.LoadDocumentFromStreamAsync(stream).ConfigureAwait(false); + var openApiSpec = await DocumentLoader.LoadDocumentFromStreamAsync(stream, cancellationToken).ConfigureAwait(false); return await CreateOpenApiPluginAsync( pluginName,