diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index eff3f5f6ec9..26b0ad35233 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -34,7 +34,7 @@ jobs: strategy: max-parallel: 3 matrix: - python-version: [ 3.8, 3.9] + python-version: [3.9] runs-on: ubuntu-latest timeout-minutes: 15 steps: diff --git a/mycroft/skills/common_play_skill.py b/mycroft/skills/common_play_skill.py index db9fbd3b1dd..04a94ec3386 100644 --- a/mycroft/skills/common_play_skill.py +++ b/mycroft/skills/common_play_skill.py @@ -16,7 +16,7 @@ from enum import Enum, IntEnum from abc import ABC, abstractmethod from ovos_bus_client.message import Message -from ovos_workshop.skills.mycroft_skill import MycroftSkill +from ovos_workshop.skills import OVOSSkill from ovos_bus_client.apis.ocp import ClassicAudioServiceInterface as AudioService @@ -45,7 +45,7 @@ class CPSTrackStatus(IntEnum): END_OF_MEDIA = 90 # playback finished, is the default state when CPS loads -class CommonPlaySkill(MycroftSkill, ABC): +class CommonPlaySkill(OVOSSkill, ABC): """ To integrate with the common play infrastructure of Mycroft skills should use this base class and override the two methods `CPS_match_query_phrase` (for checking if the skill can play the diff --git a/ovos_core/intent_services/__init__.py b/ovos_core/intent_services/__init__.py index 400dc960f10..aae154c5a92 100644 --- a/ovos_core/intent_services/__init__.py +++ b/ovos_core/intent_services/__init__.py @@ -298,13 +298,22 @@ def _emit_match_message(self, match: IntentMatch, message: Message): # Launch skill if not handled by the match function if match.intent_type: - # keep all original message.data and update with intent - # match, mycroft-core only keeps "utterances" + # keep all original message.data and update with intent match data = dict(message.data) data.update(match.intent_data) + # NOTE: message.reply to ensure correct message destination reply = message.reply(match.intent_type, data) self.bus.emit(reply) + def send_cancel_event(self, message): + LOG.info("utterance canceled, cancel_word:" + message.context.get("cancel_word")) + # play dedicated cancel sound + sound = Configuration().get('sounds', {}).get('cancel', "snd/cancel.mp3") + # NOTE: message.reply to ensure correct message destination + self.bus.emit(message.reply('mycroft.audio.play_sound', {"uri": sound})) + self.bus.emit(message.reply("ovos.utterance.cancelled")) + self.bus.emit(message.reply("ovos.utterance.handled")) + def handle_utterance(self, message: Message): """Main entrypoint for handling user utterances @@ -332,60 +341,53 @@ def handle_utterance(self, message: Message): Args: message (Message): The messagebus data """ - try: + # Get utterance utterance_plugins additional context + message = self._handle_transformers(message) - # Get utterance utterance_plugins additional context - message = self._handle_transformers(message) + if message.context.get("canceled"): + self.send_cancel_event(message) + return - if message.context.get("canceled"): - # TODO - play dedicated sound - LOG.info("utterance canceled, cancel_word:" + message.context.get("cancel_word")) - self.bus.emit(message.reply("ovos.utterance.cancelled")) - return + # tag language of this utterance + lang = self.disambiguate_lang(message) - # tag language of this utterance - lang = self.disambiguate_lang(message) + try: + setup_locale(lang) + except Exception as e: + LOG.exception(f"Failed to set lingua_franca default lang to {lang}") - try: - setup_locale(lang) - except Exception as e: - LOG.exception(f"Failed to set lingua_franca default lang to {lang}") - - utterances = message.data.get('utterances', []) - - stopwatch = Stopwatch() - - # get session - sess = self._validate_session(message, lang) - message.context["session"] = sess.serialize() - - # match - match = None - with stopwatch: - # Loop through the matching functions until a match is found. - for match_func in self.get_pipeline(session=sess): - match = match_func(utterances, lang, message) - if match: - try: - self._emit_match_message(match, message) - break - except: - LOG.exception(f"{match_func} returned an invalid match") - LOG.debug(f"no match from {match_func}") - else: - # Nothing was able to handle the intent - # Ask politely for forgiveness for failing in this vital task - self.send_complete_intent_failure(message) + utterances = message.data.get('utterances', []) - LOG.debug(f"intent matching took: {stopwatch.time}") + stopwatch = Stopwatch() - # sync any changes made to the default session, eg by ConverseService - if sess.session_id == "default": - SessionManager.sync(message) - return match, message.context, stopwatch + # get session + sess = self._validate_session(message, lang) + message.context["session"] = sess.serialize() + + # match + match = None + with stopwatch: + # Loop through the matching functions until a match is found. + for match_func in self.get_pipeline(session=sess): + match = match_func(utterances, lang, message) + if match: + try: + self._emit_match_message(match, message) + break + except: + LOG.exception(f"{match_func} returned an invalid match") + LOG.debug(f"no match from {match_func}") + else: + # Nothing was able to handle the intent + # Ask politely for forgiveness for failing in this vital task + self.send_complete_intent_failure(message) - except Exception as err: - LOG.exception(err) + LOG.debug(f"intent matching took: {stopwatch.time}") + + # sync any changes made to the default session, eg by ConverseService + if sess.session_id == "default": + SessionManager.sync(message) + return match, message.context, stopwatch def send_complete_intent_failure(self, message): """Send a message that no skill could handle the utterance. @@ -394,8 +396,10 @@ def send_complete_intent_failure(self, message): message (Message): original message to forward from """ sound = Configuration().get('sounds', {}).get('error', "snd/error.mp3") - self.bus.emit(message.forward('mycroft.audio.play_sound', {"uri": sound})) - self.bus.emit(message.forward('complete_intent_failure')) + # NOTE: message.reply to ensure correct message destination + self.bus.emit(message.reply('mycroft.audio.play_sound', {"uri": sound})) + self.bus.emit(message.reply('complete_intent_failure')) + self.bus.emit(message.reply("ovos.utterance.handled")) def handle_register_vocab(self, message): """Register adapt vocabulary. diff --git a/ovos_core/intent_services/commonqa_service.py b/ovos_core/intent_services/commonqa_service.py index 3c0ff041961..6f513e2afa8 100644 --- a/ovos_core/intent_services/commonqa_service.py +++ b/ovos_core/intent_services/commonqa_service.py @@ -152,10 +152,11 @@ def match(self, utterances: str, lang: str, message: Message): message.data["utterance"] = utterance answered, skill_id = self.handle_question(message) if answered: - match = ovos_core.intent_services.IntentMatch('CommonQuery', - None, {}, - skill_id, - utterance) + match = ovos_core.intent_services.IntentMatch(intent_service='CommonQuery', + intent_type="ovos.utterance.handled", # emit instead of intent message + intent_data={}, + skill_id=skill_id, + utterance=utterance) break return match diff --git a/ovos_core/intent_services/converse_service.py b/ovos_core/intent_services/converse_service.py index 84800c4aef5..61e6563353f 100644 --- a/ovos_core/intent_services/converse_service.py +++ b/ovos_core/intent_services/converse_service.py @@ -312,6 +312,8 @@ def converse_with_skills(self, utterances, lang, message): Returns: IntentMatch if handled otherwise None. """ + session = SessionManager.get(message) + # we call flatten in case someone is sending the old style list of tuples utterances = flatten_list(utterances) # filter allowed skills @@ -319,7 +321,12 @@ def converse_with_skills(self, utterances, lang, message): # check if any skill wants to handle utterance for skill_id in self._collect_converse_skills(message): if self.converse(utterances, skill_id, lang, message): - return ovos_core.intent_services.IntentMatch('Converse', None, None, skill_id, utterances[0]) + state = session.utterance_states.get(skill_id, UtteranceState.INTENT) + return ovos_core.intent_services.IntentMatch(intent_service='Converse', + intent_type="ovos.utterance.handled" if state != UtteranceState.RESPONSE else None, # emit instead of intent message + intent_data={}, + skill_id=skill_id, + utterance=utterances[0]) return None def handle_get_response_enable(self, message): diff --git a/ovos_core/intent_services/fallback_service.py b/ovos_core/intent_services/fallback_service.py index d3b81de3db7..93124250e02 100644 --- a/ovos_core/intent_services/fallback_service.py +++ b/ovos_core/intent_services/fallback_service.py @@ -165,7 +165,11 @@ def _fallback_range(self, utterances, lang, message, fb_range): for skill_id, prio in sorted_handlers: result = self.attempt_fallback(utterances, skill_id, lang, message) if result: - return ovos_core.intent_services.IntentMatch('Fallback', None, {}, skill_id, utterances[0]) + return ovos_core.intent_services.IntentMatch(intent_service='Fallback', + intent_type=None, + intent_data={}, + skill_id=skill_id, + utterance=utterances[0]) return None def high_prio(self, utterances, lang, message): diff --git a/ovos_core/intent_services/ocp_service.py b/ovos_core/intent_services/ocp_service.py index 78a4a9bba64..2dc3b718e19 100644 --- a/ovos_core/intent_services/ocp_service.py +++ b/ovos_core/intent_services/ocp_service.py @@ -175,21 +175,21 @@ def register_ocp_api_events(self): """ Register messagebus handlers for OCP events """ - self.bus.on("ovos.common_play.search", self.handle_search_query) - self.bus.on("ovos.common_play.play_search", self.handle_play_search) - self.bus.on('ovos.common_play.status.response', self.handle_player_state_update) - self.bus.on('ovos.common_play.track.state', self.handle_track_state_update) - self.bus.on('ovos.common_play.SEI.get.response', self.handle_get_SEIs) - - self.bus.on('ovos.common_play.register_keyword', self.handle_skill_keyword_register) - self.bus.on('ovos.common_play.deregister_keyword', self.handle_skill_keyword_deregister) - self.bus.on('ovos.common_play.announce', self.handle_skill_register) - - self.bus.on("mycroft.audio.playing_track", self._handle_legacy_audio_start) - self.bus.on("mycroft.audio.queue_end", self._handle_legacy_audio_end) - self.bus.on("mycroft.audio.service.pause", self._handle_legacy_audio_pause) - self.bus.on("mycroft.audio.service.resume", self._handle_legacy_audio_resume) - self.bus.on("mycroft.audio.service.stop", self._handle_legacy_audio_stop) + self.add_event("ovos.common_play.search", self.handle_search_query) + self.add_event("ovos.common_play.play_search", self.handle_play_search) + self.add_event('ovos.common_play.status.response', self.handle_player_state_update) + self.add_event('ovos.common_play.track.state', self.handle_track_state_update) + self.add_event('ovos.common_play.SEI.get.response', self.handle_get_SEIs) + + self.add_event('ovos.common_play.register_keyword', self.handle_skill_keyword_register) + self.add_event('ovos.common_play.deregister_keyword', self.handle_skill_keyword_deregister) + self.add_event('ovos.common_play.announce', self.handle_skill_register) + + self.add_event("mycroft.audio.playing_track", self._handle_legacy_audio_start) + self.add_event("mycroft.audio.queue_end", self._handle_legacy_audio_end) + self.add_event("mycroft.audio.service.pause", self._handle_legacy_audio_pause) + self.add_event("mycroft.audio.service.resume", self._handle_legacy_audio_resume) + self.add_event("mycroft.audio.service.stop", self._handle_legacy_audio_stop) self.bus.emit(Message("ovos.common_play.status")) # sync player state on launch def register_ocp_intents(self): @@ -204,17 +204,17 @@ def register_ocp_intents(self): self.intent_matchers[lang].add_intent( intent_name.replace(".intent", ""), samples) - self.bus.on("ocp:play", self.handle_play_intent) - self.bus.on("ocp:play_favorites", self.handle_play_favorites_intent) - self.bus.on("ocp:open", self.handle_open_intent) - self.bus.on("ocp:next", self.handle_next_intent) - self.bus.on("ocp:prev", self.handle_prev_intent) - self.bus.on("ocp:pause", self.handle_pause_intent) - self.bus.on("ocp:resume", self.handle_resume_intent) - self.bus.on("ocp:media_stop", self.handle_stop_intent) - self.bus.on("ocp:search_error", self.handle_search_error_intent) - self.bus.on("ocp:like_song", self.handle_like_intent) - self.bus.on("ocp:legacy_cps", self.handle_legacy_cps) + self.add_event("ocp:play", self.handle_play_intent, is_intent=True) + self.add_event("ocp:play_favorites", self.handle_play_favorites_intent, is_intent=True) + self.add_event("ocp:open", self.handle_open_intent, is_intent=True) + self.add_event("ocp:next", self.handle_next_intent, is_intent=True) + self.add_event("ocp:prev", self.handle_prev_intent, is_intent=True) + self.add_event("ocp:pause", self.handle_pause_intent, is_intent=True) + self.add_event("ocp:resume", self.handle_resume_intent, is_intent=True) + self.add_event("ocp:media_stop", self.handle_stop_intent, is_intent=True) + self.add_event("ocp:search_error", self.handle_search_error_intent, is_intent=True) + self.add_event("ocp:like_song", self.handle_like_intent, is_intent=True) + self.add_event("ocp:legacy_cps", self.handle_legacy_cps, is_intent=True) @property def available_SEI(self): @@ -1015,30 +1015,7 @@ def handle_legacy_cps(self, message: Message): def shutdown(self): self.mycroft_cps.shutdown() - self.bus.remove("ovos.common_play.search", self.handle_search_query) - self.bus.remove("ovos.common_play.play_search", self.handle_play_search) - self.bus.remove('ovos.common_play.status.response', self.handle_player_state_update) - self.bus.remove('ovos.common_play.track.state', self.handle_track_state_update) - self.bus.remove('ovos.common_play.SEI.get.response', self.handle_get_SEIs) - self.bus.remove('ovos.common_play.register_keyword', self.handle_skill_keyword_register) - self.bus.remove('ovos.common_play.deregister_keyword', self.handle_skill_keyword_deregister) - self.bus.remove('ovos.common_play.announce', self.handle_skill_register) - self.bus.remove("mycroft.audio.playing_track", self._handle_legacy_audio_start) - self.bus.remove("mycroft.audio.queue_end", self._handle_legacy_audio_end) - self.bus.remove("mycroft.audio.service.pause", self._handle_legacy_audio_pause) - self.bus.remove("mycroft.audio.service.resume", self._handle_legacy_audio_resume) - self.bus.remove("mycroft.audio.service.stop", self._handle_legacy_audio_stop) - self.bus.remove("ocp:play", self.handle_play_intent) - self.bus.remove("ocp:play_favorites", self.handle_play_favorites_intent) - self.bus.remove("ocp:open", self.handle_open_intent) - self.bus.remove("ocp:next", self.handle_next_intent) - self.bus.remove("ocp:prev", self.handle_prev_intent) - self.bus.remove("ocp:pause", self.handle_pause_intent) - self.bus.remove("ocp:resume", self.handle_resume_intent) - self.bus.remove("ocp:media_stop", self.handle_stop_intent) - self.bus.remove("ocp:search_error", self.handle_search_error_intent) - self.bus.remove("ocp:like_song", self.handle_like_intent) - self.bus.remove("ocp:legacy_cps", self.handle_legacy_cps) + self.default_shutdown() # remove events registered via self.add_event class LegacyCommonPlay: diff --git a/ovos_core/intent_services/stop_service.py b/ovos_core/intent_services/stop_service.py index 13f563b7027..e5a640346ce 100644 --- a/ovos_core/intent_services/stop_service.py +++ b/ovos_core/intent_services/stop_service.py @@ -149,8 +149,11 @@ def match_stop_high(self, utterances, lang, message): # check if any skill can stop for skill_id in self._collect_stop_skills(message): if self.stop_skill(skill_id, message): - return ovos_core.intent_services.IntentMatch('Stop', None, {"conf": conf}, - skill_id, utterance) + return ovos_core.intent_services.IntentMatch(intent_service='Stop', + intent_type="ovos.utterance.handled", + intent_data={"conf": conf}, + skill_id=skill_id, + utterance=utterance) return None def match_stop_medium(self, utterances, lang, message): @@ -210,13 +213,20 @@ def match_stop_low(self, utterances, lang, message): # check if any skill can stop for skill_id in self._collect_stop_skills(message): if self.stop_skill(skill_id, message): - return ovos_core.intent_services.IntentMatch('Stop', None, {"conf": conf}, - skill_id, utterance) + return ovos_core.intent_services.IntentMatch(intent_service='Stop', + intent_type="ovos.utterance.handled", + # emit instead of intent message + intent_data={"conf": conf}, + skill_id=skill_id, utterance=utterance) # emit a global stop, full stop anything OVOS is doing self.bus.emit(message.reply("mycroft.stop", {})) - return ovos_core.intent_services.IntentMatch('Stop', None, {"conf": conf}, - None, utterance) + return ovos_core.intent_services.IntentMatch(intent_service='Stop', + intent_type="ovos.utterance.handled", + # emit instead of intent message {"conf": conf}, + intent_data={}, + skill_id=None, + utterance=utterance) def voc_match(self, utt: str, voc_filename: str, lang: str, exact: bool = False): diff --git a/requirements/requirements.txt b/requirements/requirements.txt index a7f019b8a08..cbc0ecbf1e5 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -12,7 +12,7 @@ ovos-plugin-manager<0.1.0, >=0.0.25 ovos-config~=0.0,>=0.0.13a8 ovos-lingua-franca>=0.4.7 ovos-backend-client~=0.1.0 -ovos-workshop<0.1.0, >=0.0.16a27 +ovos-workshop<0.1.0, >=0.0.16a30 # provides plugins and classic machine learning framework ovos-classifiers<0.1.0, >=0.0.0a53 diff --git a/test/end2end/routing/test_sched.py b/test/end2end/routing/test_sched.py index cf65ef22542..f1cc23f362f 100644 --- a/test/end2end/routing/test_sched.py +++ b/test/end2end/routing/test_sched.py @@ -60,6 +60,7 @@ def wait_for_n_messages(n): "mycroft.scheduler.schedule_event", "mycroft.skill.handler.complete", # intent code end + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default", # session update (end of utterance default sync) # skill event triggering after 3 seconds diff --git a/test/end2end/routing/test_session.py b/test/end2end/routing/test_session.py index 8dba6afb043..934d4415de7 100644 --- a/test/end2end/routing/test_session.py +++ b/test/end2end/routing/test_session.py @@ -59,6 +59,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default" ] wait_for_n_messages(len(expected_messages)) diff --git a/test/end2end/session/test_complete_failure.py b/test/end2end/session/test_complete_failure.py index 0f15653732d..b72c3ff8008 100644 --- a/test/end2end/session/test_complete_failure.py +++ b/test/end2end/session/test_complete_failure.py @@ -70,6 +70,7 @@ def wait_for_n_messages(n): # complete intent failure "mycroft.audio.play_sound", "complete_intent_failure", + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default" ] wait_for_n_messages(len(expected_messages)) @@ -94,10 +95,11 @@ def wait_for_n_messages(n): self.assertEqual(messages[3].msg_type, "mycroft.audio.play_sound") self.assertEqual(messages[3].data["uri"], "snd/error.mp3") self.assertEqual(messages[4].msg_type, "complete_intent_failure") + self.assertEqual(messages[5].msg_type, "ovos.utterance.handled") # verify default session is now updated - self.assertEqual(messages[5].msg_type, "ovos.session.update_default") - self.assertEqual(messages[5].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") @skip("TODO works if run standalone, otherwise has side effects in other tests") def test_complete_failure_lang_detect(self): diff --git a/test/end2end/session/test_converse.py b/test/end2end/session/test_converse.py index 2127b9ece98..98ed733b01d 100644 --- a/test/end2end/session/test_converse.py +++ b/test/end2end/session/test_converse.py @@ -71,6 +71,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated "ovos.session.update_default" ] @@ -111,17 +112,17 @@ def wait_for_n_messages(n): self.assertEqual(messages[8].data["meta"]["skill"], self.skill_id) self.assertEqual(messages[9].msg_type, "mycroft.skill.handler.complete") self.assertEqual(messages[9].data["name"], "TestAbortSkill.handle_converse_off") - + self.assertEqual(messages[10].msg_type, "ovos.utterance.handled") # verify default session is now updated - self.assertEqual(messages[10].msg_type, "ovos.session.update_default") - self.assertEqual(messages[10].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[10].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated self.assertEqual(sess.active_skills[0][0], self.skill_id) - self.assertEqual(messages[10].data["session_data"]["active_skills"][0][0], self.skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][0][0], self.skill_id) messages = [] @@ -153,6 +154,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated "ovos.session.update_default" ] @@ -213,17 +215,18 @@ def wait_for_n_messages(n): self.assertEqual(messages[13].data["name"], "HelloWorldSkill.handle_hello_world_intent") # verify default session is now updated - self.assertEqual(messages[14].msg_type, "ovos.session.update_default") - self.assertEqual(messages[14].data["session_data"]["session_id"], "default") + self.assertEqual(messages[14].msg_type, "ovos.utterance.handled") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[14].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated self.assertEqual(sess.active_skills[0][0], self.other_skill_id) self.assertEqual(sess.active_skills[1][0], self.skill_id) - self.assertEqual(messages[14].data["session_data"]["active_skills"][0][0], self.other_skill_id) - self.assertEqual(messages[14].data["session_data"]["active_skills"][1][0], self.skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][0][0], self.other_skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][1][0], self.skill_id) messages = [] @@ -257,6 +260,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated "ovos.session.update_default" ] @@ -318,17 +322,18 @@ def wait_for_n_messages(n): self.assertEqual(messages[15].data["name"], "TestAbortSkill.handle_converse_on") # verify default session is now updated - self.assertEqual(messages[16].msg_type, "ovos.session.update_default") - self.assertEqual(messages[16].data["session_data"]["session_id"], "default") + self.assertEqual(messages[16].msg_type, "ovos.utterance.handled") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[16].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated self.assertEqual(sess.active_skills[0][0], self.skill_id) self.assertEqual(sess.active_skills[1][0], self.other_skill_id) - self.assertEqual(messages[16].data["session_data"]["active_skills"][0][0], self.skill_id) - self.assertEqual(messages[16].data["session_data"]["active_skills"][1][0], self.other_skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][0][0], self.skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][1][0], self.other_skill_id) messages = [] @@ -353,6 +358,7 @@ def wait_for_n_messages(n): f"{self.skill_id}.activate", "ovos.session.update_default", "skill.converse.response", # CONVERSED + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated "ovos.session.update_default" ] @@ -397,17 +403,18 @@ def wait_for_n_messages(n): self.assertTrue(messages[10].data["result"]) # CONVERSED # verify default session is now updated - self.assertEqual(messages[11].msg_type, "ovos.session.update_default") - self.assertEqual(messages[11].data["session_data"]["session_id"], "default") + self.assertEqual(messages[11].msg_type, "ovos.utterance.handled") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[11].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated self.assertEqual(sess.active_skills[0][0], self.skill_id) self.assertEqual(sess.active_skills[1][0], self.other_skill_id) - self.assertEqual(messages[11].data["session_data"]["active_skills"][0][0], self.skill_id) - self.assertEqual(messages[11].data["session_data"]["active_skills"][1][0], self.other_skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][0][0], self.skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][1][0], self.other_skill_id) messages = [] @@ -515,6 +522,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", # "deactivated" "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated "ovos.session.update_default" ] @@ -553,6 +561,7 @@ def wait_for_n_messages(n): "ovos.session.update_default", # needs ovos-workshop PR "skill.converse.response", # conversed! + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated "ovos.session.update_default" diff --git a/test/end2end/session/test_fallback.py b/test/end2end/session/test_fallback.py index 23ec397c81f..e6a8d0ea1f0 100644 --- a/test/end2end/session/test_fallback.py +++ b/test/end2end/session/test_fallback.py @@ -71,6 +71,7 @@ def wait_for_n_messages(n): "ovos.session.update_default", f"ovos.skills.fallback.{self.skill_id}.response", + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default" ] wait_for_n_messages(len(expected_messages)) @@ -120,8 +121,8 @@ def wait_for_n_messages(n): self.assertEqual(messages[11].data["fallback_handler"], "UnknownSkill.handle_fallback") # verify default session is now updated - self.assertEqual(messages[12].msg_type, "ovos.session.update_default") - self.assertEqual(messages[12].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test second message with no session resumes default active skills messages = [] @@ -195,7 +196,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", f"{self.skill_id}.activate", - f"ovos.skills.fallback.{self.skill_id}.response" + f"ovos.skills.fallback.{self.skill_id}.response", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -291,7 +293,8 @@ def wait_for_n_messages(n): "intent.service.skills.deactivated", f"{self.skill_id}.deactivate", # activate events suppressed - f"ovos.skills.fallback.{self.skill_id}.response" + f"ovos.skills.fallback.{self.skill_id}.response", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) diff --git a/test/end2end/session/test_get_response.py b/test/end2end/session/test_get_response.py index 3ca22b394e1..ae48bdbe990 100644 --- a/test/end2end/session/test_get_response.py +++ b/test/end2end/session/test_get_response.py @@ -86,7 +86,7 @@ def on_speak(msg): "recognizer_loop:audio_output_start", "recognizer_loop:audio_output_end", "mycroft.skill.handler.complete", # original intent finished executing - + "ovos.utterance.handled", # session updated at end of intent pipeline "ovos.session.update_default" ] @@ -159,10 +159,10 @@ def on_speak(msg): self.assertEqual(messages[19].data["name"], "TestAbortSkill.handle_test_get_response") # verify default session is now updated - self.assertEqual(messages[20].msg_type, "ovos.session.update_default") - self.assertEqual(messages[20].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[20].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") def test_with_response(self): @@ -247,7 +247,7 @@ def answer_get_response(msg): "recognizer_loop:audio_output_start", "recognizer_loop:audio_output_end", "mycroft.skill.handler.complete", # original intent finished executing - + "ovos.utterance.handled", # session updated at end of intent pipeline "ovos.session.update_default" @@ -329,10 +329,10 @@ def answer_get_response(msg): self.assertEqual(messages[24].data["name"], "TestAbortSkill.handle_test_get_response") # verify default session is now updated - self.assertEqual(messages[25].msg_type, "ovos.session.update_default") - self.assertEqual(messages[25].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[25].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") def test_cancel_response(self): @@ -417,6 +417,7 @@ def answer_get_response(msg): "recognizer_loop:audio_output_end", "mycroft.skill.handler.complete", # original intent finished executing + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated at end of intent pipeline "ovos.session.update_default" @@ -432,7 +433,6 @@ def answer_get_response(msg): # verify that "session" is injected # (missing in utterance message) and kept in all messages for m in messages[1:]: - print(m.msg_type, m.context["session"]["session_id"]) self.assertEqual(m.context["session"]["session_id"], "default") # verify intent triggers @@ -498,10 +498,10 @@ def answer_get_response(msg): self.assertEqual(messages[24].data["name"], "TestAbortSkill.handle_test_get_response") # verify default session is now updated - self.assertEqual(messages[25].msg_type, "ovos.session.update_default") - self.assertEqual(messages[25].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[25].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") def test_with_reprompt(self): @@ -585,6 +585,7 @@ def answer_get_response(msg): "speak", # speak "ok" inside intent "mycroft.skill.handler.complete", # original intent finished executing + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated at end of intent pipeline "ovos.session.update_default" @@ -654,10 +655,10 @@ def answer_get_response(msg): self.assertEqual(messages[21].data["name"], "TestAbortSkill.handle_test_get_response3") # verify default session is now updated - self.assertEqual(messages[22].msg_type, "ovos.session.update_default") - self.assertEqual(messages[22].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[22].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") def test_nested(self): @@ -784,6 +785,7 @@ def answer_get_response(msg): "mycroft.skill.handler.complete", # original intent finished executing + "ovos.utterance.handled", # handle_utterance returned (intent service) # session updated at end of intent pipeline "ovos.session.update_default" @@ -860,4 +862,4 @@ def answer_get_response(msg): self.assertEqual(messages[50].msg_type, "mycroft.skill.handler.complete") self.assertEqual(messages[50].data["name"], "TestAbortSkill.handle_test_get_response_cascade") - self.assertEqual(messages[51].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") diff --git a/test/end2end/session/test_ocp.py b/test/end2end/session/test_ocp.py index 9f39f0bfccd..c768cb619d4 100644 --- a/test/end2end/session/test_ocp.py +++ b/test/end2end/session/test_ocp.py @@ -77,7 +77,8 @@ def wait_for_n_messages(n): # no good results "ovos.common_play.reset", "enclosure.active_skill", - "speak" # error + "speak", # error, + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -146,7 +147,8 @@ def wait_for_n_messages(n): # good results because of radio media type "ovos.common_play.reset", "add_context", # NowPlaying context - "ovos.common_play.play" # OCP api + "ovos.common_play.play", # OCP api, + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -155,7 +157,7 @@ def wait_for_n_messages(n): for idx, m in enumerate(messages): self.assertEqual(m.msg_type, expected_messages[idx]) - play = messages[-1] + play = messages[-2] self.assertEqual(play.data["media"]["uri"], "https://fake_4.mp3") def test_unk_media_match(self): @@ -220,7 +222,8 @@ def wait_for_n_messages(n): # no good results "ovos.common_play.reset", "enclosure.active_skill", - "speak" # error + "speak", # error + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -289,7 +292,8 @@ def wait_for_n_messages(n): # good results "ovos.common_play.reset", "add_context", # NowPlaying context - "ovos.common_play.play" # OCP api + "ovos.common_play.play", # OCP api + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -361,7 +365,8 @@ def wait_for_n_messages(n): # good results because of radio media type "ovos.common_play.reset", "add_context", # NowPlaying context - 'mycroft.audio.service.play' # LEGACY api + 'mycroft.audio.service.play', # LEGACY api + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -418,7 +423,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:pause", - 'mycroft.audio.service.pause' # LEGACY api + 'mycroft.audio.service.pause', # LEGACY api + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -474,7 +480,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:resume", - 'mycroft.audio.service.resume' # LEGACY api + 'mycroft.audio.service.resume', # LEGACY api + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -530,7 +537,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:media_stop", - 'mycroft.audio.service.stop' # LEGACY api + 'mycroft.audio.service.stop', # LEGACY api + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -586,7 +594,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:next", - 'mycroft.audio.service.next' # LEGACY api + 'mycroft.audio.service.next', # LEGACY api + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -640,7 +649,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:prev", - 'mycroft.audio.service.prev' # LEGACY api + 'mycroft.audio.service.prev', # LEGACY api + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -693,7 +703,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:pause", - 'ovos.common_play.pause' + 'ovos.common_play.pause', + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -746,7 +757,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:resume", - 'ovos.common_play.resume' + 'ovos.common_play.resume', + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -800,7 +812,8 @@ def wait_for_n_messages(n): "ovos.common_play.activate", "ocp:media_stop", 'ovos.common_play.stop', - "ovos.common_play.stop.response" + "ovos.common_play.stop.response", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -853,7 +866,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:next", - 'ovos.common_play.next' + 'ovos.common_play.next', + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -906,7 +920,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", "ovos.common_play.activate", "ocp:prev", - 'ovos.common_play.previous' + 'ovos.common_play.previous', + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -959,7 +974,8 @@ def wait_for_n_messages(n): "recognizer_loop:utterance", "ovos.common_play.status", "mycroft.audio.play_sound", - "complete_intent_failure" + "complete_intent_failure", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -1009,7 +1025,8 @@ def wait_for_n_messages(n): "ocp:legacy_cps", # legacy cps api "play:query", - "mycroft.audio.play_sound" # error - no results + "mycroft.audio.play_sound", # error - no results + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -1068,8 +1085,8 @@ def wait_for_n_messages(n): "ocp:legacy_cps", # legacy cps api "play:query", - "play:query.response", # searching - "play:query.response", # report results + "play:query.response", # searching + "play:query.response", # report results "play:start", # skill selected "mycroft.audio.service.track_info", # check is legacy audio service is playing # global stop signal @@ -1084,7 +1101,8 @@ def wait_for_n_messages(n): "intent.service.skills.activated", f"{self.skill_id}.activate", # skill callback code - "mycroft.audio.service.play" + "mycroft.audio.service.play", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -1093,6 +1111,5 @@ def wait_for_n_messages(n): for idx, m in enumerate(messages): self.assertEqual(m.msg_type, expected_messages[idx]) - play = messages[-1] + play = messages[-2] self.assertEqual(play.data["tracks"], ["https://fake.mp3"]) - diff --git a/test/end2end/session/test_sched.py b/test/end2end/session/test_sched.py index c0763bf2a3c..e2a5ec8f355 100644 --- a/test/end2end/session/test_sched.py +++ b/test/end2end/session/test_sched.py @@ -58,6 +58,7 @@ def wait_for_n_messages(n): "speak", "mycroft.scheduler.schedule_event", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default", # event triggering after 3 seconds "skill-ovos-schedule.openvoiceos:my_event", @@ -107,30 +108,30 @@ def wait_for_n_messages(n): self.assertEqual(messages[10].data["name"], "ScheduleSkill.handle_sched_intent") # verify default session is now updated - self.assertEqual(messages[11].msg_type, "ovos.session.update_default") - self.assertEqual(messages[11].data["session_data"]["session_id"], "default") + self.assertEqual(messages[12].msg_type, "ovos.session.update_default") + self.assertEqual(messages[12].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[11].data["session_data"]) + sess = Session.deserialize(messages[12].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated self.assertEqual(sess.active_skills[0][0], self.skill_id) - self.assertEqual(messages[11].data["session_data"]["active_skills"][0][0], self.skill_id) + self.assertEqual(messages[12].data["session_data"]["active_skills"][0][0], self.skill_id) # ensure context in triggered event is the same from message that triggered the intent self.assertEqual(messages[4].msg_type, "intent.service.skills.activated") intent_context = messages[4].context # when skill added to active list (last context change) - self.assertEqual(messages[12].msg_type, "skill-ovos-schedule.openvoiceos:my_event") - self.assertEqual(messages[12].context, intent_context) - self.assertEqual(messages[13].msg_type, "enclosure.active_skill") + self.assertEqual(messages[13].msg_type, "skill-ovos-schedule.openvoiceos:my_event") self.assertEqual(messages[13].context, intent_context) - self.assertEqual(messages[14].msg_type, "speak") - self.assertEqual(messages[14].data["lang"], "en-us") - self.assertFalse(messages[14].data["expect_response"]) - self.assertEqual(messages[14].data["meta"]["dialog"], "trigger") - self.assertEqual(messages[14].data["meta"]["skill"], self.skill_id) + self.assertEqual(messages[14].msg_type, "enclosure.active_skill") self.assertEqual(messages[14].context, intent_context) + self.assertEqual(messages[15].msg_type, "speak") + self.assertEqual(messages[15].data["lang"], "en-us") + self.assertFalse(messages[15].data["expect_response"]) + self.assertEqual(messages[15].data["meta"]["dialog"], "trigger") + self.assertEqual(messages[15].data["meta"]["skill"], self.skill_id) + self.assertEqual(messages[15].context, intent_context) def test_explicit_session(self): SessionManager.sessions = {} @@ -180,6 +181,7 @@ def wait_for_n_messages(n): "speak", "mycroft.scheduler.schedule_event", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) # event triggering after 3 seconds "skill-ovos-schedule.openvoiceos:my_event", "enclosure.active_skill", @@ -230,16 +232,16 @@ def wait_for_n_messages(n): self.assertEqual(messages[4].msg_type, "intent.service.skills.activated") intent_context = messages[4].context # when skill added to active list (last context change) - self.assertEqual(messages[10].msg_type, "skill-ovos-schedule.openvoiceos:my_event") - self.assertEqual(messages[10].context, intent_context) - self.assertEqual(messages[11].msg_type, "enclosure.active_skill") + self.assertEqual(messages[11].msg_type, "skill-ovos-schedule.openvoiceos:my_event") self.assertEqual(messages[11].context, intent_context) - self.assertEqual(messages[12].msg_type, "speak") - self.assertEqual(messages[12].data["lang"], "en-us") - self.assertFalse(messages[12].data["expect_response"]) - self.assertEqual(messages[12].data["meta"]["dialog"], "trigger") - self.assertEqual(messages[12].data["meta"]["skill"], self.skill_id) + self.assertEqual(messages[12].msg_type, "enclosure.active_skill") self.assertEqual(messages[12].context, intent_context) + self.assertEqual(messages[13].msg_type, "speak") + self.assertEqual(messages[13].data["lang"], "en-us") + self.assertFalse(messages[13].data["expect_response"]) + self.assertEqual(messages[13].data["meta"]["dialog"], "trigger") + self.assertEqual(messages[13].data["meta"]["skill"], self.skill_id) + self.assertEqual(messages[13].context, intent_context) def tearDown(self) -> None: self.core.stop() diff --git a/test/end2end/session/test_session.py b/test/end2end/session/test_session.py index 8d29fc962e5..33fa4db9f6d 100644 --- a/test/end2end/session/test_session.py +++ b/test/end2end/session/test_session.py @@ -61,6 +61,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default" ] wait_for_n_messages(len(expected_messages)) @@ -106,15 +107,15 @@ def wait_for_n_messages(n): self.assertEqual(messages[9].data["name"], "HelloWorldSkill.handle_hello_world_intent") # verify default session is now updated - self.assertEqual(messages[10].msg_type, "ovos.session.update_default") - self.assertEqual(messages[10].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[10].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated self.assertEqual(sess.active_skills[0][0], self.skill_id) - self.assertEqual(messages[10].data["session_data"]["active_skills"][0][0], self.skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][0][0], self.skill_id) def test_explicit_default_session(self): SessionManager.sessions = {} @@ -167,6 +168,7 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) "ovos.session.update_default" ] wait_for_n_messages(len(expected_messages)) @@ -216,15 +218,15 @@ def wait_for_n_messages(n): self.assertEqual(messages[11].data["name"], "HelloWorldSkill.handle_hello_world_intent") # verify default session is now updated - self.assertEqual(messages[12].msg_type, "ovos.session.update_default") - self.assertEqual(messages[12].data["session_data"]["session_id"], "default") + self.assertEqual(messages[-1].msg_type, "ovos.session.update_default") + self.assertEqual(messages[-1].data["session_data"]["session_id"], "default") # test deserialization of payload - sess = Session.deserialize(messages[12].data["session_data"]) + sess = Session.deserialize(messages[-1].data["session_data"]) self.assertEqual(sess.session_id, "default") # test that active skills list has been updated - self.assertEqual(messages[12].data["session_data"]["active_skills"][0][0], self.skill_id) + self.assertEqual(messages[-1].data["session_data"]["active_skills"][0][0], self.skill_id) self.assertEqual(sess.active_skills[0][0], self.skill_id) self.assertNotEqual(sess.active_skills[0][1], now) @@ -282,7 +284,8 @@ def wait_for_n_messages(n): f"{self.skill_id}.activate", "enclosure.active_skill", "speak", - "mycroft.skill.handler.complete" + "mycroft.skill.handler.complete", + "ovos.utterance.handled", # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) diff --git a/test/end2end/session/test_stop.py b/test/end2end/session/test_stop.py index 1d6e45839db..f6836c2c257 100644 --- a/test/end2end/session/test_stop.py +++ b/test/end2end/session/test_stop.py @@ -115,7 +115,8 @@ def wait_for_n_messages(n): # skill code executing "enclosure.active_skill", "speak", - "mycroft.skill.handler.complete" + "mycroft.skill.handler.complete", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -288,7 +289,8 @@ def wait_for_n_messages(n): # skill code executing "enclosure.active_skill", "speak", - "mycroft.skill.handler.complete" + "mycroft.skill.handler.complete", + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -332,7 +334,8 @@ def wait_for_n_messages(n): "enclosure.active_skill", "speak", # "utterance":"stop 123" - f"{self.new_skill_id}.stop.response", # skill reports it stopped (new style) + f"{self.new_skill_id}.stop.response", # skill reports it stopped (new style), + "ovos.utterance.handled" # handle_utterance returned (intent service) ] wait_for_n_messages(len(expected_messages)) @@ -348,7 +351,7 @@ def wait_for_n_messages(n): self.assertEqual(m.data["utterance"], "stop 123") # confirm "skill-new-stop" was the one that reported success - handler = messages[-1] + handler = messages[-2] self.assertEqual(handler.msg_type, f"{self.new_skill_id}.stop.response") self.assertEqual(handler.data["result"], True) diff --git a/test/unittests/skills/test_intent_service.py b/test/unittests/skills/test_intent_service.py index a9ca59bfb49..5dbaafc7a7a 100644 --- a/test/unittests/skills/test_intent_service.py +++ b/test/unittests/skills/test_intent_service.py @@ -256,107 +256,124 @@ def test_get_no_match_after_detach_skill(self): self.assertEqual(reply.data['intent'], None) def test_shutdown(self): - intent_service = IntentService(MockEmitter(), config={"experimental_ocp_pipeline": False, "padatious": {"disabled": True}}) intent_service.shutdown() - self.assertListEqual(intent_service.bus.removed, - ['padatious:register_intent', - 'padatious:register_entity', - 'detach_intent', - 'detach_skill', - 'question:query.response', - 'common_query.question', - 'ovos.common_query.pong', - 'mycroft.speech.recognition.unknown', - 'intent.service.skills.deactivate', - 'intent.service.skills.activate', - 'active_skill_request', - 'intent.service.active_skills.get', - 'skill.converse.get_response.enable', - 'skill.converse.get_response.disable', - 'ovos.skills.fallback.register', - 'ovos.skills.fallback.deregister', - 'register_vocab', - 'register_intent', - 'recognizer_loop:utterance', - 'detach_intent', - 'detach_skill', - 'add_context', - 'remove_context', - 'clear_context', - 'mycroft.skills.loaded', - 'intent.service.intent.get', - 'intent.service.skills.get', - 'intent.service.adapt.get', - 'intent.service.adapt.manifest.get', - 'intent.service.adapt.vocab.manifest.get', - 'intent.service.padatious.get', - 'intent.service.padatious.manifest.get', - 'intent.service.padatious.entities.manifest.get']) + self.assertEqual(intent_service.bus.removed, + ['padatious:register_intent', + 'padatious:register_entity', + 'detach_intent', + 'detach_skill', + 'question:query.response', + 'common_query.question', + 'ovos.common_query.pong', + 'mycroft.speech.recognition.unknown', + 'intent.service.skills.deactivate', + 'intent.service.skills.activate', + 'active_skill_request', + 'intent.service.active_skills.get', + 'skill.converse.get_response.enable', + 'skill.converse.get_response.disable', + 'ovos.skills.fallback.register', + 'ovos.skills.fallback.deregister', + 'register_vocab', + 'register_intent', + 'recognizer_loop:utterance', + 'detach_intent', + 'detach_skill', + 'add_context', + 'remove_context', + 'clear_context', + 'mycroft.skills.loaded', + 'intent.service.intent.get', + 'intent.service.skills.get', + 'intent.service.adapt.get', + 'intent.service.adapt.manifest.get', + 'intent.service.adapt.vocab.manifest.get', + 'intent.service.padatious.get', + 'intent.service.padatious.manifest.get', + 'intent.service.padatious.entities.manifest.get']) intent_service = IntentService(MockEmitter(), config={"experimental_ocp_pipeline": True, "padatious": {"disabled": True}}) intent_service.shutdown() - self.assertListEqual(intent_service.bus.removed, - ['padatious:register_intent', - 'padatious:register_entity', - 'detach_intent', - 'detach_skill', - 'question:query.response', - 'common_query.question', - 'ovos.common_query.pong', - 'mycroft.speech.recognition.unknown', - 'intent.service.skills.deactivate', - 'intent.service.skills.activate', - 'active_skill_request', - 'intent.service.active_skills.get', - 'skill.converse.get_response.enable', - 'skill.converse.get_response.disable', - 'ovos.skills.fallback.register', - 'ovos.skills.fallback.deregister', - 'play:query.response', - 'ovos.common_play.search', - 'ovos.common_play.play_search', - 'ovos.common_play.status.response', - 'ovos.common_play.track.state', - 'ovos.common_play.SEI.get.response', - 'ovos.common_play.register_keyword', - 'ovos.common_play.deregister_keyword', - 'ovos.common_play.announce', - 'mycroft.audio.playing_track', - 'mycroft.audio.queue_end', - 'mycroft.audio.service.pause', - 'mycroft.audio.service.resume', - 'mycroft.audio.service.stop', - 'ocp:play', - 'ocp:play_favorites', - 'ocp:open', - 'ocp:next', - 'ocp:prev', - 'ocp:pause', - 'ocp:resume', - 'ocp:media_stop', - 'ocp:search_error', - 'ocp:like_song', - 'ocp:legacy_cps', - 'register_vocab', - 'register_intent', - 'recognizer_loop:utterance', - 'detach_intent', - 'detach_skill', - 'add_context', - 'remove_context', - 'clear_context', - 'mycroft.skills.loaded', - 'intent.service.intent.get', - 'intent.service.skills.get', - 'intent.service.adapt.get', - 'intent.service.adapt.manifest.get', - 'intent.service.adapt.vocab.manifest.get', - 'intent.service.padatious.get', - 'intent.service.padatious.manifest.get', - 'intent.service.padatious.entities.manifest.get']) + self.assertEqual(set(intent_service.bus.removed), + {'active_skill_request', + 'add_context', + 'clear_context', + 'common_query.question', + 'detach_intent', + 'detach_skill', + 'intent.service.active_skills.get', + 'intent.service.adapt.get', + 'intent.service.adapt.manifest.get', + 'intent.service.adapt.vocab.manifest.get', + 'intent.service.intent.get', + 'intent.service.padatious.entities.manifest.get', + 'intent.service.padatious.get', + 'intent.service.padatious.manifest.get', + 'intent.service.skills.activate', + 'intent.service.skills.activated', + 'intent.service.skills.deactivate', + 'intent.service.skills.deactivated', + 'intent.service.skills.get', + 'mycroft.audio.playing_track', + 'mycroft.audio.queue_end', + 'mycroft.audio.service.pause', + 'mycroft.audio.service.resume', + 'mycroft.audio.service.stop', + 'mycroft.skill.disable_intent', + 'mycroft.skill.enable_intent', + 'mycroft.skill.remove_cross_context', + 'mycroft.skill.set_cross_context', + 'mycroft.skills.loaded', + 'mycroft.skills.settings.changed', + 'mycroft.speech.recognition.unknown', + 'mycroft.stop', + 'ocp:legacy_cps', + 'ocp:like_song', + 'ocp:media_stop', + 'ocp:next', + 'ocp:open', + 'ocp:pause', + 'ocp:play', + 'ocp:play_favorites', + 'ocp:prev', + 'ocp:resume', + 'ocp:search_error', + 'ovos.common_play.SEI.get.response', + 'ovos.common_play.activate', + 'ovos.common_play.announce', + 'ovos.common_play.converse.get_response', + 'ovos.common_play.converse.ping', + 'ovos.common_play.converse.request', + 'ovos.common_play.deactivate', + 'ovos.common_play.deregister_keyword', + 'ovos.common_play.play_search', + 'ovos.common_play.register_keyword', + 'ovos.common_play.search', + 'ovos.common_play.set', + 'ovos.common_play.status.response', + 'ovos.common_play.stop', + 'ovos.common_play.stop.ping', + 'ovos.common_play.track.state', + 'ovos.common_query.pong', + 'ovos.skills.fallback.deregister', + 'ovos.skills.fallback.register', + 'ovos.skills.settings_changed', + 'padatious:register_entity', + 'padatious:register_intent', + 'play:query.response', + 'question:query.response', + 'recognizer_loop:utterance', + 'register_intent', + 'register_vocab', + 'remove_context', + 'skill.converse.get_response', + 'skill.converse.get_response.disable', + 'skill.converse.get_response.enable', + 'skill.converse.ping', + 'skill.converse.request'}) class TestAdaptIntent(TestCase):