diff --git a/.gitignore b/.gitignore index 2c183ddde3..59d3fefd21 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,16 @@ # Build results [Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +ecf/ +rcf/ bones/ .vs/ @@ -19,4 +29,4 @@ bones/ .config/ # Python virtual environments -**/*env/ \ No newline at end of file +**/*env/ diff --git a/schemas/skills/SchemaManifestTests/SchemaManifestTests.csproj b/schemas/skills/SchemaManifestTests/SchemaManifestTests.csproj new file mode 100644 index 0000000000..69029b71c9 --- /dev/null +++ b/schemas/skills/SchemaManifestTests/SchemaManifestTests.csproj @@ -0,0 +1,25 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/schemas/skills/SchemaManifestTests/SchemaManifestTests.sln b/schemas/skills/SchemaManifestTests/SchemaManifestTests.sln new file mode 100644 index 0000000000..47f561e1e2 --- /dev/null +++ b/schemas/skills/SchemaManifestTests/SchemaManifestTests.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31409.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchemaManifestTests", "SchemaManifestTests.csproj", "{53609E6C-0C2C-4DB2-864C-628BE29495E4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {53609E6C-0C2C-4DB2-864C-628BE29495E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53609E6C-0C2C-4DB2-864C-628BE29495E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53609E6C-0C2C-4DB2-864C-628BE29495E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53609E6C-0C2C-4DB2-864C-628BE29495E4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DB082524-0CE2-4C94-BA0E-A9FFDBE8EE42} + EndGlobalSection +EndGlobal diff --git a/schemas/skills/SchemaManifestTests/ValidateSchemaTests.cs b/schemas/skills/SchemaManifestTests/ValidateSchemaTests.cs new file mode 100644 index 0000000000..29538bdc15 --- /dev/null +++ b/schemas/skills/SchemaManifestTests/ValidateSchemaTests.cs @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; +using NJsonSchema; +using NJsonSchema.Generation; +using Xunit; +using JsonSchema = NJsonSchema.JsonSchema; +using JsonSchemaResolver = NJsonSchema.Generation.JsonSchemaResolver; + +namespace SchemaManifestTests +{ + /// + /// Validates sample manifests against schemas. + /// + /// + /// There are some differences on the validation provided by Newtonsoft and NJsonSchema so we use both libraries in the tests + /// to ensure better compatibility. + /// + public class ValidateSchemaTests + { + // List of schema version folders to test. + private static readonly List _schemaVersionFolders = new List + { + "v2.0", + "v2.1", + "v2.2" + }; + + // Path to the folder containing the schema files and samples (relative to where the test is executing). + private static readonly string _schemasRootFolder = Path.Combine(Directory.GetCurrentDirectory(), "../../../../"); + + /// + /// Builds the list of manifest schemas and samples to validate from the file system. + /// + public static TheoryData GetManifestAndSamples() + { + var manifestAndSamples = new TheoryData(); + + foreach (var schemaVersion in _schemaVersionFolders) + { + var schemaFolder = Path.Combine(_schemasRootFolder, schemaVersion); + var samplesFolder = Path.Combine(schemaFolder, "Samples"); + var sampleManifestFiles = Directory.GetFileSystemEntries(samplesFolder, "*.json", SearchOption.AllDirectories); + foreach (var manifestFile in sampleManifestFiles) + { + var manifestRelativePath = Path.GetRelativePath(schemaFolder, manifestFile); + manifestAndSamples.Add(schemaVersion, manifestRelativePath); + } + } + + return manifestAndSamples; + } + + [Theory] + [MemberData(nameof(GetManifestAndSamples))] + public async Task ValidateManifestSamplesAgainstSchemasUsingNJsonSchemaAsync(string schemaVersion, string sampleManifest) + { + // Arrange + var manifestSchemaPath = Path.Combine(_schemasRootFolder, schemaVersion, "skill-manifest.json"); + var manifestSchema = await GetSchemaAsync(manifestSchemaPath); + + var sampleManifestPath = Path.Combine(_schemasRootFolder, schemaVersion, sampleManifest); + var sampleManifestText = await File.ReadAllTextAsync(sampleManifestPath); + + // Act + var validationErrors = manifestSchema.Validate(sampleManifestText); + + // Assert + Assert.Empty(validationErrors); + } + + [Theory] + [MemberData(nameof(GetManifestAndSamples))] + public async Task ValidateManifestSamplesAgainstSchemasUsingNewtonsoftSchemaAsync(string schemaVersion, string sampleManifest) + { + // Note: you can use https://www.jsonschemavalidator.net/ for an interactive version. + + // Arrange + var manifestSchemaPath = Path.Combine(_schemasRootFolder, schemaVersion, "skill-manifest.json"); + var manifestSchema = JSchema.Parse(await File.ReadAllTextAsync(manifestSchemaPath), new JSchemaUrlResolver()); + + var sampleManifestPath = Path.Combine(_schemasRootFolder, schemaVersion, sampleManifest); + var json = JToken.Parse(await File.ReadAllTextAsync(sampleManifestPath)); + + // Act + json.IsValid(manifestSchema, out IList validationErrors); + + // Assert + Assert.Empty(validationErrors); + } + + private static async Task GetSchemaAsync(string schemaPath) + { + var rawSchemaText = await File.ReadAllTextAsync(schemaPath); + + return await JsonSchema.FromJsonAsync(rawSchemaText, null, x => + { + var schemaResolver = new JsonSchemaResolver(x, new JsonSchemaGeneratorSettings()); + var referenceResolver = new JsonReferenceResolver(schemaResolver); + referenceResolver.AddDocumentReference("http://json-schema.org/draft-07/schema", JsonSchema.CreateAnySchema()); + + return referenceResolver; + }); + } + } +} diff --git a/schemas/skills/readme.md b/schemas/skills/readme.md index 40d96bf0e4..81d744f25d 100644 --- a/schemas/skills/readme.md +++ b/schemas/skills/readme.md @@ -10,7 +10,7 @@ The skill manifest JSON schema is published at: Example: -`https://schemas.botframework.com/schemas/skills/v2.1/skill-manifest.json` +`https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json` You should use the published version when referencing this schema. diff --git a/schemas/skills/v2.1/skill-manifest.json b/schemas/skills/v2.1/skill-manifest.json index 0ed5345428..116615a8de 100644 --- a/schemas/skills/v2.1/skill-manifest.json +++ b/schemas/skills/v2.1/skill-manifest.json @@ -1,7 +1,7 @@ { "$id": "https://schemas.botframework.com/schemas/skills/v2.1/skill-manifest.json", "$schema": "http://json-schema.org/draft-07/schema#", - "$version": "2.1.0", + "$version": "2.1.1", "title": "Skill Manifest Schema", "description": "A schema for Bot Framework skill manifests", "type": "object", @@ -206,8 +206,11 @@ "properties": { "type": { "type": "string", + "title": "Activity Type", "description": "The activity type", - "const": "event" + "enum": [ + "event" + ] }, "name": { "type": "string", @@ -245,8 +248,11 @@ "properties": { "type": { "type": "string", + "title": "Activity Type", "description": "The activity type", - "const": "invoke" + "enum": [ + "invoke" + ] }, "name": { "type": "string", @@ -284,8 +290,9 @@ "type": { "type": "string", "description": "The activity type", - "const": "message", - "default": "message" + "enum": [ + "message" + ] }, "description": { "type": "string", @@ -315,11 +322,8 @@ "type": { "type": "string", "title": "Activity Type", - "description": "Contains the activity type (message, event, invoke, etc.)", + "description": "The activity type", "enum": [ - "message", - "event", - "invoke", "messageReaction", "endOfConversation", "handoff", @@ -332,8 +336,7 @@ "deleteUserData", "messageUpdate", "messageDelete" - ], - "pattern":"^(?!(message|event|invoke)$)((messageReaction|endOfConversation|handoff|typing|conversationUpdate|trace|installationUpdate|contactRelationUpdate|suggestion|deleteUserData|messageUpdate|messageDelete)$)" + ] } }, "additionalProperties": true @@ -369,4 +372,4 @@ "additionalProperties": false } } -} \ No newline at end of file +} diff --git a/schemas/skills/v2.2/samples/complex-pva-manifest.json b/schemas/skills/v2.2/samples/complex-pva-manifest.json new file mode 100644 index 0000000000..f8c1bc5e96 --- /dev/null +++ b/schemas/skills/v2.2/samples/complex-pva-manifest.json @@ -0,0 +1,164 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json", + "$id": "SkillBot", + "name": "Sample skill definition that can handle multiple types of activities", + "version": "1.0", + "description": "This is a sample skill definition for multiple activity types", + "publisherName": "Microsoft", + "privacyUrl": "https://myskill.contoso.com/privacy.html", + "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.", + "license": "", + "iconUrl": "https://myskill.contoso.com/icon.png", + "tags": [ + "sample", + "travel", + "weather" + ], + "endpoints": [ + { + "name": "americas", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot in the Americas", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "00000000-0000-0000-0000-000000000000" + } + ], + "dispatchModels": { + "languages": { + "en": [ + { + "name": "SkillBot LU (English)", + "contentType": "application/lu", + "url": "http://sample.com/SkillBot-en.lu", + "description": "English language model for the skill" + }, + { + "name": "SkillBot QnA LU (English)", + "contentType": "application/qna", + "url": "http://sample.com/SkillBot-QnA-en.qna", + "description": "English language model for the skill (QnAMaker)" + } + ] + }, + "intents": [ + "bookFlight", + "getWeather" + ] + }, + "activities": { + "bookFlight": { + "description": "Books a flight", + "type": "event", + "name": "BookFlight", + "value": { + "$ref": "#/definitions/bookingInfo" + }, + "resultValue": { + "$ref": "#/definitions/bookingInfo" + } + }, + "getWeather": { + "description": "Retrieves and returns the weather for the user's location", + "type": "invoke", + "name": "GetWeather", + "value": { + "$ref": "#/definitions/location" + }, + "resultValue": { + "$ref": "#/definitions/weatherReport" + } + }, + "message": { + "type": "message", + "description": "Receives the user's' utterance and attempts to resolve it using the skill's LU models" + }, + "typing": { + "type": "typing" + }, + "conversationUpdate": { + "type": "conversationUpdate" + } + }, + "definitions": { + "localeValue": { + "type": "object", + "properties": { + "locale": { + "type": "string", + "description": "The current user's locale ISO code" + } + } + }, + "bookingInfo": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "this is the origin city for the flight" + }, + "destination": { + "type": "string", + "description": "this is the destination city for the flight" + }, + "date": { + "type": "string", + "description": "The date for the flight in YYYY-MM-DD format" + } + } + }, + "weatherReport": { + "type": "array", + "description": "Array of forecasts for the next week.", + "items": [ + { + "type": "string" + } + ] + }, + "location": { + "type": "object", + "description": "Location metadata", + "properties": { + "latitude": { + "type": "number", + "title": "Latitude" + }, + "longitude": { + "type": "number", + "title": "Longitude" + }, + "postalCode": { + "type": "string", + "title": "Postal code" + } + } + } + }, + "activitiesSent": { + "flightUpdated": { + "type": "event", + "name": "FlightUpdated", + "description": "Event which is sent by the skill when there is an update in flight info", + "value": { + "type": "object", + "description": "Flight update information", + "properties": { + "flightNumber": { + "type": "string" + }, + "departureDate": { + "type": "string", + "description": "The departure date for the flight in YYYY-MM-DD format" + }, + "departureTime": { + "type": "string", + "description": "The departure time for the flight in HH-MM format" + } + } + } + } + } +} diff --git a/schemas/skills/v2.2/samples/complex-skillmanifest.json b/schemas/skills/v2.2/samples/complex-skillmanifest.json new file mode 100644 index 0000000000..854857a21a --- /dev/null +++ b/schemas/skills/v2.2/samples/complex-skillmanifest.json @@ -0,0 +1,199 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json", + "$id": "SkillBot", + "name": "Sample skill definition that can handle multiple types of activities", + "version": "1.0", + "description": "This is a sample skill definition for multiple activity types", + "publisherName": "Microsoft", + "privacyUrl": "https://myskill.contoso.com/privacy.html", + "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.", + "license": "", + "iconUrl": "skillIcon.png", + "tags": [ + "sample", + "travel", + "weather" + ], + "endpoints": [ + { + "name": "americas", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot in the Americas", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "00000000-0000-0000-0000-000000000000" + }, + { + "name": "eu", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot in Europe", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "11111111-0000-0000-0000-000000000000" + } + ], + "dispatchModels": { + "languages": { + "en": [ + { + "name": "SkillBot LU (English)", + "contentType": "application/lu", + "url": "http://sample.com/SkillBot-en.lu", + "description": "English language model for the skill" + }, + { + "name": "SkillBot QnA LU (English)", + "contentType": "application/qna", + "url": "http://sample.com/SkillBot-QnA-en.qna", + "description": "English language model for the skill (QnAMaker)" + } + ], + "es-ES": [ + { + "name": "SkillBot LU (Spanish-Spain)", + "contentType": "application/lu", + "url": "http://sample.com/SkillBot-es-ES.lu", + "description": "Spanish (Spain) language model for the skill" + }, + { + "name": "SkillBot QnA LU (Spanish-Spain)", + "contentType": "application/qna", + "url": "http://sample.com/SkillBot-QnA-es-ES.qna", + "description": "Spanish (Spain) language model for the skill (QnAMaker)" + } + ], + "es-MX": [ + { + "name": "SkillBot LU (Spanish-Mexico)", + "contentType": "application/lu", + "url": "http://sample.com/SkillBot-es-MX.lu", + "description": "Spanish (Mexico) language model for the skill" + }, + { + "name": "SkillBot QnA LU (Spanish-Mexico)", + "contentType": "application/qna", + "url": "http://sample.com/SkillBot-QnA-es-MX.qna", + "description": "Spanish (Mexico) language model for the skill (QnAMaker)" + } + ] + }, + "intents": [ + "bookFlight", + "getWeather" + ] + }, + "activities": { + "bookFlight": { + "description": "Books a flight", + "type": "event", + "name": "BookFlight", + "value": { + "$ref": "#/definitions/bookingInfo" + }, + "resultValue": { + "$ref": "#/definitions/bookingInfo" + } + }, + "getWeather": { + "description": "Retrieves and returns the weather for the user's location", + "type": "invoke", + "name": "GetWeather", + "value": { + "$ref": "#/definitions/location" + }, + "resultValue": { + "$ref": "#/definitions/weatherReport" + } + }, + "message": { + "type": "message", + "description": "Receives the user's' utterance and attempts to resolve it using the skill's LU models" + }, + "typing": { + "type": "typing" + }, + "conversationUpdate": { + "type": "conversationUpdate" + } + }, + "definitions": { + "localeValue": { + "type": "object", + "properties": { + "locale": { + "type": "string", + "description": "The current user's locale ISO code" + } + } + }, + "bookingInfo": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "this is the origin city for the flight" + }, + "destination": { + "type": "string", + "description": "this is the destination city for the flight" + }, + "date": { + "type": "string", + "description": "The date for the flight in YYYY-MM-DD format" + } + } + }, + "weatherReport": { + "type": "array", + "description": "Array of forecasts for the next week.", + "items": [ + { + "type": "string" + } + ] + }, + "location": { + "type": "object", + "description": "Location metadata", + "properties": { + "latitude": { + "type": "number", + "title": "Latitude" + }, + "longitude": { + "type": "number", + "title": "Longitude" + }, + "postalCode": { + "type": "string", + "title": "Postal code" + } + } + } + }, + "activitiesSent": { + "flightUpdated": { + "type": "event", + "name": "FlightUpdated", + "description": "Event which is sent by the skill when there is an update in flight info", + "value": { + "type": "object", + "description": "Flight update information", + "properties": { + "flightNumber": { + "type": "string" + }, + "departureDate": { + "type": "string", + "description": "The departure date for the flight in YYYY-MM-DD format" + }, + "departureTime": { + "type": "string", + "description": "The departure time for the flight in HH-MM format" + } + } + } + } + } +} diff --git a/schemas/skills/v2.2/samples/echo-skillmanifest.json b/schemas/skills/v2.2/samples/echo-skillmanifest.json new file mode 100644 index 0000000000..760cf0252c --- /dev/null +++ b/schemas/skills/v2.2/samples/echo-skillmanifest.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json", + "$id": "EchoSkill", + "name": "Echo skill", + "version": "1.0", + "description": "This skill echoes whatever the user says", + "publisherName": "Microsoft", + "privacyUrl": "https://myskill.contoso.com/privacy.html", + "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.", + "license": "", + "iconUrl": "https://myskill.contoso.com/icon.png", + "tags": [ + "sample", + "echo" + ], + "endpoints": [ + { + "name": "default", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot.", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "a0000f00-Ad00-a000-a000-a0000aaaAaa0" + } + ], + "activities": { + "message": { + "type": "message", + "description": "A message activity containing the utterance that the skill will echo back to the user" + } + } +} diff --git a/schemas/skills/v2.2/samples/relativeUris/complex-skillmanifest.json b/schemas/skills/v2.2/samples/relativeUris/complex-skillmanifest.json new file mode 100644 index 0000000000..e0f74ee152 --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/complex-skillmanifest.json @@ -0,0 +1,199 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json", + "$id": "SkillBot", + "name": "Sample skill definition that can handle multiple types of activities", + "version": "1.0", + "description": "This is a sample skill definition for multiple activity types", + "publisherName": "Microsoft", + "privacyUrl": "privacy.html", + "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.", + "license": "", + "iconUrl": "skillIcon.png", + "tags": [ + "sample", + "travel", + "weather" + ], + "endpoints": [ + { + "name": "americas", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot in the Americas", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "00000000-0000-0000-0000-000000000000" + }, + { + "name": "eu", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot in Europe", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "11111111-0000-0000-0000-000000000000" + } + ], + "dispatchModels": { + "languages": { + "en": [ + { + "name": "SkillBot LU (English)", + "contentType": "application/lu", + "url": "language-understanding/SkillBot-en.lu", + "description": "English language model for the skill" + }, + { + "name": "SkillBot QnA LU (English)", + "contentType": "application/qna", + "url": "knowledge-base/SkillBot-QnA-en.qna", + "description": "English language model for the skill (QnAMaker)" + } + ], + "es-ES": [ + { + "name": "SkillBot LU (Spanish-Spain)", + "contentType": "application/lu", + "url": "language-understanding/SkillBot-es-ES.lu", + "description": "Spanish (Spain) language model for the skill" + }, + { + "name": "SkillBot QnA LU (Spanish-Spain)", + "contentType": "application/qna", + "url": "knowledge-base/SkillBot-QnA-es-ES.qna", + "description": "Spanish (Spain) language model for the skill (QnAMaker)" + } + ], + "es-MX": [ + { + "name": "SkillBot LU (Spanish-Mexico)", + "contentType": "application/lu", + "url": "language-understanding/SkillBot-es-MX.lu", + "description": "Spanish (Mexico) language model for the skill" + }, + { + "name": "SkillBot QnA LU (Spanish-Mexico)", + "contentType": "application/qna", + "url": "knowledge-base/SkillBot-QnA-es-MX.qna", + "description": "Spanish (Mexico) language model for the skill (QnAMaker)" + } + ] + }, + "intents": [ + "bookFlight", + "getWeather" + ] + }, + "activities": { + "bookFlight": { + "description": "Books a flight", + "type": "event", + "name": "BookFlight", + "value": { + "$ref": "#/definitions/bookingInfo" + }, + "resultValue": { + "$ref": "#/definitions/bookingInfo" + } + }, + "getWeather": { + "description": "Retrieves and returns the weather for the user's location", + "type": "invoke", + "name": "GetWeather", + "value": { + "$ref": "#/definitions/location" + }, + "resultValue": { + "$ref": "#/definitions/weatherReport" + } + }, + "message": { + "type": "message", + "description": "Receives the user's' utterance and attempts to resolve it using the skill's LU models" + }, + "typing": { + "type": "typing" + }, + "conversationUpdate": { + "type": "conversationUpdate" + } + }, + "definitions": { + "localeValue": { + "type": "object", + "properties": { + "locale": { + "type": "string", + "description": "The current user's locale ISO code" + } + } + }, + "bookingInfo": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "this is the origin city for the flight" + }, + "destination": { + "type": "string", + "description": "this is the destination city for the flight" + }, + "date": { + "type": "string", + "description": "The date for the flight in YYYY-MM-DD format" + } + } + }, + "weatherReport": { + "type": "array", + "description": "Array of forecasts for the next week.", + "items": [ + { + "type": "string" + } + ] + }, + "location": { + "type": "object", + "description": "Location metadata", + "properties": { + "latitude": { + "type": "number", + "title": "Latitude" + }, + "longitude": { + "type": "number", + "title": "Longitude" + }, + "postalCode": { + "type": "string", + "title": "Postal code" + } + } + } + }, + "activitiesSent": { + "flightUpdated": { + "type": "event", + "name": "FlightUpdated", + "description": "Event which is sent by the skill when there is an update in flight info", + "value": { + "type": "object", + "description": "Flight update information", + "properties": { + "flightNumber": { + "type": "string" + }, + "departureDate": { + "type": "string", + "description": "The departure date for the flight in YYYY-MM-DD format" + }, + "departureTime": { + "type": "string", + "description": "The departure time for the flight in HH-MM format" + } + } + } + } + } +} diff --git a/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-en.qna b/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-en.qna new file mode 100644 index 0000000000..5f3a60698e --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-en.qna @@ -0,0 +1,3 @@ +# ? Sample Question +- sample answer 1 +- sample answer 2 diff --git a/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-ES.qna b/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-ES.qna new file mode 100644 index 0000000000..5f3a60698e --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-ES.qna @@ -0,0 +1,3 @@ +# ? Sample Question +- sample answer 1 +- sample answer 2 diff --git a/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-MX.qna b/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-MX.qna new file mode 100644 index 0000000000..5f3a60698e --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-MX.qna @@ -0,0 +1,3 @@ +# ? Sample Question +- sample answer 1 +- sample answer 2 diff --git a/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-en.lu b/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-en.lu new file mode 100644 index 0000000000..8e2a9f49c9 --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-en.lu @@ -0,0 +1,7 @@ +# bookFlight +- Utterance 1 +- Utterance 2 + +# getWeather +- Utterance 3 +- Utterance 4 diff --git a/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-ES.lu b/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-ES.lu new file mode 100644 index 0000000000..8e2a9f49c9 --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-ES.lu @@ -0,0 +1,7 @@ +# bookFlight +- Utterance 1 +- Utterance 2 + +# getWeather +- Utterance 3 +- Utterance 4 diff --git a/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-MX.lu b/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-MX.lu new file mode 100644 index 0000000000..8e2a9f49c9 --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-MX.lu @@ -0,0 +1,7 @@ +# bookFlight +- Utterance 1 +- Utterance 2 + +# getWeather +- Utterance 3 +- Utterance 4 diff --git a/schemas/skills/v2.2/samples/relativeUris/privacy.html b/schemas/skills/v2.2/samples/relativeUris/privacy.html new file mode 100644 index 0000000000..9375381073 --- /dev/null +++ b/schemas/skills/v2.2/samples/relativeUris/privacy.html @@ -0,0 +1,11 @@ + + + + + + Sample privacy notice + + +TODO + + diff --git a/schemas/skills/v2.2/samples/relativeUris/skillIcon.png b/schemas/skills/v2.2/samples/relativeUris/skillIcon.png new file mode 100644 index 0000000000..37c81be7d6 Binary files /dev/null and b/schemas/skills/v2.2/samples/relativeUris/skillIcon.png differ diff --git a/schemas/skills/v2.2/samples/simple-skillmanifest.json b/schemas/skills/v2.2/samples/simple-skillmanifest.json new file mode 100644 index 0000000000..b42b96aa3e --- /dev/null +++ b/schemas/skills/v2.2/samples/simple-skillmanifest.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json", + "$id": "CatchAllSkill", + "name": "Simple Skill", + "version": "1.0", + "description": "This is the simplest skill you can think of, it just defines an endpoint that can receive any activity", + "publisherName": "Microsoft", + "privacyUrl": "https://myskill.contoso.com/privacy.html", + "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.", + "license": "", + "iconUrl": "https://myskill.contoso.com/icon.png", + "tags": [ + "sample" + ], + "endpoints": [ + { + "name": "default", + "protocol": "BotFrameworkV3", + "description": "Production endpoint for SkillBot.", + "endpointUrl": "http://myskill.contoso.com/api/messages", + "msAppId": "00000000-0000-0000-0000-000000000000" + } + ] +} diff --git a/schemas/skills/v2.2/skill-manifest.json b/schemas/skills/v2.2/skill-manifest.json new file mode 100644 index 0000000000..6106fc8b58 --- /dev/null +++ b/schemas/skills/v2.2/skill-manifest.json @@ -0,0 +1,406 @@ +{ + "$id": "https://schemas.botframework.com/schemas/skills/v2.2/skill-manifest.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "$version": "2.2.0", + "title": "Skill Manifest Schema", + "description": "A schema for Bot Framework skill manifests", + "type": "object", + "required": [ + "$id", + "$schema", + "name", + "version", + "publisherName", + "endpoints" + ], + "properties": { + "$schema": { + "type": "string", + "format": "uri", + "title": "Manifest schema", + "description": "The schema to verify this skill manifest against" + }, + "$id": { + "type": "string", + "title": "Manifest ID", + "description": "The identifier for the skill manifest" + }, + "name": { + "type": "string", + "title": "Skill name", + "description": "Name of the skill" + }, + "version": { + "type": "string", + "title": "Skill version", + "description": "Skill version" + }, + "description": { + "type": "string", + "title": "Skill description", + "description": "A human readable description for the skill" + }, + "publisherName": { + "type": "string", + "title": "Publisher name", + "description": "The name of the skill publisher" + }, + "privacyUrl": { + "type": "string", + "format": "uri-reference", + "title": "Privacy URL", + "description": "The URL with the privacy description for the skill" + }, + "copyright": { + "type": "string", + "title": "Copyright", + "description": "The copyright for the skill" + }, + "license": { + "type": "string", + "title": "License", + "description": "The license agreement for the skill" + }, + "iconUrl": { + "type": "string", + "format": "uri-reference", + "title": "Icon URL", + "description": "Optional icon to be shown for the skill" + }, + "tags": { + "type": "array", + "uniqueItems": true, + "title": "Tags", + "description": "An array of strings with tags for the skill", + "items": { + "type": "string" + } + }, + "endpoints": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "title": "Skill endpoints", + "description": "List of endpoints supported by the skill", + "items": { + "$ref": "#/definitions/endpoint" + } + }, + "dispatchModels": { + "type": "object", + "title": "Language models", + "description": "Language models and top level intents for the skill", + "properties": { + "languages": { + "type": "object", + "description": "List of languages supported by the skill", + "minProperties": 1, + "additionalProperties": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "description": "List of language models supported by the skill", + "items": { + "$ref": "#/definitions/languageModel" + } + } + }, + "intents": { + "type": "array", + "uniqueItems": true, + "description": "A list of the skill's top level intents that can be used by the consumer to filter out language files.", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "activities": { + "type": "object", + "title": "Activities", + "description": "Definition of activities to enable skill host tooling to programmatically interact with the skill.", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/eventActivity" + }, + { + "$ref": "#/definitions/invokeActivity" + }, + { + "$ref": "#/definitions/messageActivity" + }, + { + "$ref": "#/definitions/otherActivities" + } + ] + } + }, + "activitiesSent": { + "type": "object", + "title": "Activities sent", + "description": "Definitions of activities to enable skill host tooling to handle activities which may be sent by the skill.", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/eventActivity" + }, + { + "$ref": "#/definitions/messageActivity" + }, + { + "$ref": "#/definitions/otherActivities" + } + ] + } + }, + "definitions": { + "type": "object", + "description": "Definitions of the structure of object payloads", + "additionalProperties": { + "$ref": "http://json-schema.org/draft-07/schema#" + } + } + }, + "additionalProperties": false, + "definitions": { + "endpoint": { + "type": "object", + "title": "Skill endpoint", + "description": "Skill endpoint definition", + "required": [ + "name", + "endpointUrl", + "msAppId" + ], + "properties": { + "name": { + "type": "string", + "title": "Endpoint name", + "description": "Unique name for the endpoint", + "default": "default" + }, + "protocol": { + "type": "string", + "title": "Endpoint protocol", + "description": "Supported protocol", + "default": "BotFrameworkV3" + }, + "description": { + "type": "string", + "title": "Endpoint description", + "description": "Description of the endpoint", + "examples": [ + "Production bot" + ] + }, + "endpointUrl": { + "type": "string", + "format": "uri", + "title": "Endpoint URL", + "description": "Endpoint for the skill", + "examples": [ + "http://contoso.com/api/messaages" + ] + }, + "msAppId": { + "type": "string", + "title": "Microsoft App Id", + "pattern": "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$", + "description": "The Microsoft AppId for the skill. This app ID is used to authenticate requests" + } + }, + "additionalProperties": false + }, + "eventActivity": { + "type": "object", + "title": "Event Activity", + "description": "An activity with Type=Event where the Name property indicates the task that the skill will execute", + "required": [ + "type", + "name" + ], + "properties": { + "type": { + "type": "string", + "title": "Activity type", + "description": "The activity type", + "enum": [ + "event" + ] + }, + "name": { + "type": "string", + "title": "Event name", + "description": "The name for the event", + "examples": [ + "BookFlight" + ] + }, + "description": { + "type": "string", + "title": "Event description", + "description": "Description for the activity" + }, + "value": { + "$ref": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "Value", + "description": "The JsonSchema definition of the shape of the value property that this event expects" + }, + "resultValue": { + "$ref": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "Result", + "description": "The JsonSchema definition of the shape of the resultValue that this event may produce" + } + }, + "additionalProperties": false + }, + "invokeActivity": { + "type": "object", + "title": "Invoke Activity", + "description": "An activity with Type=Invoke where the Name property indicates the task that the skill will execute", + "required": [ + "type", + "name" + ], + "properties": { + "type": { + "type": "string", + "title": "Activity type", + "description": "The activity type", + "enum": [ + "invoke" + ] + }, + "name": { + "type": "string", + "title": "Invoke name", + "description": "The name property for the invoke activity", + "examples": [ + "GetWeather" + ] + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description for the activity" + }, + "value": { + "type": "object", + "title": "Value", + "description": "The JsonSchema definition of the shape of the value property that this event expects", + "$ref": "http://json-schema.org/draft-07/schema#" + }, + "resultValue": { + "type": "object", + "title": "Result", + "description": "The JsonSchema definition of the shape of the resultValue that this event may produce", + "$ref": "http://json-schema.org/draft-07/schema#" + } + }, + "additionalProperties": false + }, + "messageActivity": { + "type": "object", + "title": "Message Activity", + "description": "An activity with Type=Message where the utterance is passed to the skill in the Text property", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "title": "Activity type", + "description": "The activity type", + "enum": [ + "message" + ] + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description for the activity" + }, + "value": { + "type": "object", + "title": "Value", + "description": "The JsonSchema definition of the shape of the value property that this message would like to have", + "$ref": "http://json-schema.org/draft-07/schema#" + }, + "resultValue": { + "type": "object", + "title": "Result", + "description": "The JsonSchema definition of the shape of the resultValue that this message may produce", + "$ref": "http://json-schema.org/draft-07/schema#" + } + }, + "additionalProperties": false + }, + "otherActivities": { + "type": "object", + "title": "Activity", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "title": "Activity type", + "description": "The activity type", + "enum": [ + "messageReaction", + "endOfConversation", + "handoff", + "typing", + "conversationUpdate", + "trace", + "installationUpdate", + "contactRelationUpdate", + "suggestion", + "deleteUserData", + "messageUpdate", + "messageDelete" + ] + } + }, + "additionalProperties": true + }, + "languageModel": { + "type": "object", + "title": "Language model", + "description": "A language model for a given culture. The name is a combination of an ISO 639 two-letter lowercase culture code associated with a language and an ISO 3166 two-letter uppercase subculture code associated with a country or region", + "required": [ + "name", + "contentType", + "url" + ], + "properties": { + "name": { + "type": "string", + "title": "Language model name", + "description": "Name for the language model" + }, + "contentType": { + "type": "string", + "title": "Language model content type", + "description": "Type of the language model" + }, + "url": { + "type": "string", + "format": "uri-reference", + "title": "Language model URL", + "description": "An absolute or relative URI for the location of the language model file" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description for the language model" + } + }, + "additionalProperties": false + } + } +}