diff --git a/README.md b/README.md
index b64ce9b..c1f3bb3 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
# Actions On Google Client Library
+
+
+
![](https://storage.googleapis.com/kotlin-actions-sdk.appspot.com/actions-kotlin-java.png)
This is a port of the [official Node.js SDK](https://github.com/actions-on-google/actions-on-google-nodejs) to Kotlin. This can also be used from Java and any JVM language.
@@ -15,25 +18,41 @@ __Quick Facts__
* Conversation Components & Transaction Sample ported
* Supports v2 of Actions on Google API (if v1 is needed, make an issue please)
-## Setup Instructions
+
+## V2 Support
+
+The V2 release is available by using:
+
+ compile 'com.tmsdurham.actions:actions-on-google:2.0.1'
+
+The V2 is mostly complete, but may have a few bugs and missing features. All Conversation components and Transaction API are working. Dialogflow & ActionSDK has been tested and working. The API matches the official node.js API very closely. The sample in this repo is a good place to get started. The setup and samples in this readme have not been updated yet. There are a few differerences and additions:
+
+ * use action name from Dialogflow instead of intent name. The official library changed from using the action field, to using the intent name. There is a PR open on the official SDK for support for action. If/when this is merged, this library will be updated to match.
+ * middleware not supported. Same functionality can be implemented without lib support by wrapping handlers in fuctions.
+
+__V2 notes__:
+A common module was used with the intent on targeting multiple platforms (JS & possibly native). These other platforms are purely experimental at this time. A single code base for JVM and JS would be more efficient.
+
+## Setup Instructions(V1 - see sample for V2 setup and use)
This library is available on jCenter. If your using gradle simply add the dependency as follows:
__Gradle:__
repositories {
- jcenter()
+ jCenter()
+ }
}
dependencies {
- compile 'com.tmsdurham.actions:actions-on-google:1.6.3'
+ compile 'com.tmsdurham.actions:actions-on-google:1.6.0'
}
__Maven:__
com.tmsdurham.actions
actions-on-google
- 1.6.3
+ 1.6.0
pom
@@ -41,14 +60,14 @@ The above artifact should fit the needs of most developers, however, if you are
__Gradle:__
- compile 'com.tmsdurham.actions:actions-on-google-core:1.6.3'. //only if not using Servlets
+ compile 'com.tmsdurham.actions:actions-on-google-core:1.6.0'. //only if not using Servlets
__Maven:__
com.tmsdurham.actions
actions-on-google-core //only if not using Servlets
- 1.6.3
+ 1.6.0
pom
diff --git a/action-sdk-samples/action.json b/action-sdk-samples/action.json
deleted file mode 100644
index bd5a80f..0000000
--- a/action-sdk-samples/action.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "actions": [
- {
- "description": "Launch intent",
- "name": "MAIN",
- "fulfillment": {
- "conversationName": "mainConversation"
- },
- "intent": {
- "name": "actions.intent.MAIN"
- }
- }
- ],
- "conversations": {
- "mainConversation": {
- "name": "mainConversation",
- "url": "https://kotlin-actions-sdk.appspot.com/conversation",
- "fulfillmentApiVersion": 2
- }
- }
-}
diff --git a/action-sdk-samples/build.gradle b/action-sdk-samples/build.gradle
deleted file mode 100644
index 79a3875..0000000
--- a/action-sdk-samples/build.gradle
+++ /dev/null
@@ -1,44 +0,0 @@
-buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath 'com.google.cloud.tools:appengine-gradle-plugin:+'
- // latest App Engine Gradle tasks
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$project.ext.kotlinVersion"
- }
-}
-repositories {
- mavenCentral()
-}
-
-apply plugin: 'idea'
-apply plugin: 'kotlin'
-apply plugin: 'java'
-apply plugin: 'war'
-apply plugin: 'com.google.cloud.tools.appengine'
-
-dependencies {
- compile('javax.servlet:javax.servlet-api:3.1.0',
- 'com.google.appengine:appengine:+',
- "com.google.code.gson:gson:$project.ext.gsonVersion",
- "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$project.ext.kotlinVersion")
- compile project(':sdk-gson-servlet')
-}
-
-
-appengine { // App Engine tasks configuration
- run { // local (dev_appserver) configuration (standard environments only)
- port = 8080 // default
- }
-
- deploy { // deploy configuration
- stopPreviousVersion = true // default - stop the current version
- promote = true // default - & make this the current version
- version = 'prod'
- }
-}
-
-sourceCompatibility = "1.8"
-targetCompatibility = "1.8"
-
diff --git a/action-sdk-samples/src/main/java/com/tmsdurham/actions/ConversationComponentsSample.kt b/action-sdk-samples/src/main/java/com/tmsdurham/actions/ConversationComponentsSample.kt
deleted file mode 100644
index fdbb5e6..0000000
--- a/action-sdk-samples/src/main/java/com/tmsdurham/actions/ConversationComponentsSample.kt
+++ /dev/null
@@ -1,234 +0,0 @@
-package com.tmsdurham.actions
-
-import main.java.com.tmsdurham.dialogflow.sample.ActionsSdkAction
-import java.util.logging.Logger
-import javax.servlet.annotation.WebServlet
-import javax.servlet.http.HttpServlet
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
-
-// Copyright 2017, Google, Inc.
-// Licensed under the Apache License, Version 2.0 (the "License")
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Constants for list and carousel selection
-val logger = Logger.getAnonymousLogger()
-
-val SELECTION_KEY_ONE = "title"
-val SELECTION_KEY_GOOGLE_HOME = "googleHome"
-val SELECTION_KEY_GOOGLE_PIXEL = "googlePixel"
-val SELECTION_KEY_GOOGLE_ALLO = "googleAllo"
-
-// Constant for image URLs
-val IMG_URL_AOG = "https://developers.google.com/actions/images/badges" +
- "/XPM_BADGING_GoogleAssistant_VER.png"
-val IMG_URL_GOOGLE_HOME = "https://lh3.googleusercontent.com" +
- "/Nu3a6F80WfixUqf_ec_vgXy_c0-0r4VLJRXjVFF_X_CIilEu8B9fT35qyTEj_PEsKw"
-val IMG_URL_GOOGLE_PIXEL = "https://storage.googleapis.com/madebygoog/v1" +
- "/Pixel/Pixel_ColorPicker/Pixel_Device_Angled_Black-720w.png"
-val IMG_URL_GOOGLE_ALLO = "https://allo.google.com/images/allo-logo.png"
-
-// Welcome
-fun welcome(app: ActionsSdkApp) =
- app.ask(app.buildRichResponse()
- .addSimpleResponse(speech = "Hi there!", displayText = "Hello there!")
- .addSimpleResponse(
- speech = "I can show you basic cards, lists and carousels as well as " +
- "suggestions on your phone",
- displayText = "I can show you basic cards, lists and carousels as " +
- "well as suggestions"
- )
- .addSuggestions(
- "Basic Card", "List", "Carousel", "Suggestions"))
-
-fun normalAsk(app: ActionsSdkApp) =
- app.ask("Ask me to show you a list, carousel, or basic card")
-
-// Suggestions
-fun suggestions(app: ActionsSdkApp) =
- app.ask(app
- .buildRichResponse()
- .addSimpleResponse("This is a simple response for suggestions")
- .addSuggestions("Suggestion Chips")
- .addSuggestions("Basic Card", "List", "Carousel")
- .addSuggestionLink("Suggestion Link", "https://assistant.google.com/"))
-
-// Basic card
-fun basicCard(app: ActionsSdkApp) {
- app.ask(app.buildRichResponse()
- .addSimpleResponse("This is the first simple response for a basic card")
- .addSuggestions(
- "Basic Card", "List", "Carousel", "Suggestions")
- // Create a basic card and add it to the rich response
- .addBasicCard(app.buildBasicCard(""" This is a basic card . Text in a
- basic card can include "quotes" and most other unicode characters
- including emoji 📱. Basic cards also support some markdown
- formatting like * emphasis * or _italics_, ** strong * * or __bold__,
- and * * * bold itallic * * * or ___strong emphasis___ as well as other things
- like line \nbreaks """) // Note the two spaces before "\n" required for a
- // line break to be rendered in the card
- .setSubtitle("This is a subtitle")
- .setTitle("Title: this is a title")
- .addButton("This is a button", "https://assistant.google.com/")
- .setImage(IMG_URL_AOG, "Image alternate text")
- )
- .addSimpleResponse(
- speech = "This is the second simple response ",
- displayText = "This is the 2nd simple response")
- )
-}
-
-// List
-fun list(app: ActionsSdkApp) {
- app.askWithList(app.buildRichResponse()
- .addSimpleResponse("This is a simple response for a list")
- .addSuggestions(
- "Basic Card", "List", "Carousel", "Suggestions"),
- // Build a list
- app.buildList("List Title")
- // Add the first item to the list
- .addItems(app.buildOptionItem(SELECTION_KEY_ONE,
- "synonym of title 1", "synonym of title 2", "synonym of title 3")
- .setTitle("Title of First List Item")
- .setDescription("This is a description of a list item")
- .setImage(IMG_URL_AOG, "Image alternate text"))
- // Add the second item to the list
- .addItems(app.buildOptionItem(SELECTION_KEY_GOOGLE_HOME,
- "Google Home Assistant", "Assistant on the Google Home")
- .setTitle("Google Home")
- .setDescription(""" Google Home is a voice - activated speaker powered by
- the Google Assistant.""")
- .setImage(IMG_URL_GOOGLE_HOME, "Google Home")
- )
- // Add third item to the list
- .addItems(app.buildOptionItem(SELECTION_KEY_GOOGLE_PIXEL,
- "Google Pixel XL", "Pixel", "Pixel XL")
- .setTitle("Google Pixel")
- .setDescription("Pixel. Phone by Google.")
- .setImage(IMG_URL_GOOGLE_PIXEL, "Google Pixel")
- )
- // Add last item of the list
- .addItems(app.buildOptionItem(SELECTION_KEY_GOOGLE_ALLO)
- .setTitle("Google Allo")
- .setDescription("Introducing Google Allo, a smart messaging app" +
- "that helps you say more and do more.")
- .setImage(IMG_URL_GOOGLE_ALLO, "Google Allo Logo")
- .addSynonyms("Allo")
- )
- )
-}
-
-// Carousel
-fun carousel(app: ActionsSdkApp) {
- app.askWithCarousel(app.buildRichResponse()
- .addSimpleResponse("This is a simple response for a carousel")
- .addSuggestions(
- "Basic Card", "List", "Carousel", "Suggestions"),
- app.buildCarousel()
- // Add the first item to the carousel
- .addItems(app.buildOptionItem(SELECTION_KEY_ONE,
- "synonym of title 1", "synonym of title 2", "synonym of title 3")
- .setTitle("Title of First List Item")
- .setDescription("This is a description of a carousel item")
- .setImage(IMG_URL_AOG, "Image alternate text"))
- // Add the second item to the carousel
- .addItems(app.buildOptionItem(SELECTION_KEY_GOOGLE_HOME,
- "Google Home Assistant", "Assistant on the Google Home")
- .setTitle("Google Home")
- .setDescription(""" Google Home is a voice - activated speaker powered by
- the Google Assistant.""")
- .setImage(IMG_URL_GOOGLE_HOME, "Google Home")
- )
- // Add third item to the carousel
- .addItems(app.buildOptionItem(SELECTION_KEY_GOOGLE_PIXEL,
- "Google Pixel XL", "Pixel", "Pixel XL")
- .setTitle("Google Pixel")
- .setDescription("Pixel. Phone by Google.")
- .setImage(IMG_URL_GOOGLE_PIXEL, "Google Pixel")
- )
- // Add last item of the carousel
- .addItems(app.buildOptionItem(SELECTION_KEY_GOOGLE_ALLO)
- .setTitle("Google Allo")
- .setDescription("Introducing Google Allo, a smart messaging app" +
- "that helps you say more and do more.")
- .setImage(IMG_URL_GOOGLE_ALLO, "Google Allo Logo")
- .addSynonyms("Allo")
- )
- )
-}
-
-// React to list or carousel selection
-fun itemSelected(app: ActionsSdkApp) {
- val param = app.getSelectedOption()
- logger.info("USER SELECTED: " + param)
- when (param) {
- null -> app.ask("You did not select any item from the list or carousel")
- SELECTION_KEY_ONE -> app.ask("You selected the first item in the list or carousel")
- SELECTION_KEY_GOOGLE_HOME -> app.ask("You selected the Google Home!")
- SELECTION_KEY_GOOGLE_PIXEL -> app.ask("You selected the Google Pixel!")
- SELECTION_KEY_GOOGLE_ALLO -> app.ask("You selected Google Allo!")
- else -> app.ask("You selected an unknown item from the list or carousel")
- }
-}
-
-// Leave conversation with card
-fun byeCard(app: ActionsSdkApp) {
- app.tell(app.buildRichResponse()
- .addSimpleResponse("Goodbye, World!")
- .addBasicCard(app.buildBasicCard("This is a goodbye card.")))
-}
-
-// Leave conversation with SimpleResponse
-fun byeResponse(app: ActionsSdkApp) {
- app.tell(
- speech = "Okay see you later",
- displayText = "OK see you later!"
- )
-}
-
-// Leave conversation
-fun normalBye(app: ActionsSdkApp) {
- app.tell("Okay see you later!")
-}
-
-fun actionsText(app: ActionsSdkApp) {
- val rawInput = app.getRawInput()
- logger.info("USER SAID " + rawInput)
- when (rawInput) {
- "Basic Card", "basic card" -> basicCard(app)
- "List", "list" -> list(app)
- "Carousel", "carousel" -> carousel(app)
- "normal ask" -> normalAsk(app)
- "normal bye" -> normalBye(app)
- "bye card" -> byeCard(app)
- "bye response" -> byeResponse(app)
- "Suggestions", "Suggestion Chips",
- "suggestions", "suggestions chips" ->
- suggestions(app)
- else ->
- normalAsk(app)
- }
-}
-
-@WebServlet("/conversation")
-class ConversationComponentsSample : HttpServlet() {
- override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
-
- val app = ActionsSdkAction(req, resp)
- val actionMap = mutableMapOf(
- app.app.STANDARD_INTENTS.MAIN to ::welcome,
- app.app.STANDARD_INTENTS.TEXT to ::actionsText,
- app.app.STANDARD_INTENTS.OPTION to ::itemSelected)
- app.handleRequest(actionMap)
- }
-}
-
diff --git a/action-sdk-samples/src/main/webapp/WEB-INF/appengine-web.xml b/action-sdk-samples/src/main/webapp/WEB-INF/appengine-web.xml
deleted file mode 100644
index e58d6f3..0000000
--- a/action-sdk-samples/src/main/webapp/WEB-INF/appengine-web.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- kotlin-actions-sdk
- dev
-
- java8
- true
-
- 100ms
- 500ms
- 30
-
-
-
-
-
diff --git a/action-sdk-samples/src/main/webapp/WEB-INF/web.xml b/action-sdk-samples/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644
index 9e5b267..0000000
--- a/action-sdk-samples/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 8f41dd8..06dd800 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,50 +1,69 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
+allprojects {
+ group 'com.ticketmaster.actions'
+ version '1-SNAPSHOT'
-buildscript {
- ext.kotlin_version = '1.2.10'
- repositories {
- jcenter()
+ apply plugin: 'idea'
+ idea {
+ module {
+ outputDir file('build/classes/main')
+ testOutputDir file('build/classes/test')
+ }
}
- dependencies {
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ if (project.convention.findPlugin(JavaPluginConvention)) {
+ // Change the output directory for the main and test source sets back to the old path
+ sourceSets.main.output.classesDir = new File(buildDir, "classes/main")
+ sourceSets.test.output.classesDir = new File(buildDir, "classes/test")
}
}
-apply plugin: 'kotlin'
+task wrapper(type: Wrapper) {
+ gradleVersion = '4.7'
+ distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
+}
+
+task cleanOutDir(type: Delete) {
+ delete 'out'
+}
repositories {
maven { url "http://dl.bintray.com/jetbrains/spek" }
}
-allprojects {
+buildscript {
+ ext.kotlinVersion = '1.2.51'
+
repositories {
jcenter()
+ mavenCentral()
+ maven { url "https://plugins.gradle.org/m2/" }
}
- project.ext {
- kotlinVersion = '1.2.10'
- gsonVersion = '2.8.1'
- sdkVersion = '1.6.4' //version of deployed artifacts
- spekVersion = '1.1.5'
+ dependencies {
+ classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
+ classpath "com.eriwen:gradle-js-plugin:2.14.1"
+ classpath 'com.moowork.gradle:gradle-node-plugin:1.2.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
-repositories {
- mavenCentral()
-}
-dependencies {
- compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ext {
+ sdkVersion = '2.0.2-alpha' //version of deployed artifacts
+ nodeVersion = '8.11.1'
+ qunitVersion = '2.6.0'
+ libraries = [
+ junit : "junit:junit:4.12",
+ kotlin_stdlib : "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion",
+ kotlin_stdlib_common : "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion",
+ kotlin_stdlib_js : "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion",
+ kotlin_test_annotations_common: "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlinVersion",
+ kotlin_test_common : "org.jetbrains.kotlin:kotlin-test-common:$kotlinVersion",
+ kotlin_test_js : "org.jetbrains.kotlin:kotlin-test-js:$kotlinVersion",
+ kotlin_test_junit : "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion",
+ ]
}
-compileKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
-compileTestKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
+
+subprojects {
+ repositories {
+ jcenter()
+ mavenCentral()
}
}
diff --git a/common-mock/build.gradle b/common-mock/build.gradle
new file mode 100644
index 0000000..28d84b3
--- /dev/null
+++ b/common-mock/build.gradle
@@ -0,0 +1,19 @@
+apply plugin: 'kotlin-platform-common'
+
+archivesBaseName = 'actions-on-google-common-mock'
+
+dependencies {
+ compile project(":common")
+ compile libraries.kotlin_stdlib_common
+ testCompile libraries.kotlin_test_annotations_common
+ testCompile libraries.kotlin_test_common
+}
+
+task sourcesJar(type: Jar) {
+ classifier = 'sources'
+ from sourceSets.main.kotlin
+}
+
+artifacts {
+ archives sourcesJar
+}
diff --git a/common-mock/src/main/kotlin/actions/AogMockFactory.kt b/common-mock/src/main/kotlin/actions/AogMockFactory.kt
new file mode 100644
index 0000000..aafe803
--- /dev/null
+++ b/common-mock/src/main/kotlin/actions/AogMockFactory.kt
@@ -0,0 +1,7 @@
+package actions
+
+object AogMockFactory {
+ fun mockWelcome() {
+
+ }
+}
\ No newline at end of file
diff --git a/common-mock/src/main/kotlin/actions/Requests.kt b/common-mock/src/main/kotlin/actions/Requests.kt
new file mode 100644
index 0000000..1083425
--- /dev/null
+++ b/common-mock/src/main/kotlin/actions/Requests.kt
@@ -0,0 +1,131 @@
+package actions
+
+object MockResponses {
+ const val welcome = """{
+"user":{
+"userId":"APhe68EmFG8L689xcinHdNbpSadP",
+"locale":"en-US",
+"lastSeen":"2018-05-22T01:38:28Z",
+"userStorage":"{\"data\":{}}"
+},
+"conversation":{
+"conversationId":"1526953174329",
+"type":"ACTIVE",
+"conversationToken":"{\"data\":{}}"
+},
+"inputs":[
+{
+"intent":"actions.intent.TEXT",
+"rawInputs":[
+{
+"inputType":"TOUCH",
+"query":"Basic Card"
+}
+],
+"arguments":[
+{
+"name":"text",
+"rawText":"Basic Card",
+"textValue":"Basic Card"
+}
+]
+}
+],
+"surface":{
+"capabilities":[
+{
+"name":"actions.capability.MEDIA_RESPONSE_AUDIO"
+},
+{
+"name":"actions.capability.WEB_BROWSER"
+},
+{
+"name":"actions.capability.AUDIO_OUTPUT"
+},
+{
+"name":"actions.capability.SCREEN_OUTPUT"
+}
+]
+},
+"isInSandbox":true,
+"availableSurfaces":[
+{
+"capabilities":[
+{
+"name":"actions.capability.WEB_BROWSER"
+},
+{
+"name":"actions.capability.AUDIO_OUTPUT"
+},
+{
+"name":"actions.capability.SCREEN_OUTPUT"
+}
+]
+}
+]
+}"""
+
+ const val basicCard = """{
+ "user":{
+ "userId":"APhe68EmFG8L689xcinHdNbpSadP",
+ "locale":"en-US",
+ "lastSeen":"2018-05-22T01:38:28Z",
+ "userStorage":"{\"data\":{}}"
+ },
+ "conversation":{
+ "conversationId":"1526953174329",
+ "type":"ACTIVE",
+ "conversationToken":"{\"data\":{}}"
+ },
+ "inputs":[
+ {
+ "intent":"actions.intent.TEXT",
+ "rawInputs":[
+ {
+ "inputType":"TOUCH",
+ "query":"Basic Card"
+ }
+ ],
+ "arguments":[
+ {
+ "name":"text",
+ "rawText":"Basic Card",
+ "textValue":"Basic Card"
+ }
+ ]
+ }
+ ],
+ "surface":{
+ "capabilities":[
+ {
+ "name":"actions.capability.MEDIA_RESPONSE_AUDIO"
+ },
+ {
+ "name":"actions.capability.WEB_BROWSER"
+ },
+ {
+ "name":"actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name":"actions.capability.SCREEN_OUTPUT"
+ }
+ ]
+ },
+ "isInSandbox":true,
+ "availableSurfaces":[
+ {
+ "capabilities":[
+ {
+ "name":"actions.capability.WEB_BROWSER"
+ },
+ {
+ "name":"actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name":"actions.capability.SCREEN_OUTPUT"
+ }
+ ]
+ }
+ ]
+}"""
+}
diff --git a/common-mock/src/test/kotlin/actions/ActionsSdkTest.kt b/common-mock/src/test/kotlin/actions/ActionsSdkTest.kt
new file mode 100644
index 0000000..8b0d06d
--- /dev/null
+++ b/common-mock/src/test/kotlin/actions/ActionsSdkTest.kt
@@ -0,0 +1,96 @@
+package actions
+
+import actions.expected.Serializer
+import actions.expected.deserialize
+import actions.framework.Headers
+import actions.service.actionssdk.actionssdk
+import actions.service.actionssdk.api.GoogleActionsV2AppRequest
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+/**
+ * Test setup for Tests.
+ * Other solutions - 1) use official javascipt tests against the javascript version of this lib
+ * 2) Use Spek library once v2 & multiplatform support lands and test common module
+ */
+class ActionsSdkTest {
+ data class TestConvData(var ct: Int? = null)
+ data class TestUserStorage(var name: String? = null)
+
+ @Test
+ fun returnEmptyConvData() {
+ val app = actionssdk({})
+ app.intent("test") { conv ->
+ conv.data["ct"] = 5
+ conv.ask("This is a test")
+ }
+
+ val result = app(deserialize(testWelcomeRequestStr)!!)
+ }
+}
+
+
+val testWelcomeRequestStr = """{
+"user":{
+"userId":"APhe68EmFG8L689xcinHdNbpSadP",
+"locale":"en-US",
+"lastSeen":"2018-05-22T01:38:28Z",
+"userStorage":"{\"data\":{}}"
+},
+"conversation":{
+"conversationId":"1526953174329",
+"type":"ACTIVE",
+"conversationToken":"{\"data\":{}}"
+},
+"inputs":[
+{
+"intent":"actions.intent.TEXT",
+"rawInputs":[
+{
+"inputType":"TOUCH",
+"query":"Basic Card"
+}
+],
+"arguments":[
+{
+"name":"text",
+"rawText":"Basic Card",
+"textValue":"Basic Card"
+}
+]
+}
+],
+"surface":{
+"capabilities":[
+{
+"name":"actions.capability.MEDIA_RESPONSE_AUDIO"
+},
+{
+"name":"actions.capability.WEB_BROWSER"
+},
+{
+"name":"actions.capability.AUDIO_OUTPUT"
+},
+{
+"name":"actions.capability.SCREEN_OUTPUT"
+}
+]
+},
+"isInSandbox":true,
+"availableSurfaces":[
+{
+"capabilities":[
+{
+"name":"actions.capability.WEB_BROWSER"
+},
+{
+"name":"actions.capability.AUDIO_OUTPUT"
+},
+{
+"name":"actions.capability.SCREEN_OUTPUT"
+}
+]
+}
+]
+}"""
\ No newline at end of file
diff --git a/common-mock/src/test/resources/conversation_sample_basic_card_request.json b/common-mock/src/test/resources/conversation_sample_basic_card_request.json
new file mode 100644
index 0000000..891d561
--- /dev/null
+++ b/common-mock/src/test/resources/conversation_sample_basic_card_request.json
@@ -0,0 +1,63 @@
+{
+ "user":{
+ "userId":"APhe68EmFG8L689xcinHdNbpSadP",
+ "locale":"en-US",
+ "lastSeen":"2018-05-22T01:38:28Z",
+ "userStorage":"{\"data\":{}}"
+ },
+ "conversation":{
+ "conversationId":"1526953174329",
+ "type":"ACTIVE",
+ "conversationToken":"{\"data\":{}}"
+ },
+ "inputs":[
+ {
+ "intent":"actions.intent.TEXT",
+ "rawInputs":[
+ {
+ "inputType":"TOUCH",
+ "query":"Basic Card"
+ }
+ ],
+ "arguments":[
+ {
+ "name":"text",
+ "rawText":"Basic Card",
+ "textValue":"Basic Card"
+ }
+ ]
+ }
+ ],
+ "surface":{
+ "capabilities":[
+ {
+ "name":"actions.capability.MEDIA_RESPONSE_AUDIO"
+ },
+ {
+ "name":"actions.capability.WEB_BROWSER"
+ },
+ {
+ "name":"actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name":"actions.capability.SCREEN_OUTPUT"
+ }
+ ]
+ },
+ "isInSandbox":true,
+ "availableSurfaces":[
+ {
+ "capabilities":[
+ {
+ "name":"actions.capability.WEB_BROWSER"
+ },
+ {
+ "name":"actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name":"actions.capability.SCREEN_OUTPUT"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/conversation_sample_basic_card_response.json b/common-mock/src/test/resources/conversation_sample_basic_card_response.json
new file mode 100644
index 0000000..ac39457
--- /dev/null
+++ b/common-mock/src/test/resources/conversation_sample_basic_card_response.json
@@ -0,0 +1,76 @@
+{
+ "status": 200,
+ "headers": {
+ "content-type": "application/json; charset=utf-8"
+ },
+ "body": {
+ "expectUserResponse": true,
+ "expectedInputs": [
+ {
+ "inputPrompt": {
+ "richInitialPrompt": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the first simple response for a basic card."
+ }
+ },
+ {
+ "basicCard": {
+ "title": "Title: this is a title",
+ "subtitle": "This is a subtitle",
+ "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emoji 📱. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Image alternate text"
+ },
+ "buttons": [
+ {
+ "title": "This is a button",
+ "openUrlAction": {
+ "url": "https://assistant.google.com/"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the second simple response.",
+ "displayText": "This is the 2nd simple response."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ }
+ ]
+ }
+ },
+ "possibleIntents": [
+ {
+ "intent": "actions.intent.TEXT"
+ }
+ ]
+ }
+ ],
+ "conversationToken": "{\"data\":{}}",
+ "userStorage": "{\"data\":{}}"
+ }
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/conversation_sample_welcome_request.json b/common-mock/src/test/resources/conversation_sample_welcome_request.json
new file mode 100644
index 0000000..37ca887
--- /dev/null
+++ b/common-mock/src/test/resources/conversation_sample_welcome_request.json
@@ -0,0 +1,113 @@
+{
+ "responses": [],
+ "expectUserResponse": true,
+ "digested": false,
+ "_responded": false,
+ "request": null,
+ "headers": null,
+ "sandbox": true,
+ "input": {
+ "raw": "Talk to conversation components",
+ "type": "KEYBOARD"
+ },
+ "surface": {
+ "capabilities": {
+ "list": [
+ {
+ "name": "actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name": "actions.capability.SCREEN_OUTPUT"
+ },
+ {
+ "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
+ },
+ {
+ "name": "actions.capability.WEB_BROWSER"
+ }
+ ]
+ }
+ },
+ "available": {
+ "surfaces": {
+ "list": [
+ {
+ "capabilities": {
+ "list": [
+ {
+ "name": "actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name": "actions.capability.SCREEN_OUTPUT"
+ },
+ {
+ "name": "actions.capability.WEB_BROWSER"
+ }
+ ]
+ }
+ }
+ ],
+ "capabilities": {
+ "surfaces": [
+ {
+ "capabilities": {
+ "list": [
+ {
+ "name": "actions.capability.AUDIO_OUTPUT"
+ },
+ {
+ "name": "actions.capability.SCREEN_OUTPUT"
+ },
+ {
+ "name": "actions.capability.WEB_BROWSER"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ },
+ "user": {
+ "raw": {
+ "userId": "APhe68EmFG8L689xcinHdNbpSadP",
+ "locale": "en-US",
+ "lastSeen": "2018-05-21T15:10:52Z",
+ "userStorage": "{\"data\":{}}"
+ },
+ "storage": {},
+ "id": "APhe68EmFG8L689xcinHdNbpSadP",
+ "locale": "en-US",
+ "permissions": [],
+ "last": {
+ "seen": "2018-05-21T15:10:52.000Z"
+ },
+ "name": {},
+ "entitlements": [],
+ "access": {},
+ "profile": {}
+ },
+ "arguments": {
+ "parsed": {
+ "input": {},
+ "list": []
+ },
+ "status": {
+ "input": {},
+ "list": []
+ },
+ "raw": {
+ "list": [],
+ "input": {}
+ }
+ },
+ "device": {},
+ "id": "1526915488535",
+ "type": "NEW",
+ "screen": true,
+ "body": null,
+ "intent": "actions.intent.MAIN",
+ "data": {},
+ "hasScreen": true,
+ "hasAudioPlayback": true
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/conversation_sample_welcome_response.json b/common-mock/src/test/resources/conversation_sample_welcome_response.json
new file mode 100644
index 0000000..18dacfe
--- /dev/null
+++ b/common-mock/src/test/resources/conversation_sample_welcome_response.json
@@ -0,0 +1,58 @@
+{
+ "status": 200,
+ "headers": {
+ "content-type": "application/json; charset=utf-8"
+ },
+ "body": {
+ "expectUserResponse": true,
+ "expectedInputs": [
+ {
+ "inputPrompt": {
+ "richInitialPrompt": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "Hi there!",
+ "displayText": "Hello there!"
+ }
+ },
+ {
+ "simpleResponse": {
+ "textToSpeech": "I can show you basic cards, lists and carousels as well as suggestions on your phone.",
+ "displayText": "I can show you basic cards, lists and carousels as well as suggestions."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ }
+ ]
+ }
+ },
+ "possibleIntents": [
+ {
+ "intent": "actions.intent.TEXT"
+ }
+ ]
+ }
+ ],
+ "conversationToken": "{\"data\":{}}",
+ "userStorage": "{\"data\":{}}"
+ }
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_basic_card_response.json b/common-mock/src/test/resources/df_sample_basic_card_response.json
new file mode 100644
index 0000000..ff8cb6c
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_basic_card_response.json
@@ -0,0 +1,77 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the first simple response for a basic card."
+ }
+ },
+ {
+ "basicCard": {
+ "title": "Title: this is a title",
+ "subtitle": "This is a subtitle",
+ "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emoji 📱. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Image alternate text"
+ },
+ "buttons": [
+ {
+ "title": "This is a button",
+ "openUrlAction": {
+ "url": "https://assistant.google.com/"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the second simple response.",
+ "displayText": "This is the 2nd simple response."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1530842303910/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
diff --git a/common-mock/src/test/resources/df_sample_browse_carousel_response.json b/common-mock/src/test/resources/df_sample_browse_carousel_response.json
new file mode 100644
index 0000000..16eaa79
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_browse_carousel_response.json
@@ -0,0 +1,82 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is an example of a \"Browse Carousel\""
+ }
+ },
+ {
+ "carouselBrowse": {
+ "items": [
+ {
+ "title": "Title of item 1",
+ "openUrlAction": {
+ "url": "https://google.com"
+ },
+ "description": "Description of item 1",
+ "footer": "Item 1 footer",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Google Assistant Bubbles"
+ }
+ },
+ {
+ "title": "Title of item 2",
+ "openUrlAction": {
+ "url": "https://google.com"
+ },
+ "description": "Description of item 2",
+ "footer": "Item 2 footer",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Google Assistant Bubbles"
+ }
+ }
+ ]
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1531012494339/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_carousel_response.json b/common-mock/src/test/resources/df_sample_carousel_response.json
new file mode 100644
index 0000000..ed293fa
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_carousel_response.json
@@ -0,0 +1,123 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is a simple response for a carousel."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}",
+ "systemIntent": {
+ "intent": "actions.intent.OPTION",
+ "data": {
+ "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
+ "carouselSelect": {
+ "items": [
+ {
+ "optionInfo": {
+ "key": "title",
+ "synonyms": [
+ "synonym of title 1",
+ "synonym of title 2",
+ "synonym of title 3"
+ ]
+ },
+ "description": "This is a description of a carousel item.",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Image alternate text"
+ },
+ "title": "Title of First Carousel Item"
+ },
+ {
+ "optionInfo": {
+ "key": "googleHome",
+ "synonyms": [
+ "Google Home Assistant",
+ "Assistant on the Google Home"
+ ]
+ },
+ "description": "Google Home is a voice-activated speaker powered by the Google Assistant.",
+ "image": {
+ "url": "https://lh3.googleusercontent.com/Nu3a6F80WfixUqf_ec_vgXy_c0-0r4VLJRXjVFF_X_CIilEu8B9fT35qyTEj_PEsKw",
+ "accessibilityText": "Google Home"
+ },
+ "title": "Google Home"
+ },
+ {
+ "optionInfo": {
+ "key": "googlePixel",
+ "synonyms": [
+ "Google Pixel XL",
+ "Pixel",
+ "Pixel XL"
+ ]
+ },
+ "description": "Pixel. Phone by Google.",
+ "image": {
+ "url": "https://storage.googleapis.com/madebygoog/v1/Pixel/Pixel_ColorPicker/Pixel_Device_Angled_Black-720w.png",
+ "accessibilityText": "Google Pixel"
+ },
+ "title": "Google Pixel"
+ },
+ {
+ "optionInfo": {
+ "key": "googleAllo",
+ "synonyms": [
+ "Allo"
+ ]
+ },
+ "description": "Introducing Google Allo, a smart messaging app that helps you say more and do more.",
+ "image": {
+ "url": "https://allo.google.com/images/allo-logo.png",
+ "accessibilityText": "Google Allo Logo"
+ },
+ "title": "Google Allo"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1531012494339/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_list_response.json b/common-mock/src/test/resources/df_sample_list_response.json
new file mode 100644
index 0000000..2ba4ddb
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_list_response.json
@@ -0,0 +1,124 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is a simple response for a list."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}",
+ "systemIntent": {
+ "intent": "actions.intent.OPTION",
+ "data": {
+ "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
+ "listSelect": {
+ "title": "List Title",
+ "items": [
+ {
+ "optionInfo": {
+ "key": "title",
+ "synonyms": [
+ "synonym of title 1",
+ "synonym of title 2",
+ "synonym of title 3"
+ ]
+ },
+ "description": "This is a description of a list item.",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Image alternate text"
+ },
+ "title": "Title of First List Item"
+ },
+ {
+ "optionInfo": {
+ "key": "googleHome",
+ "synonyms": [
+ "Google Home Assistant",
+ "Assistant on the Google Home"
+ ]
+ },
+ "description": "Google Home is a voice-activated speaker powered by the Google Assistant.",
+ "image": {
+ "url": "https://lh3.googleusercontent.com/Nu3a6F80WfixUqf_ec_vgXy_c0-0r4VLJRXjVFF_X_CIilEu8B9fT35qyTEj_PEsKw",
+ "accessibilityText": "Google Home"
+ },
+ "title": "Google Home"
+ },
+ {
+ "optionInfo": {
+ "key": "googlePixel",
+ "synonyms": [
+ "Google Pixel XL",
+ "Pixel",
+ "Pixel XL"
+ ]
+ },
+ "description": "Pixel. Phone by Google.",
+ "image": {
+ "url": "https://storage.googleapis.com/madebygoog/v1/Pixel/Pixel_ColorPicker/Pixel_Device_Angled_Black-720w.png",
+ "accessibilityText": "Google Pixel"
+ },
+ "title": "Google Pixel"
+ },
+ {
+ "optionInfo": {
+ "key": "googleAllo",
+ "synonyms": [
+ "Allo"
+ ]
+ },
+ "description": "Introducing Google Allo, a smart messaging app that helps you say more and do more.",
+ "image": {
+ "url": "https://allo.google.com/images/allo-logo.png",
+ "accessibilityText": "Google Allo Logo"
+ },
+ "title": "Google Allo"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1531012494339/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_media_response.json b/common-mock/src/test/resources/df_sample_media_response.json
new file mode 100644
index 0000000..8177e10
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_media_response.json
@@ -0,0 +1,68 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the first simple response for a media response"
+ }
+ },
+ {
+ "mediaResponse": {
+ "mediaType": "AUDIO",
+ "mediaObjects": [
+ {
+ "contentUrl": "http://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3",
+ "description": "A funky Jazz tune",
+ "icon": {
+ "url": "http://storage.googleapis.com/automotive-media/album_art.jpg",
+ "accessibilityText": "Media icon"
+ },
+ "name": "Jazz in Paris"
+ }
+ ]
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1531012494339/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_suggestions_response.json b/common-mock/src/test/resources/df_sample_suggestions_response.json
new file mode 100644
index 0000000..f364213
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_suggestions_response.json
@@ -0,0 +1,59 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is a simple response for suggestions."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Suggestion Chips"
+ },
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ],
+ "linkOutSuggestion": {
+ "destinationName": "Suggestion Link",
+ "url": "https://assistant.google.com/"
+ }
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1531013042496/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_table_response.json b/common-mock/src/test/resources/df_sample_table_response.json
new file mode 100644
index 0000000..e46ac7e
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_table_response.json
@@ -0,0 +1,71 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "You can include table data like this"
+ }
+ },
+ {
+ "tableCard": {
+ "rows": [
+ {
+ "cells": [
+ {
+ "text": "row 1 item 1"
+ },
+ {
+ "text": "row 1 item 2"
+ },
+ {
+ "text": "row 1 item 3"
+ }
+ ],
+ "dividerAfter": true
+ },
+ {
+ "cells": [
+ {
+ "text": "row 2 item 1"
+ },
+ {
+ "text": "row 2 item 2"
+ },
+ {
+ "text": "row 2 item 3"
+ }
+ ],
+ "dividerAfter": true
+ }
+ ],
+ "columnProperties": [
+ {
+ "header": "header 1"
+ },
+ {
+ "header": "header 2"
+ },
+ {
+ "header": "header 3"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1531013042496/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_test_response.json b/common-mock/src/test/resources/df_sample_test_response.json
new file mode 100644
index 0000000..62916e7
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_test_response.json
@@ -0,0 +1,77 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the first simple response for a basic card."
+ }
+ },
+ {
+ "basicCard": {
+ "title": "Title: this is a title",
+ "subtitle": "This is a subtitle",
+ "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emoji 📱. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks",
+ "image": {
+ "url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
+ "accessibilityText": "Image alternate text"
+ },
+ "buttons": [
+ {
+ "title": "This is a button",
+ "openUrlAction": {
+ "url": "https://assistant.google.com/"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "simpleResponse": {
+ "textToSpeech": "This is the second simple response.",
+ "displayText": "This is the 2nd simple response."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1530842303910/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_sample_welcome_response.json b/common-mock/src/test/resources/df_sample_welcome_response.json
new file mode 100644
index 0000000..8b48c96
--- /dev/null
+++ b/common-mock/src/test/resources/df_sample_welcome_response.json
@@ -0,0 +1,59 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "Hi there!",
+ "displayText": "Hello there!"
+ }
+ },
+ {
+ "simpleResponse": {
+ "textToSpeech": "I can show you basic cards, lists and carousels as well as suggestions on your phone.",
+ "displayText": "I can show you basic cards, lists and carousels as well as suggestions."
+ }
+ }
+ ],
+ "suggestions": [
+ {
+ "title": "Basic Card"
+ },
+ {
+ "title": "Browse Carousel"
+ },
+ {
+ "title": "Carousel"
+ },
+ {
+ "title": "List"
+ },
+ {
+ "title": "Media"
+ },
+ {
+ "title": "Suggestions"
+ },
+ {
+ "title": "Table"
+ },
+ {
+ "title": "Test"
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-sample-v2/agent/sessions/1530842303910/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{}"
+ }
+ }
+ ]
+}
diff --git a/common-mock/src/test/resources/df_transaction_got_address.json b/common-mock/src/test/resources/df_transaction_got_address.json
new file mode 100644
index 0000000..42d6c4a
--- /dev/null
+++ b/common-mock/src/test/resources/df_transaction_got_address.json
@@ -0,0 +1,26 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "Great, got your address! Now say \"confirm transaction\"."
+ }
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}"
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-v2-transactions/agent/sessions/1531419984314/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{\"deliveryAddress\":{\"zipCode\":\"27525\",\"postalAddress\":{\"regionCode\":\"US\",\"recipients\":[\"Patrick Jackson\"],\"postalCode\":\"27525\",\"locality\":\"FRANKLINTON\",\"addressLines\":[\"165 SUTHERLAND DR\"],\"administrativeArea\":\"NC\"},\"phoneNumber\":\"9196076160\",\"city\":\"FRANKLINTON\",\"coordinates\":{\"latitude\":36.080033,\"longitude\":-78.507623}}}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common-mock/src/test/resources/df_transactions_confirm_transaction.json b/common-mock/src/test/resources/df_transactions_confirm_transaction.json
new file mode 100644
index 0000000..db81017
--- /dev/null
+++ b/common-mock/src/test/resources/df_transactions_confirm_transaction.json
@@ -0,0 +1,201 @@
+{
+ "payload": {
+ "google": {
+ "expectUserResponse": true,
+ "richResponse": {
+ "items": [
+ {
+ "simpleResponse": {
+ "textToSpeech": "PLACEHOLDER"
+ }
+ }
+ ]
+ },
+ "userStorage": "{\"data\":{}}",
+ "systemIntent": {
+ "intent": "actions.intent.TRANSACTION_DECISION",
+ "data": {
+ "@type": "type.googleapis.com/google.actions.v2.TransactionDecisionValueSpec",
+ "orderOptions": {
+ "requestDeliveryAddress": true
+ },
+ "paymentOptions": {
+ "actionProvidedOptions": {
+ "paymentType": "PAYMENT_CARD",
+ "displayName": "VISA-1234"
+ }
+ },
+ "proposedOrder": {
+ "id": "",
+ "cart": {
+ "merchant": {
+ "id": "book_store_1",
+ "name": "Book Store"
+ },
+ "lineItems": [
+ {
+ "name": "My Memoirs",
+ "id": "memoirs_1",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 990000000,
+ "units": 3
+ },
+ "type": "ACTUAL"
+ },
+ "quantity": 1,
+ "subLines": [
+ {
+ "note": "Note from the author"
+ }
+ ],
+ "type": "REGULAR"
+ },
+ {
+ "name": "Memoirs of a person",
+ "id": "memoirs_2",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 990000000,
+ "units": 5
+ },
+ "type": "ACTUAL"
+ },
+ "quantity": 1,
+ "subLines": [
+ {
+ "note": "Special introduction by author"
+ }
+ ],
+ "type": "REGULAR"
+ },
+ {
+ "name": "Their memoirs",
+ "id": "memoirs_3",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 750000000,
+ "units": 15
+ },
+ "type": "ACTUAL"
+ },
+ "quantity": 1,
+ "subLines": [
+ {
+ "lineItem": {
+ "name": "Special memoir epilogue",
+ "id": "memoirs_epilogue",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 990000000,
+ "units": 3
+ },
+ "type": "ACTUAL"
+ },
+ "quantity": 1,
+ "type": "REGULAR"
+ }
+ }
+ ],
+ "type": "REGULAR"
+ },
+ {
+ "name": "Our memoirs",
+ "id": "memoirs_4",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 490000000,
+ "units": 6
+ },
+ "type": "ACTUAL"
+ },
+ "quantity": 1,
+ "subLines": [
+ {
+ "note": "Special introduction by author"
+ }
+ ],
+ "type": "REGULAR"
+ }
+ ],
+ "notes": "The Memoir collection",
+ "otherItems": [
+ {
+ "name": "Subtotal",
+ "id": "subtotal",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 220000000,
+ "units": 32
+ },
+ "type": "ESTIMATE"
+ },
+ "type": "SUBTOTAL"
+ },
+ {
+ "name": "Tax",
+ "id": "tax",
+ "price": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 780000000,
+ "units": 2
+ },
+ "type": "ESTIMATE"
+ },
+ "type": "TAX"
+ }
+ ]
+ },
+ "otherItems": [],
+ "totalPrice": {
+ "amount": {
+ "currencyCode": "USD",
+ "nanos": 0,
+ "units": 35
+ },
+ "type": "ESTIMATE"
+ },
+ "extension": {
+ "@type": "type.googleapis.com/google.actions.v2.orders.GenericExtension",
+ "locations": [
+ {
+ "type": "DELIVERY",
+ "location": {
+ "postalAddress": {
+ "regionCode": "US",
+ "recipients": [
+ "Patrick Jackson"
+ ],
+ "postalCode": "27525",
+ "locality": "FRANKLINTON",
+ "addressLines": [
+ "165 SUTHERLAND DR"
+ ],
+ "administrativeArea": "NC"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "outputContexts": [
+ {
+ "name": "projects/df-v2-transactions/agent/sessions/1531419984314/contexts/_actions_on_google",
+ "lifespanCount": 99,
+ "parameters": {
+ "data": "{\"deliveryAddress\":{\"zipCode\":\"27525\",\"postalAddress\":{\"regionCode\":\"US\",\"recipients\":[\"Patrick Jackson\"],\"postalCode\":\"27525\",\"locality\":\"FRANKLINTON\",\"addressLines\":[\"165 SUTHERLAND DR\"],\"administrativeArea\":\"NC\"},\"phoneNumber\":\"9196076160\",\"city\":\"FRANKLINTON\",\"coordinates\":{\"latitude\":36.080033,\"longitude\":-78.507623}}}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/common/build.gradle b/common/build.gradle
new file mode 100644
index 0000000..2281f43
--- /dev/null
+++ b/common/build.gradle
@@ -0,0 +1,31 @@
+apply plugin: 'kotlin-platform-common'
+
+archivesBaseName = 'actions-on-google-common'
+
+configurations {
+ testArtifacts
+}
+
+task testJar (type: Jar) {
+ baseName = "$project.name}-test"
+ from sourceSets.test.output
+}
+
+artifacts {
+ testArtifacts testJar
+}
+
+dependencies {
+ compile libraries.kotlin_stdlib_common
+ testCompile libraries.kotlin_test_annotations_common
+ testCompile libraries.kotlin_test_common
+}
+
+task sourcesJar(type: Jar) {
+ classifier = 'sources'
+ from sourceSets.main.kotlin
+}
+
+artifacts {
+ archives sourcesJar
+}
diff --git a/common/src/main/kotlin/actions/Assistant.kt b/common/src/main/kotlin/actions/Assistant.kt
new file mode 100644
index 0000000..7771e68
--- /dev/null
+++ b/common/src/main/kotlin/actions/Assistant.kt
@@ -0,0 +1,158 @@
+package actions
+
+import actions.framework.*
+import actions.expected.BuiltinFrameworks
+import actions.expected.Serializer
+import actions.expected.log
+import actions.service.actionssdk.ActionsSdk
+import actions.service.actionssdk.ActionsSdkIntentHandler4
+import actions.service.actionssdk.conversation.Conversation
+import actions.service.dialogflow.DialogflowIntentHandler4
+
+
+abstract class AppHandler: BaseApp()
+
+interface AppOptions {
+ var debug: Boolean?
+}
+
+abstract class ServiceBaseApp {
+ operator fun invoke(vararg args: Any) {
+ omni?.handle(*args)
+ }
+
+ var omni: OmniHandler? = null
+
+ abstract var handler: StandardHandler
+}
+
+//interface Plugin, PluginResult> {
+// (app: AppHandler & TService & TApp): (AppHandler & TService & TApp & TPlugin) | void
+//}
+
+data class SerivcePlugin(val service: TService,
+ val pluging: TPlugin)
+
+data class BaseAppPlugin(val baseApp: BaseApp,
+ val pluging: TPlugin)
+
+
+typealias Plugin = ((PluginApp) -> PluginResult)
+
+data class PluginApp(val app: AppHandler,
+ val service: TService,
+ val tApp: TApp)
+
+data class PluginResult(val app: AppHandler,
+ val service: TService,
+ val tApp: TApp,
+ val plugin: TPlugin)
+
+abstract class BaseApp: ServiceBaseApp() {
+ abstract var frameworks: BuiltinFrameworks
+
+
+ abstract fun use(plugin: Plugin): BaseAppPlugin
+
+ abstract var debug: Boolean
+}
+
+fun create(options: AppOptions? = null): BaseApp {
+// BaseApp(
+// frameworks: Object. assign ({}, builtin),
+// handler: () => Promise.reject(new Error('StandardHandler not set')),
+// use(plugin) {
+// return plugin(this) || this
+// },
+// debug:!!(options && options.debug))
+ return object: BaseApp() {
+ override var handler: StandardHandler
+ get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
+ set(value) {}
+ override var frameworks: BuiltinFrameworks
+ get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
+ set(value) {}
+
+ override fun use(plugin: Plugin): BaseAppPlugin {
+ TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ }
+
+ override var debug: Boolean
+ get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
+ set(value) {}
+
+ }
+}
+
+//equivalent of (AppHandler & TService) mixin
+data class AttachedAppHandlerService(val handler: AppHandler,
+ val service: TService)
+
+data class AttachedBaseAppService(val baseApp: BaseApp,
+ val service: TService)
+
+data class AttachResult(
+ val baseApp: BaseApp,
+ val handler: StandardHandler,
+ val service: TService)
+
+abstract class AppResult: BaseApp(), StandardHandler {
+
+}
+
+fun , TUserStorage> attach(
+ service: ActionsSdk,
+ options: AppOptions? = null): AppResult {
+
+ val baseApp = create(options)
+ val omni = object: OmniHandler {
+ override fun handle(vararg args: Any): Any {
+ for (framework in baseApp.frameworks) {
+ if(framework.check(args)) {
+ return framework.handle(baseApp.handler).handle(args)
+ }
+ }
+ return baseApp.handler.handle(args[0] as Conversation, args[1] as Headers)
+ }
+ }
+
+ var handler = baseApp.handler
+ val standard = object: StandardHandler {
+ override fun handle(body: Any, headers: Headers, overrideHandler: DialogflowIntentHandler4?, aogOverrideHandler: ActionsSdkIntentHandler4?): StandardResponse {
+ log("Request", Serializer.serialize(body))
+ log("Headers", Serializer.serialize(headers))
+ val response = /* await */ handler.handle(body, headers)
+ response.headers?.get("content-type")?.add("application/json; charset=utf-8")
+ log("Response", Serializer.serialize(response))
+ return response
+ }
+ }
+ baseApp.omni = omni
+ baseApp.handler = standard
+
+// var appResult = object: OmniHandler by omni, actions.BaseApp by baseApp, actions.framework.StandardHandler by standardHandler, actions.ServiceBaseApp by service {
+//
+// }
+
+// var attachedResult = AttachResult(
+// baseApp = baseApp,
+// service = service,
+// omni = omni,
+// handler = standardHandler)
+
+ return object: AppResult() {
+ override var handler: StandardHandler
+ get() = standard
+ set(value) {handler = value}
+
+ override fun use(plugin: Plugin): BaseAppPlugin {
+ TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ }
+
+ override fun handle(body: Any, headers: Headers, overrideHandler: DialogflowIntentHandler4?, aogOverrideHandler: ActionsSdkIntentHandler4?): StandardResponse = standard.handle(body, headers)
+
+ override var frameworks: BuiltinFrameworks = baseApp.frameworks
+
+ override var debug: Boolean = baseApp.debug
+ }
+}
diff --git a/common/src/main/kotlin/actions/Common.kt b/common/src/main/kotlin/actions/Common.kt
new file mode 100644
index 0000000..c7b4588
--- /dev/null
+++ b/common/src/main/kotlin/actions/Common.kt
@@ -0,0 +1,69 @@
+package actions
+
+import actions.service.actionssdk.api.*
+import actions.service.actionssdk.conversation.SurfaceCapability
+
+const val name = "actions-on-google"
+
+
+///** @hidden */
+//const values = (o: { [key: string]: T }) => Object.keys(o).map(k => o[k])
+
+
+/**
+ * All possible fields are here, though only one spec used at any given time.
+ * To create a ProtoAny use _data(Spec.Type) { }
+ */
+data class ProtoAny(var `@type`: String? = null,
+ var dialogSpec: DialogSpecData? = null,
+ var optContext: String? = null,
+ var permissions: MutableList? = null,
+ var updatePermissionValueSpec: GoogleActionsV2UpdatePermissionValueSpec? = null,
+ var capabilities: MutableList? = null,
+ var context: String? = null,
+ var notificationTitle: String? = null,
+ var arguments: MutableList? = null,
+ var openUrlAction: GoogleActionsV2UiElementsOpenUrlAction? = null,
+ var triggerContext: GoogleActionsV2TriggerContext? = null,
+ var addressOptions: GoogleActionsV2DeliveryAddressValueSpecAddressOptions? = null,
+ var checkResult: MutableList? = null,
+ var deliveryAddress: GoogleActionsV2Location? = null,
+ var order: GoogleActionsV2OrdersOrder? = null,
+ var presentationOptions: GoogleActionsV2OrdersPresentationOptions? = null,
+ var proposedOrder: GoogleActionsV2OrdersProposedOrder? = null,
+ var userDecision: GoogleActionsV2TransactionDecisionValueUserDecision? = null,
+ var orderOptions: GoogleActionsV2OrdersOrderOptions? = null,
+ var paymentOptions: GoogleActionsV2OrdersPaymentOptions? = null,
+ var listSelect: GoogleActionsV2UiElementsListSelect? = null,
+ var carouselSelect: GoogleActionsV2UiElementsCarouselSelect? = null,
+ var locations: MutableList? = null,
+ var time: Time? = null) {
+
+ fun dialogSpec(init: DialogSpecData.() -> Unit) {
+
+ }
+
+ fun locations(vararg init: GoogleActionsV2OrdersOrderLocation.() -> Unit) {
+ this.locations = init.map {
+ val location = GoogleActionsV2OrdersOrderLocation()
+ location.it()
+ location
+ }.toMutableList()
+ }
+}
+
+data class Time(var type: GoogleActionsV2OrdersTimeType? = null, var time_iso8601: String? = null)
+
+data class DialogSpecData(var `@type`: String? = null,
+ var permissionContext: String? = null,
+ var requestPrompt: String? = null,
+ var destinationName: String? = null,
+ var requestLinkReason: String? = null,
+ var requestDatetimeText: String? = null,
+ var requestDateText: String? = null,
+ var requestTimeText: String? = null,
+ var requestConfirmationText: String? = null)
+
+
+/** @hidden */
+class ApiClientObjectMap : MutableMap by mutableMapOf()
diff --git a/common/src/main/kotlin/actions/expected/BuiltInFrameworks.kt b/common/src/main/kotlin/actions/expected/BuiltInFrameworks.kt
new file mode 100644
index 0000000..8158bf8
--- /dev/null
+++ b/common/src/main/kotlin/actions/expected/BuiltInFrameworks.kt
@@ -0,0 +1,17 @@
+package actions.expected
+import actions.framework.Frameworks
+
+
+expect class BuiltinFrameworks() :Frameworks {
+ /**
+ * Plug and play web framework support for express using body-parser
+ * @public
+ */
+// var express: Express
+
+ /**
+ * Plug and play web framework support for lambda API gateway
+ * @public
+ */
+// var lambda: Lambda
+}
\ No newline at end of file
diff --git a/common/src/main/kotlin/actions/expected/Expected.kt b/common/src/main/kotlin/actions/expected/Expected.kt
new file mode 100644
index 0000000..c892d66
--- /dev/null
+++ b/common/src/main/kotlin/actions/expected/Expected.kt
@@ -0,0 +1,64 @@
+package actions.expected
+
+import actions.service.actionssdk.api.GoogleActionsV2Location
+
+/*
+ Classes that must have platform specific implementations. May need refactoring into separate files
+ */
+
+expect class Date(timeStamp: String? = null) {
+ fun toISOString(): String?
+
+}
+
+
+data class TokenPayload(val accessToken: String? = null,
+ val email: String? = null)
+
+data class LoginTicket(var tokenPayload: TokenPayload? = null) {
+ fun getPayload(): TokenPayload? {
+ return null
+ }
+}
+
+data class IdToken(var idToken: String? = null,
+ var audience: String? = null)
+
+expect class OAuth2Client(clientId: String) {
+ fun verifyIdToken(idToken: IdToken): LoginTicket
+}
+
+
+expect fun deserialize(json: String?): T?
+
+
+expect fun log(message: String, vararg optionalParameters: Any?)
+
+fun info(message: String) {
+
+}
+
+fun warn(message: String) {
+
+}
+
+fun error(message: String, exception: Exception) {
+}
+
+
+data class ConversationTokenData(var data: Any? = null)
+
+
+expect object Serializer {
+ fun stringifyConversationToken(data: Any?): ConversationTokenData
+ fun serialize(any: Any?): String?
+ fun deserializeMap(json: String): MutableMap
+}
+
+
+expect val MutableMap.deliveryAddress: GoogleActionsV2Location?
+val Test.delivery: GoogleActionsV2Location?
+ get() = null
+
+typealias Test = MutableMap
+
diff --git a/common/src/main/kotlin/actions/expected/GoogleAuthLib.kt b/common/src/main/kotlin/actions/expected/GoogleAuthLib.kt
new file mode 100644
index 0000000..b2c9baa
--- /dev/null
+++ b/common/src/main/kotlin/actions/expected/GoogleAuthLib.kt
@@ -0,0 +1,9 @@
+package actions.expected
+
+
+/**
+ *
+ */
+expect class GoogleAuthLib {
+ fun asyncVerify()
+}
diff --git a/common/src/main/kotlin/actions/framework/Framework.kt b/common/src/main/kotlin/actions/framework/Framework.kt
new file mode 100644
index 0000000..5001e69
--- /dev/null
+++ b/common/src/main/kotlin/actions/framework/Framework.kt
@@ -0,0 +1,54 @@
+package actions.framework
+
+import actions.service.actionssdk.ActionsSdkIntentHandler4
+import actions.service.dialogflow.DialogflowIntentHandler4
+
+//import kotlinx.coroutines.experimental.Deferred
+
+
+abstract class Frameworks: MutableList> by mutableListOf() {
+}
+
+interface OmniHandler {
+ fun handle(vararg args: Any): Any
+}
+
+interface Framework {
+ fun handle(base: StandardHandler): OmniHandler
+
+ // tslint:disable-next-line:no-any detect if it is the correct framework from any parameter type
+ fun check(vararg args: Any): Boolean
+}
+
+//typealias OmniHandler = StandardHandler/*, ExpressHandler, LambdaHandler*/ //{
+ // tslint:disable-next-line:no-any allow any inputs and outputs depending on framework
+// (...args: any[]): any
+//}
+
+
+///** @hidden */
+//val builtin: BuiltinFrameworks = {
+// express,
+// lambda,
+//}
+
+data class StandardResponse(
+ var status: Int? = null,
+ var body: JsonObject? = null,
+ var headers: Headers? = null)
+
+typealias Headers = MutableMap>
+//interface Headers {
+// /** @public */
+// [header: string]: string | string[] | undefined
+//}
+
+//typealias StandardHandler = (body: JsonObject, headers: Headers) -> StandardResponse //TODO Promise or deferred
+
+interface StandardHandler {
+ fun handle(body: Any, headers: Headers,
+ overrideHandler: DialogflowIntentHandler4? = null,
+ aogOverrideHandler: ActionsSdkIntentHandler4? = null): StandardResponse //TODO Promise or deferred
+}
+
+typealias JsonObject = Any
diff --git a/common/src/main/kotlin/actions/service/actionssdk/ActionsSdk.kt b/common/src/main/kotlin/actions/service/actionssdk/ActionsSdk.kt
new file mode 100644
index 0000000..d635805
--- /dev/null
+++ b/common/src/main/kotlin/actions/service/actionssdk/ActionsSdk.kt
@@ -0,0 +1,451 @@
+package actions.service.actionssdk
+
+import actions.*
+import actions.expected.*
+import actions.framework.*
+import actions.service.actionssdk.api.GoogleActionsV2AppRequest
+import actions.service.actionssdk.api.GoogleActionsV2Argument
+import actions.service.actionssdk.api.GoogleRpcStatus
+import actions.service.actionssdk.conversation.*
+import actions.service.dialogflow.DialogflowIntentHandler4
+
+typealias ActionsSdkIntentHandler1 = (conv: ActionsSdkConversation) -> Any
+typealias ActionsSdkIntentHandler2 = (conv: ActionsSdkConversation, argument: Any) -> Any
+typealias ActionsSdkIntentHandler3 = (conv: ActionsSdkConversation, argument: Any, arg: GoogleActionsV2Argument?) -> Any
+typealias ActionsSdkIntentHandler4 = (conv: ActionsSdkConversation, argument: Any, arg: GoogleActionsV2Argument?, status: GoogleRpcStatus?) -> Any
+
+class ActionSdkIntentHandlers : MutableMap?> by mutableMapOf()
+
+data class ActionsSdkHandlers(
+ var intents: ActionSdkIntentHandlers = ActionSdkIntentHandlers(),
+ var catcher: ExceptionHandler>? = null, //TODO provide defaults for these nulls
+ var fallback: ActionsSdkIntentHandler4? = null
+)
+
+interface ActionsSdkMiddleware
+//<
+// TConversationPlugin: ActionsSdkConversation<*, *>> {
+// (conv: ActionsSdkConversation<*, *>): (ActionsSdkConversation<*,*> & TConversationPlugin) | void
+//}
+
+/** @public */
+abstract class ActionsSdkApp : ConversationApp() {
+ /** @hidden */
+ abstract var _handlers: ActionsSdkHandlers
+
+ /**
+ * Sets the IntentHandler to be executed when the fulfillment is called
+ * with a given Actions SDK intent.
+ *
+ * @param intent The Actions SDK intent to match.
+ * When given an array, sets the IntentHandler for any intent in the array.
+ * @param handler The IntentHandler to be executed when the intent is matched.
+ * When given a string instead of a function, the intent fulfillment will be redirected
+ * to the IntentHandler of the redirected intent.
+ * @public
+ */
+ abstract fun intent(intents: MutableList, handler: ActionsSdkIntentHandler1 /*| Intent,*/): ActionsSdkApp
+ abstract fun intent(intents: MutableList, handler: ActionsSdkIntentHandler2 /*| Intent,*/): ActionsSdkApp
+ abstract fun intent(intents: MutableList, handler: ActionsSdkIntentHandler3 /*| Intent,*/): ActionsSdkApp
+ abstract fun intent(intents: MutableList, handler: ActionsSdkIntentHandler4 /*| Intent,*/): ActionsSdkApp
+
+ /**
+ * Sets the IntentHandler to be executed when the fulfillment is called
+ * with a given Actions SDK intent.
+ *
+ * @param intent The Actions SDK intent to match.
+ * When given an array, sets the IntentHandler for any intent in the array.
+ * @param handler The IntentHandler to be executed when the intent is matched.
+ * When given a string instead of a function, the intent fulfillment will be redirected
+ * to the IntentHandler of the redirected intent.
+ * @public
+ */
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler1 /*| string,*/): ActionsSdkApp
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler2 /*| string,*/): ActionsSdkApp
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler3 /*| string,*/): ActionsSdkApp
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler4 /*| string,*/): ActionsSdkApp
+
+ /** @public */
+ abstract fun catch(catcher: ExceptionHandler>): ActionsSdkApp
+
+ /** @public */
+ abstract fun fallback(handler: ActionsSdkIntentHandler3 /*| string,*/): ActionsSdkApp
+
+ /** @hidden */
+ abstract var _middlewares: MutableList
+
+ /** @public */
+ abstract fun > middleware(middleware: ActionsSdkMiddleware): ActionsSdkApp
+
+ /** @public */
+ abstract var verification: ActionsSdkVerification? //| string
+}
+
+abstract class BaseService : ConversationApp() {
+ /** @hidden */
+ abstract var _handlers: THandler//
+
+ /**
+ * Sets the IntentHandler to be executed when the fulfillment is called
+ * with a given Actions SDK intent.
+ *
+ * @param intent The Actions SDK intent to match.
+ * When given an array, sets the IntentHandler for any intent in the array.
+ * @param handler The IntentHandler to be executed when the intent is matched.
+ * When given a string instead of a function, the intent fulfillment will be redirected
+ * to the IntentHandler of the redirected intent.
+ * @public
+ */
+ abstract fun intent(intents: MutableList, handler: TIntentHandler): ActionsSdkApp
+
+ /**
+ * Sets the IntentHandler to be executed when the fulfillment is called
+ * with a given Actions SDK intent.
+ *
+ * @param intent The Actions SDK intent to match.
+ * When given an array, sets the IntentHandler for any intent in the array.
+ * @param handler The IntentHandler to be executed when the intent is matched.
+ * When given a string instead of a function, the intent fulfillment will be redirected
+ * to the IntentHandler of the redirected intent.
+ * @public
+ */
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler1): ActionsSdkApp
+
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler2): ActionsSdkApp
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler3): ActionsSdkApp
+ abstract fun intent(vararg intents: String, handler: ActionsSdkIntentHandler4): ActionsSdkApp
+
+ /** @public */
+ abstract fun catch(catcher: ExceptionHandler>): ActionsSdkApp
+
+ /** @public */
+ abstract fun fallback(handler: ActionsSdkIntentHandler3 ): ActionsSdkApp
+
+ /** @hidden */
+ abstract var _middlewares: MutableList
+
+ /** @public */
+ abstract fun > middleware(middleware: ActionsSdkMiddleware): ActionsSdkApp
+
+ /** @public */
+ abstract var verification: ActionsSdkVerification? //| string
+}
+
+interface ActionsSdkVerification {
+ /**
+ * Google Cloud Project ID for the Assistant app.
+ * @public
+ */
+ var project: String
+
+ /**
+ * Custom status code to return on verification error.
+ * @public
+ */
+ var status: Int?
+
+ /**
+ * Custom error message as a string or a function that returns a string
+ * given the original error message set by the library.
+ *
+ * The message will get sent back in the JSON top level `error` property.
+ * @public
+ */
+ var error: String //| ((error: string) => string)
+}
+
+data class ActionsSdkOptions(
+ /**
+ * Validates whether request is from Google through signature verification.
+ * Uses Google-Auth-Library to verify authorization token against given Google Cloud Project ID.
+ * Auth token is given in request header with key, "authorization".
+ *
+ * HTTP Code 403 will be thrown by default on verification error.
+ *
+ * @example
+ * ```javascript
+ *
+ * const app = actionssdk({ verification: 'nodejs-cloud-test-project-1234' })
+ * ```
+ *
+ * @public
+ */
+ var verification: ActionsSdkVerification? = null,
+ override var init: (() -> ConversationOptionsInit)? = null,
+ override var clientId: String? = null,
+ override var debug: Boolean? = null
+) : ConversationAppOptions
+
+/**
+ * This is the function that creates the app instance which on new requests,
+ * creates a way to interact with the conversation API directly from Assistant,
+ * providing implementation for all the methods available in the API.
+ *
+ * Only supports Actions SDK v2.
+ *
+ * @example
+ * ```javascript
+ *
+ * const app = actionssdk()
+ *
+ * app.intent('actions.intent.MAIN', conv => {
+ * conv.ask('How are you?')
+ * })
+ * ```
+ *
+ * @public
+ */
+
+fun actionssdk(options: ActionsSdkOptions? = null): ActionsSdk {
+ return ActionsSdk(options)
+}
+
+fun actionssdk(init: (ActionsSdkOptions.() -> Unit)? = null): ActionsSdk {
+ val options = ActionsSdkOptions()
+ options.init?.invoke()
+ return ActionsSdk(options)
+}
+
+class ActionsSdk(options: ActionsSdkOptions? = null) : ActionsSdkApp() {
+
+
+ override lateinit var frameworks: BuiltinFrameworks
+
+ override fun use(plugin: Plugin): BaseAppPlugin {
+ TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ }
+
+ override var debug: Boolean = false
+
+
+ override var _handlers: ActionsSdkHandlers = ActionsSdkHandlers(
+ intents = ActionSdkIntentHandlers(),
+ catcher = { conv, e -> throw e }
+ )
+
+ override fun intent(intents: MutableList, handler: ActionsSdkIntentHandler1): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent.value] = { conv, status, g, arg -> handler(conv) }
+ }
+ return this
+ }
+
+ override fun intent(intents: MutableList, handler: ActionsSdkIntentHandler2): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent.value] = { conv, status, g, arg -> handler(conv, status) }
+ }
+ return this
+ }
+
+ override fun intent(intents: MutableList, handler: ActionsSdkIntentHandler3): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent.value] = { conv, status, g, arg -> handler(conv, status, g) }
+ }
+ return this
+ }
+
+ override fun intent(intents: MutableList, handler: ActionsSdkIntentHandler4): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent.value] = { conv, status, g, arg -> handler(conv, status, g, arg) }
+ }
+ return this
+ }
+
+ override fun intent(vararg intents: String, handler: ActionsSdkIntentHandler1): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent] = { conv, status, g, arg -> handler(conv) }
+ }
+ return this
+ }
+
+ override fun intent(vararg intents: String, handler: ActionsSdkIntentHandler2): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent] = { conv, status, g, arg -> handler(conv, status) }
+ }
+ return this
+ }
+
+ override fun intent(vararg intents: String, handler: ActionsSdkIntentHandler3): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent] = { conv, status, g, arg -> handler(conv, status, g) }
+ }
+ return this
+ }
+
+ override fun intent(vararg intents: String, handler: ActionsSdkIntentHandler4): ActionsSdkApp {
+ for (intent in intents) {
+ this._handlers.intents[intent] = handler
+ }
+ return this
+ }
+
+ override fun catch(catcher: ExceptionHandler>): ActionsSdkApp {
+ this._handlers.catcher = catcher
+ return this
+ }
+
+ override fun fallback(handler: ActionsSdkIntentHandler3): ActionsSdkApp {
+ this._handlers.fallback = { conv, status, g, arg -> handler.invoke(conv, status, g) }
+ return this
+ }
+
+ override var _middlewares: MutableList = mutableListOf()
+
+ override fun > middleware(middleware: ActionsSdkMiddleware): ActionsSdkApp {
+ this._middlewares.push(middleware)
+ return this
+ }
+
+ override var verification: ActionsSdkVerification? = options?.verification
+
+ override var init: (() -> ConversationOptionsInit)? = options?.init
+
+ override var auth: OAuth2Config? = if (options?.clientId != null) OAuth2Config(client = OAuth2ConfigClient(id = options.clientId)) else null
+
+ override var _client: OAuth2Client? = if (options?.verification != null || options?.clientId != null)
+ OAuth2Client(options.clientId!!) else null
+
+ override var handler: StandardHandler = object : StandardHandler {
+ override fun handle(body: Any, headers: Headers, overrideHandler: DialogflowIntentHandler4?, aogOverrideHandler: ActionsSdkIntentHandler4?): StandardResponse {
+ val convBody = body as GoogleActionsV2AppRequest
+ val debug: Boolean = options?.debug ?: false
+ val init = init
+ val verification = verification
+ if (verification != null) {
+ val project = verification.status
+ val status = 403
+ val error = verification.error
+ //} = typeof verification === 'string' ? { project: verification } : verification
+ val token = headers["authorization"]?.firstOrNull()
+ try {
+ _client!!.verifyIdToken(IdToken(
+ idToken = token,
+ audience = project.toString())
+ )
+ } catch (e: Exception) {
+ return StandardResponse(
+ status = status,
+ body = WebhookError(
+ error = error) //typeof error === 'string' ? error :
+ //error(`ID token verification failed: ${e.stack || e.message || e}`),
+ )
+ }
+ }
+
+ val conv = ActionsSdkConversation(ActionsSdkConversationOptions(
+ body = convBody,
+ headers = headers,
+ init = init?.invoke(), //init && init (),
+ debug = debug))
+
+ if (conv.user.profile?.token != null) {
+ /*await */ conv.user._verifyProfile(_client!!, auth!!.client?.id!!)
+ }
+ for (middleware in _middlewares) {
+// conv = (middleware(conv) as ActionsSdkConversation) //| void) || conv
+ }
+// val log = debug ? common.info : common.debug
+// log("Conversation", stringify(conv, {
+// request: null,
+// headers: null,
+// body: null,
+// }))
+ val intent = conv.intent
+ val traversedActionsHandlers: TraversedActionsHandlers = TraversedActionsHandlers()
+ var handler = aogOverrideHandler ?: _handlers.intents[intent]
+// while (typeof handler !== 'function') {
+ while (false) {
+ //TODO why is this loop here? handle intents mapped to a string?
+ if (handler == null) {
+ if (_handlers.fallback == null) {
+ throw Error("Actions SDK IntentHandler not found for intent: $intent")
+ }
+ handler = _handlers.fallback
+ break
+ }
+ if (traversedActionsHandlers[handler] == true) {
+ throw Error("Circular intent map detected: $handler traversed twice")
+ }
+ traversedActionsHandlers[handler] = true
+// handler = _handlers.intents[handler]
+ }
+ try {
+ /* await */ handler?.invoke(
+ conv,
+ conv.input.raw ?: "",
+ conv.arguments.raw?.input?.values?.firstOrNull(),
+// conv.arguments.parsed?.list?.firstOrNull(),
+ conv.arguments.status?.list?.firstOrNull()
+ )
+ } catch (e: Exception) {
+ //TODO provide default catcher
+ /*await */ _handlers.catcher?.invoke(conv, e)
+
+ }
+ return StandardResponse(
+ status = 200,
+ headers = mutableMapOf("Content-type" to mutableListOf("application/json; charset=UTF-8")),
+ body = conv.serialize()
+ )
+ }
+ }
+
+ init {
+ frameworks = BuiltinFrameworks()
+// val baseApp = create(options)
+ omni = object : OmniHandler {
+ override fun handle(vararg args: Any): Any {
+ log("Args in omniHandler: ${args.map { it.toString() }.joinToString { it }}")
+ for (framework in frameworks) {
+ if (framework.check(*args)) {
+ return framework.handle(handler).handle(*args)
+ }
+ }
+ return handler.handle(args[0] as GoogleActionsV2AppRequest, args[1] as Headers)
+ }
+ }
+
+// var handler = baseApp.handler
+ val standard = object : StandardHandler {
+ override fun handle(body: Any, headers: Headers, overrideHandler: DialogflowIntentHandler4?, aogOverrideHandler: ActionsSdkIntentHandler4?): StandardResponse {
+ val body = body as GoogleActionsV2AppRequest
+ log("Request", Serializer.serialize(body))
+ log("Headers", Serializer.serialize(headers))
+ val response = /* await */ handler.handle(body, headers)
+ response.headers?.get("content-type")?.add("application/json; charset=utf-8")
+ log("Response", Serializer.serialize(response))
+ return response
+ }
+ }
+// baseApp.omni = omni
+// baseApp.handler = standard
+
+// var appResult = object: OmniHandler by omni, actions.BaseApp by baseApp, actions.framework.StandardHandler by standardHandler, actions.ServiceBaseApp by service {
+//
+// }
+
+// var attachedResult = AttachResult(
+// baseApp = baseApp,
+// service = service,
+// omni = omni,
+// handler = standardHandler)
+
+// return object: AppResult() {
+// handler = standard
+
+ fun use(plugin: Plugin): BaseAppPlugin {
+ TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ }
+
+// override fun handle(body: JsonObject, headers: Headers): StandardResponse = standard.handle(body, headers)
+//
+// override var frameworks: BuiltinFrameworks = baseApp.frameworks
+//
+// override var debug: Boolean = baseApp.debug
+// }
+ }
+
+}
+
+data class WebhookError(var error: String? = null)
+
diff --git a/common/src/main/kotlin/actions/service/actionssdk/CommonExtensions.kt b/common/src/main/kotlin/actions/service/actionssdk/CommonExtensions.kt
new file mode 100644
index 0000000..4db66ff
--- /dev/null
+++ b/common/src/main/kotlin/actions/service/actionssdk/CommonExtensions.kt
@@ -0,0 +1,28 @@
+package actions.service.actionssdk
+
+import actions.service.actionssdk.conversation.response.GoogleActionsV2RichResponseItem
+
+fun MutableList.push(item: T): Unit =
+ if (size == 0) {
+ add(item)
+ Unit
+ } else {
+ add(0, item)
+ }
+
+fun MutableList.push(vararg items: T): Unit =
+ items.forEach {
+ if (size == 0) {
+ add(it)
+ Unit
+ } else {
+ add(0, it)
+ }
+ }
+
+fun MutableList.push(init: GoogleActionsV2RichResponseItem.() -> Unit): Unit {
+ val item = GoogleActionsV2RichResponseItem()
+ item.init()
+ push(item)
+}
+
diff --git a/common/src/main/kotlin/actions/service/actionssdk/Conv.kt b/common/src/main/kotlin/actions/service/actionssdk/Conv.kt
new file mode 100644
index 0000000..51b763c
--- /dev/null
+++ b/common/src/main/kotlin/actions/service/actionssdk/Conv.kt
@@ -0,0 +1,111 @@
+package actions.service.actionssdk
+
+import actions.expected.Serializer
+import actions.expected.deserialize
+import actions.framework.Headers
+import actions.service.actionssdk.api.*
+import actions.service.actionssdk.conversation.*
+
+
+data class ActionsSdkConversationOptions<
+ TUserStorage>(override var headers: Headers?,
+ var body: GoogleActionsV2AppRequest? = null,
+ override var init: ConversationOptionsInit? = null,
+ override var debug: Boolean? = null) : ConversationBaseOptions
+
+
+
+class ActionsSdkConversation(options: ActionsSdkConversationOptions) :
+ Conversation(options = ConversationOptions(request = options.body, headers = options.headers)) {
+
+ var body: GoogleActionsV2AppRequest?
+
+ /**
+ * Get the current Actions SDK intent.
+ *
+ * @example
+ * ```javascript
+ *
+ * app.intent('actions.intent.MAIN', conv => {
+ * const intent = conv.intent // will be 'actions.intent.MAIN'
+ * })
+ * ```
+ *
+ * @public
+ */
+ var intent: String
+
+ /**
+ * The session data in JSON format.
+ * Stored using conversationToken.
+ *
+ * @example
+ * ```javascript
+ *
+ * app.intent('actions.intent.MAIN', conv => {
+ * conv.data.someProperty = 'someValue'
+ * })
+ * ```
+ *
+ * @public
+ */
+ var data: MutableMap = mutableMapOf()
+
+ /** @public */
+ init {
+ this.body = options?.body
+
+ val body = options.body
+ val init = options
+
+ val inputs = body?.inputs ?: mutableListOf()
+ val firstInput = inputs.firstOrNull()
+
+ val intent = firstInput?.intent ?: ""
+ val conversation = body?.conversation
+ val conversationToken = conversation?.conversationToken
+
+ this.intent = intent
+
+ this.data = if (conversationToken != null) {
+ deserialize>(conversationToken) ?: mutableMapOf()
+ } else {
+ mutableMapOf()
+// TODO("Find way to do this in kotlin, or delegate to platform")
+// ((init && init.data) || {})
+ }
+ }
+
+ fun serialize(): GoogleActionsV2AppResponse {
+ if (this._raw != null) {
+ TODO("Find way to serialize. _raw as a string or JsonObject?")
+ return this._raw as GoogleActionsV2AppResponse //TODO REMOVE - ONLY HERE TO COMPILE
+ }
+ val response = this.response()
+
+ val richResponse = response.richResponse
+ val expectUserResponse = response.expectUserResponse
+ val userStorage = response.userStorage
+ val expectedIntent = response.expectedIntent
+
+ val inputPrompt = GoogleActionsV2InputPrompt(richInitialPrompt = richResponse,
+ noInputPrompts = response.noInputPrompts)
+
+ val possibleIntents = if (expectedIntent != null) {
+ mutableListOf(expectedIntent)
+ } else {
+ mutableListOf(GoogleActionsV2ExpectedIntentData(intent = IntentEnum.TEXT.value))
+ }
+ val expectedInput = GoogleActionsV2ExpectedInput(
+ inputPrompt = inputPrompt,
+ possibleIntents = possibleIntents)
+ val conversationToken = Serializer.stringifyConversationToken(this.data)
+
+ return GoogleActionsV2AppResponse(
+ expectUserResponse = expectUserResponse,
+ expectedInputs = if (expectUserResponse == true) mutableListOf(expectedInput) else null,
+ finalResponse = if (expectUserResponse == true) null else GoogleActionsV2FinalResponse(richResponse = richResponse),
+ conversationToken = Serializer.serialize(conversationToken),
+ userStorage = userStorage)
+ }
+}
diff --git a/common/src/main/kotlin/actions/service/actionssdk/api/V2.kt b/common/src/main/kotlin/actions/service/actionssdk/api/V2.kt
new file mode 100644
index 0000000..6f558ac
--- /dev/null
+++ b/common/src/main/kotlin/actions/service/actionssdk/api/V2.kt
@@ -0,0 +1,2315 @@
+package actions.service.actionssdk.api
+
+import actions.ApiClientObjectMap
+import actions.ProtoAny
+import actions.service.actionssdk.conversation.response.GoogleActionsV2RichResponseItem
+import actions.service.actionssdk.conversation.response.Image
+import actions.service.actionssdk.conversation.response.OrderUpdate
+import actions.service.actionssdk.conversation.response.SimpleResponse
+import actions.service.actionssdk.conversation.response.card.Button
+
+
+enum class GoogleActionsV2ConversationType {
+ TYPE_UNSPECIFIED,
+ NEW,
+ ACTIVE
+}
+
+
+enum class GoogleActionsV2DeliveryAddressValueUserDecision { UNKNOWN_USER_DECISION, ACCEPTED, REJECTED }
+
+enum class GoogleActionsV2EntitlementSkuType { TYPE_UNSPECIFIED, IN_APP, SUBSCRIPTION, APP }
+
+enum class GoogleActionsV2MediaResponseMediaType { MEDIA_TYPE_UNSPECIFIED, AUDIO }
+
+enum class GoogleActionsV2MediaStatusStatus { STATUS_UNSPECIFIED, FINISHED }
+
+enum class GoogleActionsV2NewSurfaceValueStatus { NEW_SURFACE_STATUS_UNSPECIFIED, CANCELLED, OK }
+
+enum class GoogleActionsV2OrdersActionProvidedPaymentOptionsPaymentType { PAYMENT_TYPE_UNSPECIFIED, PAYMENT_CARD, BANK, LOYALTY_PROGRAM, ON_FULFILLMENT, GIFT_CARD }
+
+enum class GoogleActionsV2OrdersCustomerInfoOptionsCustomerInfoProperties { CUSTOMER_INFO_PROPERTY_UNSPECIFIED, EMAIL }
+
+enum class GoogleActionsV2OrdersGoogleProvidedPaymentOptionsSupportedCardNetworks { UNSPECIFIED_CARD_NETWORK, AMEX, DISCOVER, MASTERCARD, VISA, JCB }
+
+enum class GoogleActionsV2OrdersLineItemType { UNSPECIFIED, REGULAR, TAX, DISCOUNT, GRATUITY, DELIVERY, SUBTOTAL, FEE }
+
+enum class GoogleActionsV2OrdersOrderLocationType { UNKNOWN, DELIVERY, BUSINESS, ORIGIN, DESTINATION, PICK_UP }
+
+enum class GoogleActionsV2OrdersOrderUpdateActionType { UNKNOWN, VIEW_DETAILS, MODIFY, CANCEL, RETURN, EXCHANGE, EMAIL, CALL, REORDER, REVIEW, CUSTOMER_SERVICE, FIX_ISSUE }
+
+enum class GoogleActionsV2OrdersPaymentInfoPaymentType { PAYMENT_TYPE_UNSPECIFIED, PAYMENT_CARD, BANK, LOYALTY_PROGRAM, ON_FULFILLMENT, GIFT_CARD }
+
+enum class GoogleActionsV2OrdersPaymentMethodTokenizationParametersTokenizationType { UNSPECIFIED_TOKENIZATION_TYPE, PAYMENT_GATEWAY, DIRECT }
+
+enum class GoogleActionsV2OrdersPriceType { UNKNOWN, ESTIMATE, ACTUAL }
+
+enum class GoogleActionsV2OrdersRejectionInfoType { UNKNOWN, PAYMENT_DECLINED, INELIGIBLE, PROMO_NOT_APPLICABLE, UNAVAILABLE_SLOT }
+
+enum class GoogleActionsV2OrdersTimeType { UNKNOWN, DELIVERY_DATE, ETA, RESERVATION_SLOT }
+
+enum class GoogleActionsV2PermissionValueSpecPermissions { UNSPECIFIED_PERMISSION, NAME, DEVICE_PRECISE_LOCATION, DEVICE_COARSE_LOCATION, UPDATE }
+
+enum class GoogleActionsV2RawInputInputType { UNSPECIFIED_INPUT_TYPE, TOUCH, VOICE, KEYBOARD }
+
+enum class GoogleActionsV2RegisterUpdateValueStatus { REGISTER_UPDATE_STATUS_UNSPECIFIED, OK, CANCELLED }
+
+enum class GoogleActionsV2SignInValueStatus { SIGN_IN_STATUS_UNSPECIFIED, OK, CANCELLED, ERROR }
+
+enum class GoogleActionsV2TransactionDecisionValueUserDecision { UNKNOWN_USER_DECISION, ORDER_ACCEPTED, ORDER_REJECTED, DELIVERY_ADDRESS_UPDATED, CART_CHANGE_REQUESTED }
+
+enum class GoogleActionsV2TransactionRequirementsCheckResultResultType { RESULT_TYPE_UNSPECIFIED, OK, USER_ACTION_REQUIRED, ASSISTANT_SURFACE_NOT_SUPPORTED, REGION_NOT_SUPPORTED }
+
+enum class GoogleActionsV2TriggerContextTimeContextFrequency { FREQUENCY_UNSPECIFIED, DAILY, ROUTINES }
+
+enum class GoogleActionsV2UiElementsBasicCardImageDisplayOptions { DEFAULT, WHITE, CROPPED }
+
+enum class GoogleActionsV2UiElementsCarouselBrowseImageDisplayOptions { DEFAULT, WHITE, CROPPED }
+
+enum class GoogleActionsV2UiElementsCarouselSelectImageDisplayOptions { DEFAULT, WHITE, CROPPED }
+
+enum class GoogleActionsV2UiElementsOpenUrlActionUrlTypeHint { URL_TYPE_HINT_UNSPECIFIED, AMP_CONTENT }
+
+enum class GoogleActionsV2UiElementsTableCardColumnPropertiesHorizontalAlignment { LEADING, CENTER, TRAILING }
+
+enum class GoogleActionsV2UserPermissions { UNSPECIFIED_PERMISSION, NAME, DEVICE_PRECISE_LOCATION, DEVICE_COARSE_LOCATION, UPDATE }
+
+
+open class GoogleActionsV2AppRequest {
+ /**
+ * Surfaces available for cross surface handoff.
+ */
+ var availableSurfaces: MutableList? = null
+ /**
+ * Holds session data like the conversation ID and conversation token.
+ */
+ var conversation: GoogleActionsV2Conversation? = null
+ /**
+ * Information about the device the user is using to interact with the app.
+ */
+ var device: GoogleActionsV2Device? = null
+ /**
+ * List of inputs corresponding to the expected inputs specified by the app.
+ * For the initial conversation trigger, the input contains information on
+ * how the user triggered the conversation.
+ */
+ var inputs: MutableList? = null
+ /**
+ * Indicates whether the request should be handled in sandbox mode.
+ */
+ var isInSandbox: Boolean? = null
+ /**
+ * Information about the surface the user is interacting with, e.g. whether it
+ * can output audio or has a screen.
+ */
+ var surface: GoogleActionsV2Surface? = null
+ /**
+ * User who initiated the conversation.
+ */
+ var user: GoogleActionsV2User? = null
+
+ var sender: Sender? = null
+}
+
+data class Sender(val id: String? = null)
+
+data class GoogleActionsV2AppResponse(
+ /**
+ * An opaque token that is recirculated to the app every conversation
+ * turn.
+ */
+ var conversationToken: String? = null,
+ /**
+ * Custom Push Message allows developers to send structured data to Google
+ * for interactions on the Assistant.
+ */
+ var customPushMessage: GoogleActionsV2CustomPushMessage? = null,
+ /**
+ * Indicates whether the app is expecting a user response. This is true when
+ * the conversation is ongoing, false when the conversation is done.
+ */
+ var expectUserResponse: Boolean? = null,
+ /**
+ * List of inputs the app expects, each input can be a built-in intent, or an
+ * input taking list of possible intents. Only one input is supported for now.
+ */
+ var expectedInputs: MutableList? = null,
+ /**
+ * Final response when the app does not expect user's input.
+ */
+ var finalResponse: GoogleActionsV2FinalResponse? = null,
+ /**
+ * Indicates whether the response should be handled in sandbox mode. This
+ * bit is needed to push structured data to Google in sandbox mode.
+ */
+ var isInSandbox: Boolean? = null,
+ /**
+ * Whether to clear the persisted user_storage. If set to true, then in the
+ * next interaction with the user, the user_storage field will be empty.
+ */
+ var resetUserStorage: Boolean? = null,
+ /**
+ * An opaque token controlled by the application that is persisted across
+ * conversations for a particular user. If empty or unspecified, the
+ * existing persisted token will be unchanged.
+ * The maximum size of the string is 10k bytes.
+ * If multiple dialogs are occurring concurrently for the same user, then
+ * updates to this token can overwrite each other unexpectedly.
+ */
+ var userStorage: String? = null)
+
+/**
+ * Hold data for TransactionCheckComplete, SignInStatus, TransactionDecision, NewSurfaceResult
+ */
+data class ArgumentExtension(
+ val `@type`: String = "",
+// val resultType: TransactionValues.ResultType = TransactionValues.ResultType.UNSPECIFIED,
+ val resultType: String? = null,
+ var userDecision: String = "",
+ var status: String = "",
+ var location: GoogleActionsV2Location? = null,
+ val order: OrderUpdate? = null)
+
+
+data class GoogleActionsV2Argument(
+ /**
+ * Specified when query pattern includes a `$org.schema.type.YesNo` type or
+ * expected input has a built-in intent: `actions.intent.CONFIRMATION`.
+ * NOTE: if the boolean value is missing, it represents `false`.
+ */
+ var boolValue: Boolean? = null,
+ /**
+ * Specified for the built-in intent: `actions.intent.DATETIME`.
+ */
+ var datetimeValue: GoogleActionsV2DateTime? = null,
+ /**
+ * Extension whose type depends on the argument.
+ * For example, if the argument name is `SIGN_IN` for the
+ * `actions.intent.SIGN_IN` intent, then this extension will
+ * contain a SignInValue value.
+ */
+// var extension: ApiClientObjectMap? = null,
+ var extension: ArgumentExtension? = null,
+ /**
+ * Specified for built-in intent: \"actions.intent.NUMBER\"
+ */
+ var floatValue: Float? = null,
+ /**
+ * Specified when query pattern includes a $org.schema.type.Number type or
+ * expected input has a built-in intent: \"assistant.intent.action.NUMBER\".
+ */
+ var intValue: String? = null,
+ /**
+ * Name of the argument being provided for the input.
+ */
+ var name: String? = null,
+ /**
+ * Specified when query pattern includes a $org.schema.type.Location type or
+ * expected input has a built-in intent: \"actions.intent.PLACE\".
+ */
+ var placeValue: GoogleActionsV2Location? = null,
+ /**
+ * The raw text, typed or spoken, that provided the value for the argument.
+ */
+ var rawText: String? = null,
+ /**
+ * Specified when an error was encountered while computing the argument. For
+ * example, the built-in intent \"actions.intent.PLACE\" can return an error
+ * status if the user denied the permission to access their device location.
+ */
+ var status: GoogleRpcStatus? = null,
+ /**
+ * Specified when Google needs to pass data value in JSON format.
+ */
+ var structuredValue: ApiClientObjectMap? = null,
+ /**
+ * Specified when query pattern includes a `$org.schema.type.Text` type or
+ * expected input has a built-in intent: `actions.intent.TEXT`, or
+ * `actions.intent.OPTION`. Note that for the `OPTION` intent, we set the
+ * `text_value` as option key, the `raw_text` above will indicate the raw
+ * span in user's query.
+ */
+ var textValue: String? = null,
+
+ /**** ADDED FOR KOTLIN ***/
+ var resultType: String? = null,
+
+ var userDecision: String? = null,
+
+ var location: GoogleActionsV2Location? = null,
+
+ var order: GoogleActionsV2OrdersOrder? = null
+)
+
+data class GoogleActionsV2Capability(
+ /**
+ * The name of the capability, e.g. `actions.capability.AUDIO_OUTPUT`
+ */
+ var name: String? = null
+)
+
+data class GoogleActionsV2ConfirmationValueSpec(
+ /**
+ * Configures dialog that asks for confirmation.
+ */
+ var dialogSpec: GoogleActionsV2ConfirmationValueSpecConfirmationDialogSpec? = null
+)
+
+data class GoogleActionsV2ConfirmationValueSpecConfirmationDialogSpec(
+ /**
+ * This is the question asked by confirmation sub-dialog. For example \"Are
+ * you sure about that?\"
+ */
+ var requestConfirmationText: String? = null
+)
+
+data class GoogleActionsV2Conversation(
+ /**
+ * Unique ID for the multi-turn conversation. It's assigned for the first
+ * turn. After that it remains the same for subsequent conversation turns
+ * until the conversation is terminated.
+ */
+ var conversationId: String? = null,
+ /**
+ * Opaque token specified by the app in the last conversation turn. It can
+ * be used by an app to track the conversation or to store conversation
+ * related data.
+ */
+ var conversationToken: String? = null,
+ /**
+ * Type indicates the state of the conversation in its life cycle.
+ */
+ var type: GoogleActionsV2ConversationType? = null
+)
+
+data class GoogleActionsV2CustomPushMessage(
+ /**
+ * An order update updating orders placed through transaction APIs.
+ */
+ var orderUpdate: GoogleActionsV2OrdersOrderUpdate? = null,
+ /**
+ * The specified target for the push request.
+ */
+ var target: GoogleActionsV2CustomPushMessageTarget? = null,
+ /**
+ * If specified, displays a notification to the user with specified title
+ * and text.
+ */
+ var userNotification: GoogleActionsV2UserNotification? = null
+)
+
+data class GoogleActionsV2CustomPushMessageTarget(
+ /**
+ * The argument to target for an intent. For V1, only one Argument is
+ * supported.
+ */
+ var argument: GoogleActionsV2Argument? = null,
+ /**
+ * The intent to target.
+ */
+ var intent: String? = null,
+ /**
+ * The locale to target. Follows IETF BCP-47 language code.
+ * Can be used by a multi-lingual app to target a user on a specified
+ * localized app. If not specified, it will default to en-US.
+ */
+ var locale: String? = null,
+ /**
+ * The user to target.
+ */
+ var userId: String? = null
+)
+
+data class GoogleActionsV2DateTime(
+ /**
+ * Date value
+ */
+ var date: GoogleTypeDate? = null,
+ /**
+ * Time value
+ */
+ var time: GoogleTypeTimeOfDay? = null
+)
+
+data class GoogleActionsV2DateTimeValueSpec(
+ /**
+ * Control datetime prompts.
+ */
+ var dialogSpec: GoogleActionsV2DateTimeValueSpecDateTimeDialogSpec? = null
+)
+
+data class GoogleActionsV2DateTimeValueSpecDateTimeDialogSpec(
+ /**
+ * This is used to create prompt to ask for date only.
+ * For example: What date are you looking for?
+ */
+ var requestDateText: String? = null,
+ /**
+ * This is used to create initial prompt by datetime sub-dialog.
+ * Example question: \"What date and time do you want?\"
+ */
+ var requestDatetimeText: String? = null,
+ /**
+ * This is used to create prompt to ask for time only.
+ * For example: What time?
+ */
+ var requestTimeText: String? = null
+)
+
+data class GoogleActionsV2DeliveryAddressValue(
+ /**
+ * Contains delivery address only when user agrees to share the delivery
+ * address.
+ */
+ var location: GoogleActionsV2Location? = null,
+ /**
+ * User's decision regarding the request.
+ */
+ var userDecision: GoogleActionsV2DeliveryAddressValueUserDecision? = null
+)
+
+data class GoogleActionsV2DeliveryAddressValueSpec(
+ /**
+ * Configuration for delivery address dialog.
+ */
+ var addressOptions: GoogleActionsV2DeliveryAddressValueSpecAddressOptions? = null
+) {
+ fun addressOptions(init: GoogleActionsV2DeliveryAddressValueSpecAddressOptions.() -> Unit) {
+ this.addressOptions = GoogleActionsV2DeliveryAddressValueSpecAddressOptions()
+ this.addressOptions?.init()
+ }
+}
+
+data class GoogleActionsV2DeliveryAddressValueSpecAddressOptions(
+ /**
+ * App can optionally pass a short text giving user a hint why delivery
+ * address is requested. For example, \"Grubhub is asking your address for
+ * [determining the actions.service area].\", the text in `[]` is the custom TTS
+ * that should be populated here.
+ */
+ var reason: String? = null
+)
+
+data class GoogleActionsV2Device(
+ /**
+ * Represents actual device location such as lat, lng, and formatted address.
+ * Requires the
+ * DEVICE_COARSE_LOCATION
+ * or
+ * DEVICE_PRECISE_LOCATION
+ * permission.
+ */
+ var location: GoogleActionsV2Location? = null
+)
+
+data class GoogleActionsV2DevicesAndroidApp(
+ /**
+ * Package name
+ * Package name must be specified when specifing Android Fulfillment.
+ */
+ var packageName: String? = null,
+ /**
+ * When multiple filters are specified, any filter match will trigger the app.
+ */
+ var versions: MutableList? = null
+)
+
+data class GoogleActionsV2DevicesAndroidAppVersionFilter(
+ /**
+ * Max version code, inclusive.
+ * The range considered is [min_version:max_version].
+ * A null range implies any version.
+ * Examples:
+ * To specify a single version use: [target_version:target_version].
+ * To specify any version leave min_version and max_version unspecified.
+ * To specify all versions until max_version, leave min_version unspecified.
+ * To specify all versions from min_version, leave max_version unspecified.
+ */
+ var maxVersion: Float? = null,
+ /**
+ * Min version code or 0, inclusive.
+ */
+ var minVersion: Float? = null
+)
+
+data class GoogleActionsV2DialogSpec(
+ /**
+ * Holds helper specific dialog specs if any. For example:
+ * ConfirmationDialogSpec for confirmation helper.
+ */
+ var extension: ApiClientObjectMap? = null
+)
+
+data class GoogleActionsV2Entitlement(
+ /**
+ * Only present for in-app purchase and in-app subs.
+ */
+ var inAppDetails: GoogleActionsV2SignedData? = null,
+ /**
+ * Product sku. Package name for paid app, suffix of Finsky docid for
+ * in-app purchase and in-app subscription.
+ * Match getSku() in Play InApp Billing API.
+ */
+ var sku: String? = null,
+ var skuType: GoogleActionsV2EntitlementSkuType? = null
+)
+
+data class GoogleActionsV2ExpectedInput(
+ /**
+ * The customized prompt used to ask user for input.
+ */
+ var inputPrompt: GoogleActionsV2InputPrompt? = null,
+ /**
+ * List of intents that can be used to fulfill this input.
+ * To have the Google Assistant just return the raw user input, the app
+ * should ask for the `actions.intent.TEXT` intent.
+ */
+ var possibleIntents: MutableList? = null,
+ /**
+ * List of phrases the app wants Google to use for speech biasing.
+ * Up to 1000 phrases are allowed.
+ */
+ var speechBiasingHints: MutableList? = null
+)
+
+interface GoogleActionsV2ExpectedIntent {
+ /**
+ * Additional configuration data required by a built-in intent. Possible
+ * values for the built-in intents: `actions.intent.OPTION ->`
+ * [google.actions.v2.OptionValueSpec], `actions.intent.CONFIRMATION ->`
+ * [google.actions.v2.ConfirmationValueSpec],
+ * `actions.intent.TRANSACTION_REQUIREMENTS_CHECK ->`
+ * [google.actions.v2.TransactionRequirementsCheckSpec],
+ * `actions.intent.DELIVERY_ADDRESS ->`
+ * [google.actions.v2.DeliveryAddressValueSpec],
+ * `actions.intent.TRANSACTION_DECISION ->`
+ * [google.actions.v2.TransactionDecisionValueSpec],
+ * `actions.intent.PLACE ->`
+ * [google.actions.v2.PlaceValueSpec],
+ * `actions.intent.Link ->`
+ * [google.actions.v2.LinkValueSpec]
+ */
+ var inputValueData: ProtoAny?
+ /**
+ * The built-in intent name, e.g. `actions.intent.TEXT`, or intents
+ * defined in the action package. If the intent specified is not a built-in
+ * intent, it is only used for speech biasing and the input provided by the
+ * Google Assistant will be the `actions.intent.TEXT` intent.
+ */
+ var intent: String?
+ /**
+ * Optionally, a parameter of the intent that is being requested. Only valid
+ * for requested intents. Used for speech biasing.
+ */
+ var parameterName: String?
+}
+
+data class GoogleActionsV2ExpectedIntentData(override var inputValueData: ProtoAny? = null,
+ override var intent: String? = null,
+ override var parameterName: String? = null) : GoogleActionsV2ExpectedIntent
+
+data class GoogleActionsV2FinalResponse(
+ /**
+ * Rich response when user is not required to provide an input.
+ */
+ var richResponse: GoogleActionsV2RichResponse? = null,
+ /**
+ * Spoken response when user is not required to provide an input.
+ */
+ var speechResponse: GoogleActionsV2SpeechResponse? = null
+)
+
+data class GoogleActionsV2Input(
+ /**
+ * A list of provided argument values for the input requested by the app.
+ */
+ var arguments: MutableList? = null,
+ /**
+ * Indicates the user's intent. For the first conversation turn, the intent
+ * will refer to the intent of the action that is being triggered. For
+ * subsequent conversation turns, the intent will be a built-in intent.
+ * For example, if the expected input is `actions.intent.OPTION`, then the
+ * the intent specified here will either be `actions.intent.OPTION` if the
+ * Google Assistant was able to satisfy that intent, or
+ * `actions.intent.TEXT` if the user provided other information.
+ */
+ var intent: String? = null,
+ /**
+ * Raw input transcription from each turn of conversation that was used to
+ * provide this input.
+ * Multiple conversation turns that don't involve the app may be required
+ * for the assistant to provide some types of input.
+ */
+ var rawInputs: MutableList? = null
+)
+
+data class GoogleActionsV2InputPrompt(
+ /**
+ * Initial prompts asking user to provide an input.
+ * Only a single initial_prompt is supported.
+ */
+ var initialPrompts: MutableList? = null,
+ /**
+ * Prompt used to ask user when there is no input from user.
+ */
+ var noInputPrompts: MutableList? = null,
+ /**
+ * Prompt payload.
+ */
+ var richInitialPrompt: GoogleActionsV2RichResponse? = null
+)
+
+data class GoogleActionsV2LinkValueSpec(
+ var dialogSpec: GoogleActionsV2DialogSpec? = null,
+ /**
+ * Destination that the app should link to. Could be a web URL, a
+ * conversational link or an Android intent. A web URL is used to handoff the
+ * flow to some website. A conversational link is used to provide a deep link
+ * into another AoG app. An Android intent URI is used to trigger an Android
+ * intent. This requires the package_name to be specified.
+ */
+ var openUrlAction: GoogleActionsV2UiElementsOpenUrlAction? = null
+)
+
+data class GoogleActionsV2LinkValueSpecLinkDialogSpec(
+ /**
+ * The name of the app or site this request wishes to linking to.
+ * The TTS will be created with the title \"Open \". Also
+ * used during confirmation, \"Can I send you to ?\" If we
+ * know the actual title of the link that is being handed off to, we will
+ * ignore this field and use the appropriate title.
+ * Max 20 chars.
+ */
+ var destinationName: String? = null,
+ /**
+ * A string that is added to the end of the confirmation prompt to explain
+ * why we need to link out. Example: \"navigate to pick up your coffee?\" This
+ * can be appended to the confirmation prompt like \"Can I send you to Google
+ * Maps to navigate to pick up your coffee?\"
+ */
+ var requestLinkReason: String? = null
+)
+
+data class GoogleActionsV2Location(
+ /**
+ * City.
+ * Requires the DEVICE_PRECISE_LOCATION or
+ * DEVICE_COARSE_LOCATION permission.
+ */
+ var city: String? = null,
+ /**
+ * Geo coordinates.
+ * Requires the DEVICE_PRECISE_LOCATION permission.
+ */
+ var coordinates: GoogleTypeLatLng? = null,
+ /**
+ * Display address, e.g., \"1600 Amphitheatre Pkwy, Mountain View, CA 94043\".
+ * Requires the DEVICE_PRECISE_LOCATION permission.
+ */
+ var formattedAddress: String? = null,
+ /**
+ * Name of the place.
+ */
+ var name: String? = null,
+ /**
+ * Notes about the location.
+ */
+ var notes: String? = null,
+ /**
+ * Phone number of the location, e.g. contact number of business location or
+ * phone number for delivery location.
+ */
+ var phoneNumber: String? = null,
+ /**
+ * Postal address.
+ * Requires the DEVICE_PRECISE_LOCATION or
+ * DEVICE_COARSE_LOCATION permission.
+ */
+ var postalAddress: GoogleTypePostalAddress? = null,
+ /**
+ * Zip code.
+ * Requires the DEVICE_PRECISE_LOCATION or
+ * DEVICE_COARSE_LOCATION permission.
+ */
+ var zipCode: String? = null,
+
+ var address: String? = null
+)
+
+interface GoogleActionsV2MediaObject {
+ /**
+ * The url pointing to the media content.
+ */
+ var contentUrl: String?
+ /**
+ * Description of this media object.
+ */
+ var description: String?
+ /**
+ * A small image icon displayed on the right from the title.
+ * It's resized to 36x36 dp.
+ */
+ var icon: GoogleActionsV2UiElementsImage?
+ /**
+ * A large image, such as the cover of the album, etc.
+ */
+ var largeImage: GoogleActionsV2UiElementsImage?
+ /**
+ * Name of this media object.
+ */
+ var name: String?
+}
+
+interface GoogleActionsV2MediaResponse {
+ /**
+ * The list of media objects.
+ */
+ var mediaObjects: MutableList?
+ /**
+ * Type of the media within this response.
+ */
+ var mediaType: GoogleActionsV2MediaResponseMediaType?
+}
+
+data class GoogleActionsV2MediaStatus(
+ /**
+ * The status of the media
+ */
+ var status: GoogleActionsV2MediaStatusStatus? = null
+)
+
+data class GoogleActionsV2NewSurfaceValue(
+ var status: GoogleActionsV2NewSurfaceValueStatus? = null
+)
+
+data class GoogleActionsV2NewSurfaceValueSpec(
+ /**
+ * The list of capabilities required from the surface. Eg,
+ * [\"actions.capability.SCREEN_OUTPUT\"]
+ */
+ var capabilities: MutableList? = null,
+ /**
+ * Context describing the content the user will receive on the new surface.
+ * Eg, \"[Sure, I know of 10 that are really popular. The highest-rated one is
+ * at Mount Marcy.] Is it okay if I send that to your phone?\"
+ */
+ var context: String? = null,
+ /**
+ * Title of the notification which prompts the user to continue on the new
+ * surface.
+ */
+ var notificationTitle: String? = null
+)
+
+data class GoogleActionsV2OptionInfo(
+ /**
+ * A unique key that will be sent back to the agent if this response is given.
+ */
+ var key: String? = null,
+ /**
+ * A list of synonyms that can also be used to trigger this item in dialog.
+ */
+ var synonyms: MutableList? = null
+)
+
+data class GoogleActionsV2OptionValueSpec(
+ /**
+ * A select with a card carousel GUI
+ */
+ var carouselSelect: GoogleActionsV2UiElementsCarouselSelect? = null,
+ /**
+ * A select with a list card GUI
+ */
+ var listSelect: GoogleActionsV2UiElementsListSelect? = null,
+ /**
+ * A simple select with no associated GUI
+ */
+ var simpleSelect: GoogleActionsV2SimpleSelect? = null
+)
+
+data class GoogleActionsV2OrdersActionProvidedPaymentOptions(
+ /**
+ * Name of the instrument displayed on the receipt.
+ * Required for action-provided payment info.
+ * For `PAYMENT_CARD`, this could be \"VISA-1234\".
+ * For `BANK`, this could be \"Chase Checking-1234\".
+ * For `LOYALTY_PROGRAM`, this could be \"Starbuck's points\".
+ * For `ON_FULFILLMENT`, this could be something like \"pay on delivery\".
+ */
+ var displayName: String? = null,
+ /**
+ * Type of payment.
+ * Required.
+ */
+ var paymentType: GoogleActionsV2OrdersActionProvidedPaymentOptionsPaymentType? = null
+)
+
+data class GoogleActionsV2OrdersCancellationInfo(
+ /**
+ * Reason for cancellation.
+ */
+ var reason: String? = null
+)
+
+data class GoogleActionsV2OrdersCart(
+ /**
+ * Extension to the cart based on the type of order.
+ */
+ var extension: ApiClientObjectMap? = null,
+ /**
+ * Optional id for this cart. Included as part of the
+ * Cart returned back to the integrator at confirmation time.
+ */
+ var id: String? = null,
+ /**
+ * The good(s) or actions.service(s) the user is ordering. There must be at least
+ * one line item.
+ */
+ var lineItems: MutableList? = null,
+ /**
+ * Merchant for the cart, if different from the caller.
+ */
+ var merchant: GoogleActionsV2OrdersMerchant? = null,
+ /**
+ * Notes about this cart.
+ */
+ var notes: String? = null,
+ /**
+ * Adjustments entered by the user, e.g. gratuity.
+ */
+ var otherItems: MutableList? = null,
+ /**
+ * Optional. Promotional coupons added to the cart. Eligible promotions will
+ * be sent back as discount line items in proposed order.
+ */
+ var promotions: MutableList? = null
+) {
+
+ fun merchant(init: GoogleActionsV2OrdersMerchant.() -> Unit) {
+ merchant = GoogleActionsV2OrdersMerchant()
+ merchant?.init()
+ }
+
+ fun lineItems(vararg init: GoogleActionsV2OrdersLineItem.() -> Unit) {
+ this.lineItems = init.map {
+ val item = GoogleActionsV2OrdersLineItem()
+ item.it()
+ item
+ }.toMutableList()
+ }
+
+ fun otherItems(vararg init: GoogleActionsV2OrdersLineItem.() -> Unit) {
+ this.otherItems = init.map {
+ val item = GoogleActionsV2OrdersLineItem()
+ item.it()
+ item
+ }.toMutableList()
+ }
+}
+
+data class GoogleActionsV2OrdersCustomerInfo(
+ /**
+ * Customer email will be included and returned to the app if
+ * CustomerInfoProperty.EMAIL specified in CustomerInfoOptions.
+ */
+ var email: String? = null
+)
+
+data class GoogleActionsV2OrdersCustomerInfoOptions(
+ /**
+ * List of customer info properties.
+ */
+ var customerInfoProperties: MutableList? = null
+)
+
+data class GoogleActionsV2OrdersFulfillmentInfo(
+ /**
+ * When the order will be fulfilled.
+ */
+ var deliveryTime: String? = null
+)
+
+data class GoogleActionsV2OrdersGenericExtension(
+ /**
+ * Locations associated with the order. Up to 2 locations.
+ */
+ var locations: MutableList? = null,
+ /**
+ * Time indicator associated with the proposed order.
+ */
+ var time: GoogleActionsV2OrdersTime? = null
+)
+
+data class GoogleActionsV2OrdersGoogleProvidedPaymentOptions(
+ /**
+ * If true, billing address will be returned.
+ */
+ var billingAddressRequired: Boolean? = null,
+ /**
+ * If true, disallow prepaid cards from being used in the transaction.
+ */
+ var prepaidCardDisallowed: Boolean? = null,
+ /**
+ * The app allows cards from any card network listed here being used in
+ * transaction.
+ * By default, Amex, Visa, MC and Discover are supported.
+ */
+ var supportedCardNetworks: MutableList? = null,
+ /**
+ * Required field for requesting Google provided payment instrument.
+ * These tokenization parameters will be used for generating payment token
+ * for use in transaction. The app should get these parameters from their
+ * payment gateway.
+ */
+ var tokenizationParameters: GoogleActionsV2OrdersPaymentMethodTokenizationParameters? = null
+)
+
+data class GoogleActionsV2OrdersInTransitInfo(
+ /**
+ * Last updated time for in transit.
+ */
+ var updatedTime: String? = null
+)
+
+data class GoogleActionsV2OrdersLineItem(
+ /**
+ * Description of the item.
+ */
+ var description: String? = null,
+ /**
+ * Extension to the line item based on its type.
+ */
+ var extension: ApiClientObjectMap? = null,
+ /**
+ * Unique id of the line item within the Cart/Order. Required.
+ */
+ var id: String? = null,
+ /**
+ * Small image associated with this item.
+ */
+ var image: Image? = null,
+ /**
+ * Name of the line item as displayed in the receipt. Required.
+ */
+ var name: String? = null,
+ /**
+ * Optional product or offer id for this item.
+ */
+ var offerId: String? = null,
+ /**
+ * Each line item should have a price, even if the price is 0. Required.
+ * This is the total price as displayed on the receipt for this line
+ * (i.e. unit price * quantity).
+ */
+ var price: GoogleActionsV2OrdersPrice? = null,
+ /**
+ * Number of items included.
+ */
+ var quantity: Int? = null,
+ /**
+ * Sub-line item(s). Only valid if type is `REGULAR`.
+ */
+ var subLines: MutableList? = null,
+ /**
+ * Type of line item.
+ */
+ var type: GoogleActionsV2OrdersLineItemType? = null
+) {
+ fun price(init: GoogleActionsV2OrdersPrice.() -> Unit) {
+ price = GoogleActionsV2OrdersPrice()
+ price?.init()
+ }
+
+ fun subLines(vararg init: GoogleActionsV2OrdersLineItemSubLine.() -> Unit) {
+ this.subLines = init.map {
+ val subLine = GoogleActionsV2OrdersLineItemSubLine()
+ subLine.it()
+ subLine
+ }?.toMutableList()
+ }
+}
+
+data class GoogleActionsV2OrdersLineItemSubLine(
+ /**
+ * A generic line item (e.g. add-on).
+ */
+ var lineItem: GoogleActionsV2OrdersLineItem? = null,
+ /**
+ * A note associated with the line item.
+ */
+ var note: String? = null
+) {
+ fun lineItem(init: GoogleActionsV2OrdersLineItem.() -> Unit) {
+ val item = GoogleActionsV2OrdersLineItem()
+ item.init()
+ this.lineItem = item
+ }
+}
+
+data class GoogleActionsV2OrdersLineItemUpdate(
+ /**
+ * Update to the line item extension. Type must match the item's
+ * existing extension type.
+ */
+ var extension: ApiClientObjectMap? = null,
+ /**
+ * New line item-level state.
+ */
+ var orderState: GoogleActionsV2OrdersOrderState? = null,
+ /**
+ * New price for the line item.
+ */
+ var price: GoogleActionsV2OrdersPrice? = null,
+ /**
+ * Reason for the change. Required for price changes.
+ */
+ var reason: String? = null
+)
+
+data class GoogleActionsV2OrdersMerchant(
+ /**
+ * Id of the merchant.
+ */
+ var id: String? = null,
+ /**
+ * User-visible name of the merchant. Required.
+ */
+ var name: String? = null
+)
+
+data class GoogleActionsV2OrdersOrder(
+ /**
+ * User-visible order id. Must be set on the initial synchronous
+ * OrderUpdate/confirmation.
+ */
+ var actionOrderId: String? = null,
+ /**
+ * If requested, customer info e.g. email will be passed back to the app.
+ */
+ var customerInfo: GoogleActionsV2OrdersCustomerInfo? = null,
+ /**
+ * Reflect back the proposed order that caused the order.
+ */
+ var finalOrder: GoogleActionsV2OrdersProposedOrder? = null,
+ /**
+ * Order id assigned by Google.
+ */
+ var googleOrderId: String? = null,
+ /**
+ * Date and time the order was created.
+ */
+ var orderDate: String? = null,
+ /**
+ * Payment related info for the order.
+ */
+ var paymentInfo: GoogleActionsV2OrdersPaymentInfo? = null
+)
+
+data class GoogleActionsV2OrdersOrderLocation(
+ /**
+ * Contains actual location info.
+ */
+ var location: GoogleActionsV2Location? = null,
+ /**
+ * Address type. Determines icon and placement. Required.
+ */
+ var type: GoogleActionsV2OrdersOrderLocationType? = null
+) {
+ fun location(init: GoogleActionsV2Location.() -> Unit) {
+ this.location = GoogleActionsV2Location()
+ this.location?.init()
+ }
+}
+
+data class GoogleActionsV2OrdersOrderOptions(
+ /**
+ * The app can request customer info by setting this field.
+ * If set, the corresponding field will show up in ProposedOrderCard for
+ * user's confirmation.
+ */
+ var customerInfoOptions: GoogleActionsV2OrdersCustomerInfoOptions? = null,
+ /**
+ * If true, delivery address is required for the associated Order.
+ */
+ var requestDeliveryAddress: Boolean? = null
+)
+
+data class GoogleActionsV2OrdersOrderState(
+ /**
+ * The user-visible string for the state. Required.
+ */
+ var label: String? = null,
+ /**
+ * State can be one of the following values:
+ *
+ * `CREATED`: Order was created at integrator's system.
+ * `REJECTED`: Order was rejected by integrator.
+ * `CONFIRMED`: Order was confirmed by the integrator and is active.
+ * `CANCELLED`: User cancelled the order.
+ * `IN_TRANSIT`: Order is being delivered.
+ * `RETURNED`: User did a return.
+ * `FULFILLED`: User received what was ordered.
+ * 'CHANGE_REQUESTED': User has requested a change to the order, and
+ * the integrator is processing this change. The
+ * order should be moved to another state after the
+ * request is handled.
+ *
+ * Required.
+ */
+ var state: String? = null
+)
+
+interface GoogleActionsV2OrdersOrderUpdate {
+ /**
+ * Required.
+ * The canonical order id referencing this order.
+ * If integrators don't generate the canonical order id in their system,
+ * they can simply copy over google_order_id included in order.
+ */
+ var actionOrderId: String?
+ /**
+ * Information about cancellation state.
+ */
+ var cancellationInfo: GoogleActionsV2OrdersCancellationInfo?
+ /**
+ * Information about fulfillment state.
+ */
+ var fulfillmentInfo: GoogleActionsV2OrdersFulfillmentInfo?
+ /**
+ * Id of the order is the Google-issued id.
+ */
+ var googleOrderId: String?
+ /**
+ * Information about in transit state.
+ */
+ var inTransitInfo: GoogleActionsV2OrdersInTransitInfo?
+ /**
+ * Extra data based on a custom order state or in addition to info of a
+ * standard state.
+ */
+ var infoExtension: ApiClientObjectMap?
+ /**
+ * Map of line item-level changes, keyed by item id. Optional.
+ */
+ var lineItemUpdates: ApiClientObjectMap?
+ /**
+ * Updated applicable management actions for the order, e.g. manage, modify,
+ * contact support.
+ */
+ var orderManagementActions: MutableList?
+ /**
+ * The new state of the order.
+ */
+ var orderState: GoogleActionsV2OrdersOrderState?
+ /**
+ * Receipt for order.
+ */
+ var receipt: GoogleActionsV2OrdersReceipt?
+ /**
+ * Information about rejection state.
+ */
+ var rejectionInfo: GoogleActionsV2OrdersRejectionInfo?
+ /**
+ * Information about returned state.
+ */
+ var returnInfo: GoogleActionsV2OrdersReturnInfo?
+ /**
+ * New total price of the order
+ */
+ var totalPrice: GoogleActionsV2OrdersPrice?
+ /**
+ * When the order was updated from the app's perspective.
+ */
+ var updateTime: GoogleTypeTimeOfDay?
+ /**
+ * If specified, displays a notification to the user with the specified
+ * title and text. Specifying a notification is a suggestion to
+ * notify and is not guaranteed to result in a notification.
+ */
+ var userNotification: GoogleActionsV2OrdersOrderUpdateUserNotification?
+
+ /**
+ * Added in AoG-Kotlin
+ */
+ var orderDate: String?
+
+ var locale: String?
+}
+
+
+data class GoogleActionsV2OrdersOrderUpdateAction(
+ /**
+ * Button label and link.
+ */
+ var button: Button? = null,
+ /**
+ * Type of action.
+ */
+ var type: GoogleActionsV2OrdersOrderUpdateActionType? = null
+) {
+ fun button(init: GoogleActionsV2UiElementsButton.() -> Unit) {
+ this.button = Button()
+ this.button?.init()
+ }
+}
+
+data class GoogleActionsV2OrdersOrderUpdateUserNotification(
+ /**
+ * The contents of the notification.
+ */
+ var text: String? = null,
+ /**
+ * The title for the user notification.
+ */
+ var title: String? = null
+)
+
+data class GoogleActionsV2OrdersPaymentInfo(
+ /**
+ * Name of the instrument displayed on the receipt.
+ */
+ var displayName: String? = null,
+ /**
+ * Google provided payment instrument.
+ */
+ var googleProvidedPaymentInstrument: GoogleActionsV2OrdersPaymentInfoGoogleProvidedPaymentInstrument? = null,
+ /**
+ * Type of payment.
+ * Required.
+ */
+ var paymentType: GoogleActionsV2OrdersPaymentInfoPaymentType? = null
+)
+
+data class GoogleActionsV2OrdersPaymentInfoGoogleProvidedPaymentInstrument(
+ /**
+ * If requested by integrator, billing address for the instrument in use
+ * will be included.
+ */
+ var billingAddress: GoogleTypePostalAddress? = null,
+ /**
+ * Google provided payment instrument.
+ */
+ var instrumentToken: String? = null
+)
+
+data class GoogleActionsV2OrdersPaymentMethodTokenizationParameters(
+ /**
+ * If tokenization_type is set to `PAYMENT_GATEWAY` then the list of
+ * parameters should contain payment gateway specific parameters required to
+ * tokenize payment method as well as parameter with the name \"gateway\" with
+ * the value set to one of the gateways that we support e.g. \"stripe\" or
+ * \"braintree\".
+ * A sample tokenization configuration used for Stripe in JSON format.
+ * `{
+ * \"gateway\" : \"stripe\",
+ * \"stripe:publishableKey\" : \"pk_1234\",
+ * \"stripe:version\" : \"1.5\"
+ * }`
+ * A sample tokenization configuration used for Braintree in JSON format.
+ * `{
+ * \"gateway\" : \"braintree\",
+ * \"braintree:merchantId\" : \"abc\"
+ * \"braintree:sdkVersion\" : \"1.4.0\"
+ * \"braintree:apiVersion\" : \"v1\"
+ * \"braintree:clientKey\" : \"production_a12b34\"
+ * \"braintree:authorizationFingerprint\" : \"production_a12b34\"
+ * }`
+ * A sample configuration used for Adyen in JSON format.
+ * `{
+ * \"gateway\" : \"adyen\",
+ * \"gatewayMerchantId\" : \"gateway-merchant-id\"
+ * }`
+ * If tokenization_type is set to DIRECT, integrators must specify a parameter
+ * named \"publicKey\" which will contain an Elliptic Curve public key using
+ * the uncompressed point format and base64 encoded. This publicKey will be
+ * used by Google to encrypt the payment information.
+ * Example of the parameter in JSON format:
+ * {
+ * \"publicKey\": \"base64encoded...\"
+ * }
+ */
+ var parameters: ApiClientObjectMap? = null,
+ /**
+ * Required.
+ */
+ var tokenizationType: GoogleActionsV2OrdersPaymentMethodTokenizationParametersTokenizationType? = null
+)
+
+data class GoogleActionsV2OrdersPaymentOptions(
+ /**
+ * Info for an Action-provided payment instrument for display on receipt.
+ */
+ var actionProvidedOptions: GoogleActionsV2OrdersActionProvidedPaymentOptions? = null,
+ /**
+ * Requirements for Google provided payment instrument.
+ */
+ var googleProvidedOptions: GoogleActionsV2OrdersGoogleProvidedPaymentOptions? = null
+) {
+ fun actionProvidedOptions(init: GoogleActionsV2OrdersActionProvidedPaymentOptions.() -> Unit) {
+ this.actionProvidedOptions = GoogleActionsV2OrdersActionProvidedPaymentOptions()
+ this.actionProvidedOptions?.init()
+ }
+
+ fun googleProvidedOptions(init: GoogleActionsV2OrdersGoogleProvidedPaymentOptions.() -> Unit) {
+ this.googleProvidedOptions = GoogleActionsV2OrdersGoogleProvidedPaymentOptions()
+ this.googleProvidedOptions?.init()
+
+ }
+}
+
+data class GoogleActionsV2OrdersPresentationOptions(
+ /**
+ * call_to_action can be one of the following values:
+ *
+ * `PLACE_ORDER`: Used for placing an order.
+ * `PAY`: Used for a payment.
+ * `BUY`: Used for a purchase.
+ * `SEND`: Used for a money transfer.
+ * `BOOK`: Used for a booking.
+ * `RESERVE`: Used for reservation.
+ * `SCHEDULE`: Used for scheduling an appointment.
+ * `SUBSCRIBE`: Used for subscription.
+ *
+ * call_to_action refers to the action verb which best describes this order.
+ * This will be used in various places like prompt, suggestion chip etc while
+ * proposing the order to the user.
+ */
+ var callToAction: String? = null
+)
+
+data class GoogleActionsV2OrdersPrice(
+ /**
+ * Monetary amount. Required.
+ */
+ var amount: GoogleTypeMoney? = null,
+ /**
+ * Type of price. Required.
+ */
+ var type: GoogleActionsV2OrdersPriceType? = null
+) {
+ fun amount(init: GoogleTypeMoney.() -> Unit) {
+ amount = GoogleTypeMoney()
+ amount?.init()
+ }
+}
+
+data class GoogleActionsV2OrdersPromotion(
+ /**
+ * Required. Coupon code understood by 3P. For ex: GOOGLE10.
+ */
+ var coupon: String? = null
+)
+
+data class GoogleActionsV2OrdersProposedOrder(
+ /**
+ * User's items.
+ */
+ var cart: GoogleActionsV2OrdersCart? = null,
+ /**
+ * Extension to the proposed order based on the kind of order.
+ * For example, if the order includes a location then this extension will
+ * contain a OrderLocation value.
+ */
+ var extension: ProtoAny? = null, //ApiClientObjectMap? = null,
+ /**
+ * Optional id for this ProposedOrder. Included as part of the
+ * ProposedOrder returned back to the integrator at confirmation time.
+ */
+ var id: String? = null,
+ /**
+ * Image associated with the proposed order.
+ */
+ var image: Image? = null,
+ /**
+ * Fees, adjustments, subtotals, etc.
+ */
+ var otherItems: MutableList? = null,
+ /**
+ * A link to the terms of actions.service that apply to this proposed order.
+ */
+ var termsOfServiceUrl: String? = null,
+ /**
+ * Total price of the proposed order. If of type `ACTUAL`, this is the amount
+ * the caller will charge when the user confirms the proposed order.
+ */
+ var totalPrice: GoogleActionsV2OrdersPrice? = null
+) {
+ fun cart(init: GoogleActionsV2OrdersCart.() -> Unit) {
+ if (cart == null) {
+ cart = GoogleActionsV2OrdersCart()
+ }
+ cart?.init()
+ }
+
+ fun totalPrice(init: GoogleActionsV2OrdersPrice.() -> Unit) {
+ if (totalPrice == null) {
+ totalPrice = GoogleActionsV2OrdersPrice()
+ }
+ totalPrice?.init()
+ }
+ fun extension(init: ProtoAny.() -> Unit) {
+ if (extension == null) {
+ extension = ProtoAny()
+ }
+ extension?.init()
+ }
+ fun image(init: Image.() -> Unit) {
+ if (image == null) {
+ image = Image()
+ }
+ image?.init()
+ }
+}
+
+fun order(init: GoogleActionsV2OrdersProposedOrder.() -> Unit): GoogleActionsV2OrdersProposedOrder {
+ val order = GoogleActionsV2OrdersProposedOrder()
+ order.init()
+ return order
+}
+
+data class GoogleActionsV2OrdersReceipt(
+ /**
+ * Confirmed order id when order has been received by the integrator. This is
+ * the canonical order id used in integrator's system referencing the order
+ * and may subsequently be used to identify the order as `action_order_id`.
+ */
+ var confirmedActionOrderId: String? = null,
+ /**
+ * Optional.
+ * The user facing id referencing to current order, which will show up in the
+ * receipt card if present. This should be the id that usually appears on
+ * a printed receipt or receipt sent to user's email.
+ * User should be able to use this id referencing her order for customer
+ * actions.service provided by integrators.
+ * Note that this field must be populated if integrator does generate
+ * user facing id for an order with a printed receipt / email receipt.
+ */
+ var userVisibleOrderId: String? = null
+)
+
+data class GoogleActionsV2OrdersRejectionInfo(
+ /**
+ * Reason for the error.
+ */
+ var reason: String? = null,
+ /**
+ * Rejection type.
+ */
+ var type: GoogleActionsV2OrdersRejectionInfoType? = null
+)
+
+data class GoogleActionsV2OrdersReturnInfo(
+ /**
+ * Reason for return.
+ */
+ var reason: String? = null
+)
+
+data class GoogleActionsV2OrdersTime(
+ /**
+ * ISO 8601 representation of time indicator: could be a duration, date or
+ * exact datetime.
+ */
+ var timeIso8601: String? = null,
+ /**
+ * Type of time indicator.
+ */
+ var type: GoogleActionsV2OrdersTimeType? = null
+)
+
+data class GoogleActionsV2PackageEntitlement(
+ /**
+ * List of entitlements for a given app
+ */
+ var entitlements: MutableList? = null,
+ /**
+ * Should match the package name in action package
+ */
+ var packageName: String? = null
+)
+
+data class GoogleActionsV2PermissionValueSpec(
+ /**
+ * The context why agent needs to request permission.
+ */
+ var optContext: String? = null,
+ /**
+ * List of permissions requested by the agent.
+ */
+ var permissions: MutableList? = null,
+ /**
+ * Additional information needed to fulfill update permission request.
+ */
+ var updatePermissionValueSpec: GoogleActionsV2UpdatePermissionValueSpec? = null
+)
+
+data class GoogleActionsV2PlaceValueSpec(
+ /**
+ * Speech configuration for askForPlace dialog. The extension should be used
+ * to define the PlaceDialogSpec configuration.
+ */
+ var dialogSpec: GoogleActionsV2DialogSpec? = null
+)
+
+data class GoogleActionsV2PlaceValueSpecPlaceDialogSpec(
+ /**
+ * This is the context for seeking permission to access various user related
+ * data if the user prompts for personal location during the sub-dialog like
+ * \"Home\", \"Work\" or \"Dad's house\". For example \"*To help you find
+ * juice stores*, I just need to check your location. Can I get that from
+ * Google?\". The first part of this permission prompt is configurable.
+ */
+ var permissionContext: String? = null,
+ /**
+ * This is the initial prompt by AskForPlace sub-dialog. For example \"What
+ * place do you want?\"
+ */
+ var requestPrompt: String? = null
+)
+
+data class GoogleActionsV2RawInput(
+ /**
+ * Indicates how the user provided this input: a typed response, a voice
+ * response, unspecified, etc.
+ */
+ var inputType: GoogleActionsV2RawInputInputType? = null,
+ /**
+ * Typed or spoken input from the end user.
+ */
+ var query: String? = null
+)
+
+data class GoogleActionsV2RegisterUpdateValue(
+ /**
+ * The status of the registering the update requested by the app.
+ */
+ var status: GoogleActionsV2RegisterUpdateValueStatus? = null
+)
+
+data class GoogleActionsV2RegisterUpdateValueSpec(
+ /**
+ * The list of arguments to necessary to fulfill an update.
+ */
+ var arguments: MutableList? = null,
+ /**
+ * The intent that the user wants to get updates from.
+ */
+ var intent: String? = null,
+ /**
+ * The trigger context that defines how the update will be triggered.
+ * This may modify the dialog in order to narrow down the user's preferences
+ * for getting his or her updates.
+ */
+ var triggerContext: GoogleActionsV2TriggerContext? = null
+)
+
+interface GoogleActionsV2RichResponse {
+ /**
+ * A list of UI elements which compose the response
+ * The items must meet the following requirements:
+ * 1. The first item must be a SimpleResponse
+ * 2. At most two SimpleResponse
+ * 3. At most one card (e.g. BasicCard or
+ * StructuredResponse or
+ * MediaResponse
+ * 4. Cards may not be used if an actions.intent.OPTION intent is used
+ * ie ListSelect or
+ * CarouselSelect
+ */
+ var items: MutableList