Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom and dynamic slots #329

Merged
merged 8 commits into from
Nov 9, 2020
Merged

Custom and dynamic slots #329

merged 8 commits into from
Nov 9, 2020

Conversation

wochinge
Copy link
Contributor

@wochinge wochinge commented Nov 4, 2020

Proposed changes:

  • fix Custom / dynamic slot mappings for forms rasa#7156
  • users can now override a method required_slots to specify slots which should be filled by the form. The FormValidationAction will look for a method extract_<slot_name> to extract these slots.
  • in case the users overrode required_slots, the FormValidationAction will automatically set the requested_slot to the next required_slot which is currently not filled. Users can override this behavior by customizing request_next_slot. By default request_next_slot also considers slots which were mapped in the domain (if there were any mapped ones).
  • introduce a utility function utils.call_potential_coroutine to get rid of our checks if is coroutine ... else ...

I will update the Rasa Open Source documentation in a separate Rasa Open Source PR.

Status (please check what you already did):

  • made PR ready for code review
  • added some tests for the functionality
  • updated the documentation
  • updated the changelog (please check changelog for instructions)
  • reformat files using black (please check Readme for instructions)

@wochinge
Copy link
Contributor Author

wochinge commented Nov 4, 2020

@samsucik I imagined something along these lines. What do you think?

@samsucik
Copy link
Contributor

samsucik commented Nov 5, 2020

Looks good to me at a high level :-)

Would next_requested_slot() (in FormValidationAction) call required_slots() and attempt to select the next requested slot from the list that required_slots() returns?

@wochinge
Copy link
Contributor Author

wochinge commented Nov 5, 2020

Would next_requested_slot() (in FormValidationAction) call required_slots() and attempt to select the next requested slot from the list that required_slots() returns?

I thought about it and decided that this would be something they should implement themselves. I want to avoid to change something for users who are just using this to validate their slots.

@samsucik
Copy link
Contributor

samsucik commented Nov 5, 2020

That's fair. Though I think we should in some way communicate that the intended pattern (when one wants to change the required slots dynamically) is to call next_requested_slot() which then calls required_slots() where the logic for changing the set of required slots should be placed. What do you think about communicating this in the form of explanatory comments in the docstring of next_requested_slot() & required_slots() and possibly also some simple (commented out) code example in next_requested_slot()?

@samsucik
Copy link
Contributor

samsucik commented Nov 5, 2020

Also, I think that with FormValidationAction it gets confusing that if your run() doesn't return any requested slots (and by the same logic if your next_requested_slot() & required_slots() don't return any slots to be filled), then your form will still continue if it's got some unfilled slots from the set defined in the domain. From looking at others' code but also from my own experience, I think that it's easy to fall in the trap of seeing your subclass of FormValidationAction as the only class responsible for the given form, without realising that there's one more layer above this class and that your subclass of FormValidationAction is just a way to interrupt/alter the behaviour provided by that above layer.

@wochinge
Copy link
Contributor Author

wochinge commented Nov 5, 2020

Makes sense 👍 We can fill required_slots with the slot mappings from the domain by default and then always call request_next_slot on the next missing slot by default.

@samsucik
Copy link
Contributor

samsucik commented Nov 5, 2020

Hmmm, this is an interesting idea. While it hides the "meta layer" even more, I think it also makes it very clear to the user how required_slots() and request_next_slot() can be used and how exactly they fit into the whole pattern. One risk I can see is that if the user doesn't explicitly set requested_slot to any value in run(), they might be very surprised to see that some next slot gets requested anyway (in case not all the slots -- as defined in the domain for the form -- are filled).

@wochinge
Copy link
Contributor Author

wochinge commented Nov 5, 2020

How about we only return a requested_slot if required_slots was overridden?

@samsucik
Copy link
Contributor

samsucik commented Nov 5, 2020

Sounds good to me! Together with an explanatory comment in run() (or also elsewhere) this should be clear enough I think.

@wochinge wochinge force-pushed the custom-dynamic-slot-mappings branch 3 times, most recently from 6a1f1b2 to 1b61035 Compare November 5, 2020 15:34
@wochinge
Copy link
Contributor Author

wochinge commented Nov 5, 2020

@samsucik Could you please have another look?

I split it up in custom slots and missing_slots. This way it's possible to implement a static version of custom_slots and still being able to request the next slot accordingly. It also allows for more precise overriding.

@wochinge wochinge marked this pull request as ready for review November 6, 2020 10:52
tracker: "Tracker",
domain: "DomainDict",
) -> Optional[List[Text]]:
return ["my slot"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in which situations would you need to fill this out? you can specify slots without a slot mapping in the domain right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok i just realised why, in case you want to dynamically change the list of requested slots :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'd override for two use cases:

  • dynamic slots
  • custom slot mappings

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok so the custom slot mapping part i'm confused about: if you specify your slots without a slot mapping in the domain file, shouldn't it just use the extract_ method for that slot?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean that we would just try to extract every slot for which we have an extract_ function defined? I think that would work fine if the slot mappings are static. It would become tricky in case your required_slots change dynamically

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok i'm super confused now - the way to extract the slot changes? how would that even work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think "my" users wanted to dynamically change how slots are extracted. They wanted to dynamically change the list of required slots, but extraction was either given right in the domain or implemented using extract_{slot} (in either case, the implementation didn't change). The way I understand it is that this new implementation should use extract_{slot} whenever it exists for the given slot, and use the "default" extraction approach otherwise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good for you @akelad ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that makes sense for me! So just to summarise, for the requested slot method that means you only need to fill it out if you want to dynamically change requested slots, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. This includes the case that you want to ignore / override slot mappings defined in the domain (ideally they just leave the slot mappings empty in the domain)

@akelad
Copy link
Contributor

akelad commented Nov 6, 2020

@wochinge anything in particular you want me to review? the example in the changelog looks good to me

@wochinge
Copy link
Contributor Author

wochinge commented Nov 6, 2020

@akelad I mainly wanted your feedback on the overall approach and as you requested this feature multiple times.

@akelad
Copy link
Contributor

akelad commented Nov 6, 2020

looks great to me, aside from the discussion we're having in one of the comments now :)

Copy link
Contributor

@alwx alwx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

rasa_sdk/utils.py Show resolved Hide resolved
rasa_sdk/forms.py Outdated Show resolved Hide resolved
wochinge and others added 2 commits November 9, 2020 18:09
Co-authored-by: Alexander Pantiukhov <alwxndr@gmail.com>
@wochinge wochinge merged commit 197af33 into master Nov 9, 2020
@wochinge wochinge deleted the custom-dynamic-slot-mappings branch November 9, 2020 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Custom / dynamic slot mappings for forms
4 participants