aws-lex-conversation 6.0.0 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +34 -0
- data/README.md +108 -0
- data/aws-lex-conversation.gemspec +1 -0
- data/lib/aws/lex/conversation/base.rb +1 -0
- data/lib/aws/lex/conversation/response/elicit_slot.rb +3 -2
- data/lib/aws/lex/conversation/slot/elicitation.rb +3 -5
- data/lib/aws/lex/conversation/type/checkpoint.rb +22 -0
- data/lib/aws/lex/conversation/type/dialog_action.rb +3 -1
- data/lib/aws/lex/conversation/type/slot.rb +1 -1
- data/lib/aws/lex/conversation/type/slot_elicitation_style.rb +17 -0
- data/lib/aws/lex/conversation/version.rb +1 -1
- data/lib/aws/lex/conversation.rb +27 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33df2c318e3e0d2e3157ebe43e27b38855334518efa5fa957be0e1035e6454f2
|
4
|
+
data.tar.gz: 5f7db4ab55ef155967688aae6a85781b1fca26860574d45280cfceb2e410b730
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4831b1eed996b95384635c446a2432efbb765900a8ef814c089ab4bbbfa5311708b0f71fe080d5b4910110448c698dfe855747bc2d9b9a8b19643743581b9c86
|
7
|
+
data.tar.gz: 53cdad241f6ace96a3ea1cb7be904f3518edbab40a403c8ab0641ea26cc6629ae1e0ce16b642cf08217a6f06017936e5865ac01be74e3fdeb620f4654edad52c
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
# 6.3.0 - Nov 22, 2021
|
2
|
+
|
3
|
+
* Add support for the recently added `slotElicitationStyle` property when generating an `ElicitSlot` repsonse ([documentation](https://docs.aws.amazon.com/lexv2/latest/dg/using-spelling.html)).
|
4
|
+
|
5
|
+
You can generate an `ElicitSlot` response now with an optional `slot_elicitation_style` property to allow for spelling support:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
conversation.elicit_slot(
|
9
|
+
slot_to_elicit: 'LastName',
|
10
|
+
slot_elicitation_style: 'SpellByWord' # one of Default, SpellByLetter, or SpellByWord
|
11
|
+
)
|
12
|
+
```
|
13
|
+
|
14
|
+
# 6.2.0 - Sept 28, 2021
|
15
|
+
|
16
|
+
* Add a `Aws::Lex::Conversation#restore_from!` method that accepts a checkpoint parameter. This method modifies the underlying conversation state to match the data from the saved checkpoint.
|
17
|
+
* Make the `dialog_action_type` parameter on `Aws::Lex::Conversation#checkpoint!` default to `Delegate` if not specified as a developer convenience.
|
18
|
+
* Allow developers to pass an optional `intent` override parameter on `Aws::Lex::Conversation#checkpoint!` for convenience.
|
19
|
+
* Update the README with advanced examples for the conversation stash and checkpoints.
|
20
|
+
|
21
|
+
# 6.1.1 - Sept 22, 2021
|
22
|
+
|
23
|
+
* renamed `maximum_elicitations` to `max_retries` and made it backwards compatible to make the param name clear, by default this value is zero, allowing each slot to elicit only once
|
24
|
+
|
25
|
+
# 6.1.0 - Sept 7, 2021
|
26
|
+
|
27
|
+
Added helper methods for clearing active contexts
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
conversation.clear_context!(name: 'test') # clears this specific active context
|
31
|
+
conversation.clear_all_contexts! # clears all current active contexts
|
32
|
+
```
|
33
|
+
|
1
34
|
# 6.0.0 - Sept 7, 2021
|
2
35
|
|
3
36
|
* **breaking change** - Modify `Aws::Lex::Conversation::Type::Base#computed_property` to accept a block instead of a callable argument. This is an internal class and should not require any application-level changes.
|
@@ -55,6 +88,7 @@ it 'creates an event' do
|
|
55
88
|
expect(event).to include_session_values(username: 'jane.doe')
|
56
89
|
end
|
57
90
|
```
|
91
|
+
|
58
92
|
* Add a few convenience methods to `Aws::Lex::Conversation` instances for dealing with active contexts:
|
59
93
|
- `#active_context(name:)`:
|
60
94
|
|
data/README.md
CHANGED
@@ -191,6 +191,114 @@ conversation.handlers = [
|
|
191
191
|
conversation.respond # => { dialogAction: { type: 'Delegate' } }
|
192
192
|
```
|
193
193
|
|
194
|
+
## Advanced Concepts
|
195
|
+
|
196
|
+
This library provides a few constructs to help manage complex interactions:
|
197
|
+
|
198
|
+
### Data Stash
|
199
|
+
|
200
|
+
`Aws::Lex::Conversation` instances implement a `stash` method that can be used to store temporary data within a single invocation.
|
201
|
+
|
202
|
+
A conversation's stashed data will not be persisted between multiple invocations of your lambda function.
|
203
|
+
|
204
|
+
The conversation stash is a great spot to store deserialized data from the session, or invocation-specific state that needs to be shared between handler classes.
|
205
|
+
|
206
|
+
This example illustrates how the stash can be used to store deserialized data from the session:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
# given we have JSON-serialized data in as a persisted session value
|
210
|
+
conversation.session[:user_data] = '{"name":"Jane","id":1234,"email":"test@example.com"}'
|
211
|
+
# we can deserialize the data into a Hash that we store in the conversation stash
|
212
|
+
conversation.stash[:user] = JSON.parse(conversation.session[:user_data])
|
213
|
+
# later on we can reference our stashed data (within the same invocation)
|
214
|
+
conversation.stash[:user] # => {"name"=>"Jane", "id"=>1234, "email"=>"test@example.com"}
|
215
|
+
```
|
216
|
+
|
217
|
+
### Checkpoints
|
218
|
+
|
219
|
+
A conversation may transition between many different topics as the interaction progresses. This type of state transition can be easily handled with checkpoints.
|
220
|
+
|
221
|
+
When a checkpoint is created, all intent and slot data is encoded and stored into a `checkpoints` session value. This data persists between invocations, and is not removed until the checkpoint is restored.
|
222
|
+
|
223
|
+
You can create a checkpoint as follows:
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
# we're ready to fulfill the OrderFlowers intent, but we want to elicit another intent first
|
227
|
+
conversation.checkpoint!(
|
228
|
+
label: 'order_flowers',
|
229
|
+
dialog_action_type: 'Close' # defaults to 'Delegate' if not specified
|
230
|
+
)
|
231
|
+
conversation.elicit_intent(
|
232
|
+
messages: [
|
233
|
+
{
|
234
|
+
content: 'Thanks! Before I place your order, is there anything else I can help with?',
|
235
|
+
contentType: 'PlainText'
|
236
|
+
}
|
237
|
+
]
|
238
|
+
)
|
239
|
+
```
|
240
|
+
|
241
|
+
You can restore the checkpoint in one of two ways:
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
# in a future invocation, we can fetch an instance of the checkpoint and easily
|
245
|
+
# restore the conversation to the previous state
|
246
|
+
checkpoint = conversation.checkpoint(label: 'order_flowers')
|
247
|
+
checkpoint.restore!(
|
248
|
+
fulfillment_state: 'Fulfilled',
|
249
|
+
messages: [
|
250
|
+
{
|
251
|
+
content: 'Okay, your flowers have been ordered! Thanks!',
|
252
|
+
contentType: 'PlainText'
|
253
|
+
}
|
254
|
+
]
|
255
|
+
) # => our response object to Lex is returned
|
256
|
+
```
|
257
|
+
|
258
|
+
It's also possible to restore state from a checkpoint and utilize the conversation's handler chain:
|
259
|
+
|
260
|
+
```ruby
|
261
|
+
class AnotherIntent < Aws::Lex::Conversation::Handler::Base
|
262
|
+
def will_respond?(conversation)
|
263
|
+
conversation.intent_name == 'AnotherIntent' &&
|
264
|
+
conversation.checkpoint?(label: 'order_flowers')
|
265
|
+
end
|
266
|
+
|
267
|
+
def response(conversation)
|
268
|
+
checkpoint = conversation.checkpoint(label: 'order_flowers')
|
269
|
+
# replace the conversation's current resolved intent/slot data with the saved checkpoint data
|
270
|
+
conversation.restore_from!(checkpoint)
|
271
|
+
# call the next handler in the chain to produce a response
|
272
|
+
successor.handle(conversation)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class OrderFlowers < Aws::Lex::Conversation::Handler::Base
|
277
|
+
def will_respond?(conversation)
|
278
|
+
conversation.intent_name == 'OrderFlowers'
|
279
|
+
end
|
280
|
+
|
281
|
+
def response(conversation)
|
282
|
+
conversation.close(
|
283
|
+
fulfillment_state: 'Fulfilled',
|
284
|
+
messages: [
|
285
|
+
{
|
286
|
+
content: 'Okay, your flowers have been ordered! Thanks!',
|
287
|
+
contentType: 'PlainText'
|
288
|
+
}
|
289
|
+
]
|
290
|
+
)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
conversation = Aws::Lex::Conversation.new(event: event, context: context)
|
295
|
+
conversation.handlers = [
|
296
|
+
{ handler: AnotherIntent },
|
297
|
+
{ handler: OrderFlowers }
|
298
|
+
]
|
299
|
+
conversation.respond # => returns a Lex response object
|
300
|
+
```
|
301
|
+
|
194
302
|
## Test Helpers
|
195
303
|
|
196
304
|
This library provides convenience methods to make testing easy! You can use the test helpers as follows:
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.license = 'MIT'
|
27
27
|
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
28
28
|
spec.metadata['homepage_uri'] = spec.homepage
|
29
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
29
30
|
|
30
31
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
31
32
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -25,6 +25,7 @@ require_relative 'type/sentiment_score'
|
|
25
25
|
require_relative 'type/sentiment_response'
|
26
26
|
require_relative 'type/invocation_source'
|
27
27
|
require_relative 'type/dialog_action_type'
|
28
|
+
require_relative 'type/slot_elicitation_style'
|
28
29
|
require_relative 'type/dialog_action'
|
29
30
|
require_relative 'type/confirmation_state'
|
30
31
|
require_relative 'type/fulfillment_state'
|
@@ -5,7 +5,7 @@ module Aws
|
|
5
5
|
class Conversation
|
6
6
|
module Response
|
7
7
|
class ElicitSlot < Base
|
8
|
-
attr_accessor :slot_to_elicit
|
8
|
+
attr_accessor :slot_to_elicit, :slot_elicitation_style
|
9
9
|
|
10
10
|
def initialize(opts = {})
|
11
11
|
super
|
@@ -16,7 +16,8 @@ module Aws
|
|
16
16
|
def dialog_action
|
17
17
|
Aws::Lex::Conversation::Type::DialogAction.shrink_wrap(
|
18
18
|
type: 'ElicitSlot',
|
19
|
-
slotToElicit: slot_to_elicit
|
19
|
+
slotToElicit: slot_to_elicit,
|
20
|
+
slotElicitationStyle: slot_elicitation_style
|
20
21
|
)
|
21
22
|
end
|
22
23
|
end
|
@@ -6,7 +6,7 @@ module Aws
|
|
6
6
|
module Slot
|
7
7
|
class Elicitation
|
8
8
|
attr_accessor :name, :elicit, :messages, :follow_up_messages,
|
9
|
-
:fallback, :
|
9
|
+
:fallback, :max_retries, :conversation
|
10
10
|
|
11
11
|
def initialize(opts = {})
|
12
12
|
self.name = opts.fetch(:name)
|
@@ -14,7 +14,7 @@ module Aws
|
|
14
14
|
self.messages = opts.fetch(:messages)
|
15
15
|
self.follow_up_messages = opts.fetch(:follow_up_messages) { opts.fetch(:messages) }
|
16
16
|
self.fallback = opts[:fallback]
|
17
|
-
self.
|
17
|
+
self.max_retries = opts[:max_retries] || opts[:maximum_elicitations] || 0
|
18
18
|
end
|
19
19
|
|
20
20
|
def elicit!
|
@@ -53,9 +53,7 @@ module Aws
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def maximum_elicitations?
|
56
|
-
|
57
|
-
|
58
|
-
elicitation_attempts > maximum_elicitations
|
56
|
+
elicitation_attempts > max_retries
|
59
57
|
end
|
60
58
|
|
61
59
|
def first_elicitation?
|
@@ -20,6 +20,28 @@ module Aws
|
|
20
20
|
fulfillment_state: FulfillmentState
|
21
21
|
)
|
22
22
|
|
23
|
+
class << self
|
24
|
+
def build(opts = {})
|
25
|
+
new(normalize_parameters(opts))
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def normalize_parameters(opts)
|
31
|
+
params = opts.dup # we don't want to mutate our arguments
|
32
|
+
|
33
|
+
if params[:dialog_action_type].is_a?(String)
|
34
|
+
params[:dialog_action_type] = DialogActionType.new(params[:dialog_action_type])
|
35
|
+
end
|
36
|
+
|
37
|
+
if params[:fulfillment_state].is_a?(String)
|
38
|
+
params[:fulfillment_state] = FulfillmentState.new(params[:fulfillment_state])
|
39
|
+
end
|
40
|
+
|
41
|
+
params
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
23
45
|
# restore the checkpoint AND remove it from session
|
24
46
|
def restore!(conversation, opts = {})
|
25
47
|
conversation.checkpoints.delete_if { |c| c.label == label }
|
@@ -8,10 +8,12 @@ module Aws
|
|
8
8
|
include Base
|
9
9
|
|
10
10
|
optional :slot_to_elicit
|
11
|
+
optional :slot_elicitation_style, default: -> { 'Default' }
|
11
12
|
required :type
|
12
13
|
|
13
14
|
coerce(
|
14
|
-
type: DialogActionType
|
15
|
+
type: DialogActionType,
|
16
|
+
slot_elicitation_style: SlotElicitationStyle
|
15
17
|
)
|
16
18
|
end
|
17
19
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Type
|
7
|
+
class SlotElicitationStyle
|
8
|
+
include Enumeration
|
9
|
+
|
10
|
+
enumeration('Default')
|
11
|
+
enumeration('SpellByLetter')
|
12
|
+
enumeration('SpellByWord')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/aws/lex/conversation.rb
CHANGED
@@ -62,9 +62,9 @@ module Aws
|
|
62
62
|
label = opts.fetch(:label)
|
63
63
|
params = {
|
64
64
|
label: label,
|
65
|
-
dialog_action_type: opts.fetch(:dialog_action_type),
|
65
|
+
dialog_action_type: opts.fetch(:dialog_action_type) { 'Delegate' },
|
66
66
|
fulfillment_state: opts[:fulfillment_state],
|
67
|
-
intent: lex.current_intent,
|
67
|
+
intent: opts.fetch(:intent) { lex.current_intent },
|
68
68
|
slot_to_elicit: opts[:slot_to_elicit]
|
69
69
|
}.compact
|
70
70
|
|
@@ -72,9 +72,8 @@ module Aws
|
|
72
72
|
# update the existing checkpoint
|
73
73
|
checkpoint(label: label).assign_attributes!(params)
|
74
74
|
else
|
75
|
-
# push a new checkpoint to the recent_intent_summary_view
|
76
75
|
checkpoints.unshift(
|
77
|
-
Type::Checkpoint.
|
76
|
+
Type::Checkpoint.build(params)
|
78
77
|
)
|
79
78
|
end
|
80
79
|
end
|
@@ -91,6 +90,21 @@ module Aws
|
|
91
90
|
lex.session_state.session_attributes.checkpoints
|
92
91
|
end
|
93
92
|
|
93
|
+
def restore_from!(checkpoint)
|
94
|
+
# we're done with the stored checkpoint once it's been restored
|
95
|
+
checkpoints.delete_if { |c| c.label == checkpoint.label }
|
96
|
+
# remove any memoized intent data
|
97
|
+
lex.current_intent = nil
|
98
|
+
# replace the intent with data from the checkpoint
|
99
|
+
lex.session_state.intent = checkpoint.intent
|
100
|
+
dialog_action = Type::DialogAction.new(
|
101
|
+
type: checkpoint.dialog_action_type,
|
102
|
+
slot_to_elicit: checkpoint.slot_to_elicit
|
103
|
+
)
|
104
|
+
lex.session_state.dialog_action = dialog_action
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
94
108
|
def active_context?(name:)
|
95
109
|
!active_context(name: name).nil?
|
96
110
|
end
|
@@ -104,7 +118,7 @@ module Aws
|
|
104
118
|
instance = active_context(name: name)
|
105
119
|
|
106
120
|
if instance
|
107
|
-
|
121
|
+
clear_context!(name: name)
|
108
122
|
else
|
109
123
|
instance = Type::Context.new
|
110
124
|
end
|
@@ -120,6 +134,14 @@ module Aws
|
|
120
134
|
instance
|
121
135
|
end
|
122
136
|
|
137
|
+
def clear_context!(name:)
|
138
|
+
lex.session_state.active_contexts.delete_if { |c| c.name == name }
|
139
|
+
end
|
140
|
+
|
141
|
+
def clear_all_contexts!
|
142
|
+
lex.session_state.active_contexts = []
|
143
|
+
end
|
144
|
+
|
123
145
|
def stash
|
124
146
|
@stash ||= {}
|
125
147
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-lex-conversation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jesse Doyle
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: exe
|
14
14
|
cert_chain: []
|
15
|
-
date: 2021-
|
15
|
+
date: 2021-11-22 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: shrink_wrap
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- lib/aws/lex/conversation/type/session_attributes.rb
|
102
102
|
- lib/aws/lex/conversation/type/session_state.rb
|
103
103
|
- lib/aws/lex/conversation/type/slot.rb
|
104
|
+
- lib/aws/lex/conversation/type/slot_elicitation_style.rb
|
104
105
|
- lib/aws/lex/conversation/type/slot_shape.rb
|
105
106
|
- lib/aws/lex/conversation/type/slot_value.rb
|
106
107
|
- lib/aws/lex/conversation/type/time_to_live.rb
|
@@ -110,6 +111,7 @@ licenses:
|
|
110
111
|
- MIT
|
111
112
|
metadata:
|
112
113
|
homepage_uri: https://github.com/amaabca/aws-lex-conversation
|
114
|
+
rubygems_mfa_required: 'true'
|
113
115
|
post_install_message:
|
114
116
|
rdoc_options: []
|
115
117
|
require_paths:
|