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

Handle multiple intents with the same name #2921

Merged

Conversation

forslund
Copy link
Collaborator

Description

This implements Alternative 1 from #2920

  • It will raise a ValueError if two named IntentBuilders with the same name is registered
  • If anonymous IntentBuilders are used they will be automatically given an unique name

The handling for enable-disable intent was updated to make sure that the intent was removed from the list of registered_intents, for re-enabling it's moved to a list of detached_intents

How to test

Add a second @intent_handler() decorator to a method ensure both can be used to trigger the handler and that the handler is triggered exactly once.

Contributor license agreement signed?

CLA [ Yes ]

@devops-mycroft devops-mycroft added the CLA: Yes Contributor License Agreement exists (see https://github.com/MycroftAI/contributors) label Jun 18, 2021
@forslund forslund force-pushed the bugfix/multiple-intents-with-same-name branch from 3a8c9d9 to aa962b6 Compare June 18, 2021 06:07
@devops-mycroft
Copy link

Voight Kampff Integration Test Succeeded (Results)

@devops-mycroft
Copy link

Voight Kampff Integration Test Failed (Results).
Mycroft logs are also available: skills.log, audio.log, voice.log, bus.log, enclosure.log

@devops-mycroft
Copy link

Voight Kampff Integration Test Succeeded (Results)

JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 1, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 1, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 1, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 1, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 5, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 5, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 5, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 6, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 6, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 6, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 7, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 7, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 7, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 7, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 7, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 9, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 9, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 9, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
JarbasAl pushed a commit to HelloChatterbox/HolmesIV that referenced this pull request Jul 9, 2021
cherry pick of MycroftAI#2921

Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

Add tests for intent collisions

Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
@krisgesling krisgesling added the Status: To be reviewed Concept accepted and PR has sufficient information for full review label Jul 12, 2021
@krisgesling krisgesling added this to Inbox in Roadmap via automation Jul 16, 2021
@krisgesling krisgesling added this to Sprint 23: Skill interactions in Upcoming Sprints Aug 19, 2021
@NeonDaniel
Copy link
Member

If an active intent is re-registered, it raises an exception that wasn't previously there which results in a spoken error. I think this could be safely caught in the mycroft_skill class and simply log some warning.

2021-10-18 13:33:18.706 | ERROR    | 2982927 | mycroft.skills.mycroft_skill.mycroft_skill:on_error:914 | An error occurred while processing a request in Wikipedia Skill
Traceback (most recent call last):
  File "/home/d_mcknight/PycharmProjects/mycroft-core/mycroft/skills/mycroft_skill/event_container.py", line 73, in wrapper
    handler(message)
  File "/opt/mycroft/skills/wiki.neon/__init__.py", line 79, in handle_intent
    self.enable_intent("WikiMore")
  File "/home/d_mcknight/PycharmProjects/mycroft-core/mycroft/skills/mycroft_skill/mycroft_skill.py", line 1106, in enable_intent
    self.register_intent(intent, None)
  File "/home/d_mcknight/PycharmProjects/mycroft-core/mycroft/skills/mycroft_skill/mycroft_skill.py", line 993, in register_intent
    return self._register_adapt_intent(intent_parser, handler)
  File "/home/d_mcknight/PycharmProjects/mycroft-core/mycroft/skills/mycroft_skill/mycroft_skill.py", line 969, in _register_adapt_intent
    raise ValueError(f'The intent name {name} is already taken')
ValueError: The intent name WikiMore is already taken

@forslund
Copy link
Collaborator Author

Thanks for flagging this. I think the registering should raise the exception but it should be caught and logged by the enable_intent. Does that sound like a good solution?

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.
The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.
MycroftSkill.enable_intent() will now check if the intent is detached
before trying to re-enable it.
@forslund forslund force-pushed the bugfix/multiple-intents-with-same-name branch from aa962b6 to 0b5e7b8 Compare October 19, 2021 15:36
nbr += 1
name = f'{original_name}{nbr}'
else:
if name in self.intent_service:
Copy link
Contributor

@JarbasAl JarbasAl Oct 22, 2021

Choose a reason for hiding this comment

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

i think this should be if name in self.intent_service.registered_intents: to account for intent enabling

caused some issues when playing around with IntentLayers that enable/disable intents

(might have been a race condition, it worked most of the time and doesn't make sense to only fail sometimes)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm, that would be basically the same thing if I understand your suggestion correctly. The __contians__ checks for names in registered_intents. the line above basically expands to

if name in [i[0] for i in self.intent_service.registered_intents]:

What sort of failure did you get?

Copy link
Contributor

Choose a reason for hiding this comment

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

It threw the exception about intent name being taken, i thought that contains also checked for disabled intents, my suggestion was meant to not throw the exception if the intent was disabled

Copy link
Collaborator Author

@forslund forslund Oct 23, 2021

Choose a reason for hiding this comment

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

I've updated the code with a quick locking around the critical sections. They're rather clumsy at the moment but hopefully there won't be deadlocks and should handle race conditions here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the clarification (firefox didn't update the page so I missed your quick reply). The detach() method moves the intent from the registered_intents list to the detached_intents list so it shouldn't throw unless the intent is really active at the moment.

Buuuut... it was long ago since I looked at this branch so might miss-remember. Will dig into the code and try to recall what my intention was.

@pep8speaks
Copy link

pep8speaks commented Oct 23, 2021

Hello @forslund! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2021-10-23 11:28:16 UTC

This should avoid some race conditions that may occur if multiple
threads tries to enable / disable intents
@forslund forslund force-pushed the bugfix/multiple-intents-with-same-name branch from 5f707bb to 8b835d0 Compare October 23, 2021 11:28
@NeonDaniel
Copy link
Member

Thanks for flagging this. I think the registering should raise the exception but it should be caught and logged by the enable_intent. Does that sound like a good solution?

I think for backwards-compatibility these exceptions should be handled (catch and log), maybe with a deprecation notice that future releases will raise an exception if an active intent is activated.

@forslund
Copy link
Collaborator Author

forslund commented Nov 7, 2022

It's now more than a year since the last concern raised here was pushed (I think), is this something the core team is interested in or should I close the PR?

@krisgesling
Copy link
Contributor

Hey Ake, I think it's a good change - seems like everything is accounted for and it passed all the tests. So if there's no opposition I think we can merge it in.

I'll do this on Monday/Tuesday unless I hear otherwise.

@krisgesling krisgesling merged commit ab242a2 into MycroftAI:dev Nov 23, 2022
Roadmap automation moved this from Inbox to Done Nov 23, 2022
JarbasAl pushed a commit to OpenVoiceOS/ovos-core that referenced this pull request Nov 26, 2022
* Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.

* Add tests for intent collisions

* Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

* Add move logic to find if intent is detached

MycroftSkill.enable_intent() will now check if the intent is detached
before trying to re-enable it.

* Lock updates of intents

This should avoid some race conditions that may occur if multiple
threads tries to enable / disable intents
JarbasAl added a commit to OpenVoiceOS/ovos-core that referenced this pull request Dec 13, 2022
* Handle multiple intents with the same name (MycroftAI#2921)

* Add check for duplicate adapt intents

There are two cases, duplicated named intent and duplicated anonymous intent.

A named intent will cause a ValueError exception notifying the skill
author that there is a collision.

An anonymous intent will silently derive a new name and use that
instead of the default generated one.

* Add tests for intent collisions

* Make enable/disable intent handle the new exception

The enable/disable intent did not mark an intent as detached, instead it
remained in the list of intents after disabling in the IntentServiceInterface
to be retrieved when the intent should be re-enabled.

This moves detached intents into a list of detached intents to so they
won't cause the double enable exception.

* Add move logic to find if intent is detached

MycroftSkill.enable_intent() will now check if the intent is detached
before trying to re-enable it.

* Lock updates of intents

This should avoid some race conditions that may occur if multiple
threads tries to enable / disable intents

* refactor a bit

* standardize usage of intent name in all methods

Co-authored-by: Åke <ake.forslund@gmail.com>
@JarbasAl JarbasAl mentioned this pull request Jan 10, 2023
23 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA: Yes Contributor License Agreement exists (see https://github.com/MycroftAI/contributors) Status: To be reviewed Concept accepted and PR has sufficient information for full review Type: Bug - complex
Projects
Roadmap
  
Done
Status: Merged
Upcoming Sprints
Sprint 3x: Review proposed changes
Development

Successfully merging this pull request may close these issues.

None yet

6 participants