From 2362e4f1f9cbb72d8df7e98be0143279333a37ec Mon Sep 17 00:00:00 2001 From: Gabo Gilabert Date: Mon, 5 Jul 2021 23:13:52 -0400 Subject: [PATCH] Skill Manifest 2.2 (#6321) * Created v2.2 folder Updated some URI properties in skill manifest to accept URI-refences Added sample with relative URLs * Added missing files * Add validation for skill manifest examples against skill manifest schemas (#6325) * Add validation for 2.2 skill manifest * Add other skill schemas and manifest versions * Fixed 2.1 and 2.2 manifest validation errors Updated test to read files directly from the skills folder to make them easier to maintain. Updated tests to use NewtonSoft and NJSonSchema validations to provide better comat Co-authored-by: Gabo Gilabert * Added titles * Fixed versions Co-authored-by: Eric Dahlvang --- .gitignore | 12 +- .../SchemaManifestTests.csproj | 25 ++ .../SchemaManifestTests.sln | 25 ++ .../ValidateSchemaTests.cs | 111 +++++ schemas/skills/readme.md | 2 +- schemas/skills/v2.1/skill-manifest.json | 27 +- .../v2.2/samples/complex-pva-manifest.json | 164 +++++++ .../v2.2/samples/complex-skillmanifest.json | 199 +++++++++ .../v2.2/samples/echo-skillmanifest.json | 31 ++ .../relativeUris/complex-skillmanifest.json | 199 +++++++++ .../knowledge-base/SkillBot-QnA-en.qna | 3 + .../knowledge-base/SkillBot-QnA-es-ES.qna | 3 + .../knowledge-base/SkillBot-QnA-es-MX.qna | 3 + .../language-understanding/SkillBot-en.lu | 7 + .../language-understanding/SkillBot-es-ES.lu | 7 + .../language-understanding/SkillBot-es-MX.lu | 7 + .../v2.2/samples/relativeUris/privacy.html | 11 + .../v2.2/samples/relativeUris/skillIcon.png | Bin 0 -> 1899 bytes .../v2.2/samples/simple-skillmanifest.json | 24 ++ schemas/skills/v2.2/skill-manifest.json | 406 ++++++++++++++++++ 20 files changed, 1252 insertions(+), 14 deletions(-) create mode 100644 schemas/skills/SchemaManifestTests/SchemaManifestTests.csproj create mode 100644 schemas/skills/SchemaManifestTests/SchemaManifestTests.sln create mode 100644 schemas/skills/SchemaManifestTests/ValidateSchemaTests.cs create mode 100644 schemas/skills/v2.2/samples/complex-pva-manifest.json create mode 100644 schemas/skills/v2.2/samples/complex-skillmanifest.json create mode 100644 schemas/skills/v2.2/samples/echo-skillmanifest.json create mode 100644 schemas/skills/v2.2/samples/relativeUris/complex-skillmanifest.json create mode 100644 schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-en.qna create mode 100644 schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-ES.qna create mode 100644 schemas/skills/v2.2/samples/relativeUris/knowledge-base/SkillBot-QnA-es-MX.qna create mode 100644 schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-en.lu create mode 100644 schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-ES.lu create mode 100644 schemas/skills/v2.2/samples/relativeUris/language-understanding/SkillBot-es-MX.lu create mode 100644 schemas/skills/v2.2/samples/relativeUris/privacy.html create mode 100644 schemas/skills/v2.2/samples/relativeUris/skillIcon.png create mode 100644 schemas/skills/v2.2/samples/simple-skillmanifest.json create mode 100644 schemas/skills/v2.2/skill-manifest.json 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 0000000000000000000000000000000000000000..37c81be7d6b7ee7f51bdcd5770d6992b104e3b9e GIT binary patch literal 1899 zcmV-x2bB1UP)002t}1^@s6I8J)%00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru;S3rQE*E_6!-xO?2KY%t zK~#9!?b~^9Q$-vH@NZs2Dbf}SX=&OtDWx1O3Iz&+#d1RtsRfa%$Wf46#*1TAJW-mq zfCwJoeLI38qa!jXqXUBnIyn9z0!?~wPNf%ZlaS4O>mQ+I%5L>FeJ>2m{$~2m?ly1V zC;Q&+Z@V>M-Ej&LszMS30!v^CEP*Ak1ePEWSOQC62`qsnumpj?5?BIDUr^vV4vT_0(g^43 zq*jCVGKJ#Aqe%dOZx&dP)w^R*!GeQDD7H+A#i~1^nu-!Sw}W$a5+d5G>q442tO=?y z_AN-j_+G&SlY#-YDW@AA%ILyW)p-?oh`Kwi^~mtbY}@^L2^iZmIAD_AP=(pu@W^l$ z>hFKN=)1WDL{WE_CDjDo3mhOEumcMdFedpH-N7V1q3n}m@K`1bb>gBIDVv-?E8p?w zF8PpD=zxy{{M{leM)lAaOwtQ#GomX~b@HMYeTrHS)fi`LeMl;BLgs)Se87qk zN&10lkL9D-FewJ>MzT<+D!u5vDR8L9I9*GSRLBSWVX+mNI)O=ALp?V!8c&R3p&XT7 z^eS>{cB%3jf*yrV@LqX8F1BKL_YRtaNm@cZlNF8iqfJbevx=anhER=BRzuLE(7^>e zw8VytL~X$&t)QNo5RIqDn7Ff8a-l=F_ikx5L2{7;lyiZ@OKlit(+*710_w@}COkXV z#J>?8p_;ysDuSLx4sP9%Wj5Sy)doyzE7ap-O?ZA>bPMkk{v)DCII8?3j2AyIw_%7i ztj%CjTcFmCG2w*?EY#^5f~11rL0z3hNQ;xmFUu1#I3eshVEHK4jP8p3tZ2?U=*qNy zosP&gEl)V{>xx7SiVq7SmQ3;JsIIV2jA5$I))I6taB^4JJaAC|Zp8mS9y0a+_$bs2 z*OM2$NZHH>`)y?+2F8U20ZXQMctjTz-4(-4Mbtuth8S>oMIvZ^AJC#y{{q(6!tW^* zd*)j}3sOJ}Q?NZJw&k|h{j;-pBm~f*`SU%cp zKdLdR-7+j2i@Dn;Eq%^p4ops8&dw)MFgb;7o1Gc~wJ*iLD!fQ-;gQTs@1zr!dwOel-97HQ&vsboKZ6P%Xw|p?y?e!O_O3;m_5CEVHvP=&jnP}%gg}S zmfa1@GrFh)3zaZ`*ZF2e74<$89;#y78Vy+b<%MQNUYTO;w-xG=aYFI+q6Ghb{WY=g zL_KyLyVNQyLu=2$hZzkhUz-e5cnH(qWnW&v>qn}A|NH9=1bk4%C5D4H&<(95A-Ne*rB@-9Cy$doe0q>?65jN-P!)?TqWT zDkT(q^7v5S7Y7d2rgXY$?mV|N4&)#gOn zMHE==#i(|(U~k=P#{40j5wrx6Q0$s#!PHwLn5rL~E{u7-ZBUwQ(KLAdBdmr4_Rcgj z<_-!17*X)qJPW4X#zOsA;=-uc%GwO2+2&upSAos$KrILCz3FDm8PrKXFrwg-xfa~V zfjU&`#>iK-fzk{M0O~F)u-YBCkSHLc_V4uv4!;CZy zz=(qPbK{Yl#^!cEm%EX%U3(~9u&#nRxL}{oio<>VBLfE`6z|TC$Nd9Xs9#RIF-#{Y z-LNQtTDJ_Fy%_ag7VNXx@wm5NB%rh&>g`!^m^YAxI(o)~q1#Gz%^Y+)>p%h2xD{CQ z9cbWy?aqzIl-t79gAs~1XPU8K5DWF&Sr3N1T%vo5rRymgKbQ=g-2oTpXwesQEQknG z*M)ofM_^%kXQur3vmOlIS`w68RQK~)6hNg*hAqDsF4BA$W$q~BzSnrM_s=?PI9S=N z?ASRE(t`vQ6s*Rmbje7xJK(-D!ZLT1;ZTWN{UH&f0qgfwG=cqb{xSvz5h~ywm9#qch8qZapPXhu=U