diff --git a/homeassistant/components/conversation/default_agent.py b/homeassistant/components/conversation/default_agent.py index bebf8cf4b6a..c9119935213 100644 --- a/homeassistant/components/conversation/default_agent.py +++ b/homeassistant/components/conversation/default_agent.py @@ -6,7 +6,6 @@ from collections import defaultdict from collections.abc import Awaitable, Callable, Iterable from dataclasses import dataclass import functools -import itertools import logging from pathlib import Path import re @@ -28,7 +27,7 @@ from hassil.recognize import ( recognize_all, ) from hassil.util import merge_dict -from home_assistant_intents import get_domains_and_languages, get_intents +from home_assistant_intents import get_intents, get_languages import yaml from homeassistant import core, setup @@ -156,7 +155,7 @@ class DefaultAgent(AbstractConversationAgent): @property def supported_languages(self) -> list[str]: """Return a list of supported languages.""" - return get_domains_and_languages()["homeassistant"] + return get_languages() async def async_initialize(self, config_intents: dict[str, Any] | None) -> None: """Initialize the default agent.""" @@ -387,6 +386,7 @@ class DefaultAgent(AbstractConversationAgent): return maybe_result # Try again with missing entities enabled + best_num_unmatched_entities = 0 for result in recognize_all( user_input.text, lang_intents.intents, @@ -394,20 +394,28 @@ class DefaultAgent(AbstractConversationAgent): intent_context=intent_context, allow_unmatched_entities=True, ): - # Remove missing entities that couldn't be filled from context - for entity_key, entity in list(result.unmatched_entities.items()): - if isinstance(entity, UnmatchedTextEntity) and ( - entity.text == MISSING_ENTITY - ): - result.unmatched_entities.pop(entity_key) + if result.text_chunks_matched < 1: + # Skip results that don't match any literal text + continue + + # Don't count missing entities that couldn't be filled from context + num_unmatched_entities = 0 + for entity in result.unmatched_entities_list: + if isinstance(entity, UnmatchedTextEntity): + if entity.text != MISSING_ENTITY: + num_unmatched_entities += 1 + else: + num_unmatched_entities += 1 if maybe_result is None: # First result maybe_result = result - elif len(result.unmatched_entities) < len(maybe_result.unmatched_entities): + best_num_unmatched_entities = num_unmatched_entities + elif num_unmatched_entities < best_num_unmatched_entities: # Fewer unmatched entities maybe_result = result - elif len(result.unmatched_entities) == len(maybe_result.unmatched_entities): + best_num_unmatched_entities = num_unmatched_entities + elif num_unmatched_entities == best_num_unmatched_entities: if (result.text_chunks_matched > maybe_result.text_chunks_matched) or ( (result.text_chunks_matched == maybe_result.text_chunks_matched) and ("name" in result.unmatched_entities) # prefer entities @@ -536,14 +544,12 @@ class DefaultAgent(AbstractConversationAgent): intents_dict = lang_intents.intents_dict language_variant = lang_intents.language_variant - domains_langs = get_domains_and_languages() + supported_langs = set(get_languages()) if not language_variant: # Choose a language variant upfront and commit to it for custom # sentences, etc. - all_language_variants = { - lang.lower(): lang for lang in itertools.chain(*domains_langs.values()) - } + all_language_variants = {lang.lower(): lang for lang in supported_langs} # en-US, en_US, en, ... for maybe_variant in _get_language_variations(language): @@ -558,23 +564,17 @@ class DefaultAgent(AbstractConversationAgent): ) return None - # Load intents for all domains supported by this language variant - for domain in domains_langs: - domain_intents = get_intents( - domain, language_variant, json_load=json_load - ) - - if not domain_intents: - continue + # Load intents for this language variant + lang_variant_intents = get_intents(language_variant, json_load=json_load) + if lang_variant_intents: # Merge sentences into existing dictionary - merge_dict(intents_dict, domain_intents) + merge_dict(intents_dict, lang_variant_intents) # Will need to recreate graph intents_changed = True _LOGGER.debug( - "Loaded intents domain=%s, language=%s (%s)", - domain, + "Loaded intents language=%s (%s)", language, language_variant, ) diff --git a/homeassistant/components/conversation/manifest.json b/homeassistant/components/conversation/manifest.json index 96fd7aaf67f..89dd880f69e 100644 --- a/homeassistant/components/conversation/manifest.json +++ b/homeassistant/components/conversation/manifest.json @@ -7,5 +7,5 @@ "integration_type": "system", "iot_class": "local_push", "quality_scale": "internal", - "requirements": ["hassil==1.6.0", "home-assistant-intents==2024.1.2"] + "requirements": ["hassil==1.6.0", "home-assistant-intents==2024.1.29"] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 330917437b8..f4205091d97 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -29,7 +29,7 @@ hass-nabucasa==0.75.1 hassil==1.6.0 home-assistant-bluetooth==1.12.0 home-assistant-frontend==20240112.0 -home-assistant-intents==2024.1.2 +home-assistant-intents==2024.1.29 httpx==0.26.0 ifaddr==0.2.0 janus==1.0.0 diff --git a/requirements_all.txt b/requirements_all.txt index 925d838427e..77e89cae6fb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1056,7 +1056,7 @@ holidays==0.41 home-assistant-frontend==20240112.0 # homeassistant.components.conversation -home-assistant-intents==2024.1.2 +home-assistant-intents==2024.1.29 # homeassistant.components.home_connect homeconnect==0.7.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index dcfc3271f2f..327e61e98a7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -849,7 +849,7 @@ holidays==0.41 home-assistant-frontend==20240112.0 # homeassistant.components.conversation -home-assistant-intents==2024.1.2 +home-assistant-intents==2024.1.29 # homeassistant.components.home_connect homeconnect==0.7.2 diff --git a/tests/components/assist_pipeline/snapshots/test_init.ambr b/tests/components/assist_pipeline/snapshots/test_init.ambr index 128f5479077..e822759d208 100644 --- a/tests/components/assist_pipeline/snapshots/test_init.ambr +++ b/tests/components/assist_pipeline/snapshots/test_init.ambr @@ -48,14 +48,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -67,7 +67,7 @@ 'data': dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'james_earl_jones', }), 'type': , @@ -75,9 +75,9 @@ dict({ 'data': dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3', }), }), 'type': , @@ -137,14 +137,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en-US', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -156,7 +156,7 @@ 'data': dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'Arnold Schwarzenegger', }), 'type': , @@ -164,9 +164,9 @@ dict({ 'data': dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=Arnold+Schwarzenegger', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=Arnold+Schwarzenegger", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_2657c1a8ee_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_2657c1a8ee_test.mp3', }), }), 'type': , @@ -226,14 +226,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en-US', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -245,7 +245,7 @@ 'data': dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'Arnold Schwarzenegger', }), 'type': , @@ -253,9 +253,9 @@ dict({ 'data': dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=Arnold+Schwarzenegger', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=Arnold+Schwarzenegger", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_2657c1a8ee_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_2657c1a8ee_test.mp3', }), }), 'type': , @@ -338,14 +338,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -357,7 +357,7 @@ 'data': dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'james_earl_jones', }), 'type': , @@ -365,9 +365,9 @@ dict({ 'data': dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3', }), }), 'type': , diff --git a/tests/components/assist_pipeline/snapshots/test_websocket.ambr b/tests/components/assist_pipeline/snapshots/test_websocket.ambr index 31b1c44e67e..a050b009a8d 100644 --- a/tests/components/assist_pipeline/snapshots/test_websocket.ambr +++ b/tests/components/assist_pipeline/snapshots/test_websocket.ambr @@ -46,14 +46,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -64,16 +64,16 @@ dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'james_earl_jones', }) # --- # name: test_audio_pipeline.6 dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3', }), }) # --- @@ -127,14 +127,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -145,16 +145,16 @@ dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'james_earl_jones', }) # --- # name: test_audio_pipeline_debug.6 dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3', }), }) # --- @@ -220,14 +220,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -238,16 +238,16 @@ dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'james_earl_jones', }) # --- # name: test_audio_pipeline_with_enhancements.6 dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3', }), }) # --- @@ -421,14 +421,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test transcript', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -439,16 +439,16 @@ dict({ 'engine': 'test', 'language': 'en-US', - 'tts_input': 'No device or entity named test transcript', + 'tts_input': "Sorry, I couldn't understand that", 'voice': 'james_earl_jones', }) # --- # name: test_audio_pipeline_with_wake_word_no_timeout.8 dict({ 'tts_output': dict({ - 'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones', + 'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones", 'mime_type': 'audio/mpeg', - 'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3', + 'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3', }), }) # --- @@ -778,7 +778,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No area named are', + 'speech': 'Sorry, I am not aware of any area called are', }), }), }), diff --git a/tests/components/conversation/snapshots/test_init.ambr b/tests/components/conversation/snapshots/test_init.ambr index e5a732eab8d..23dab0902a9 100644 --- a/tests/components/conversation/snapshots/test_init.ambr +++ b/tests/components/conversation/snapshots/test_init.ambr @@ -352,14 +352,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named do something', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -519,7 +519,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named late added alias', + 'speech': 'Sorry, I am not aware of any device or entity called late added alias', }), }), }), @@ -539,7 +539,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named kitchen light', + 'speech': 'Sorry, I am not aware of any device or entity called kitchen light', }), }), }), @@ -679,7 +679,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named late added light', + 'speech': 'Sorry, I am not aware of any device or entity called late added light', }), }), }), @@ -759,7 +759,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named kitchen light', + 'speech': 'Sorry, I am not aware of any device or entity called kitchen light', }), }), }), @@ -779,7 +779,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named my cool light', + 'speech': 'Sorry, I am not aware of any device or entity called my cool light', }), }), }), @@ -919,7 +919,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named kitchen light', + 'speech': 'Sorry, I am not aware of any device or entity called kitchen light', }), }), }), @@ -969,7 +969,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named renamed light', + 'speech': 'Sorry, I am not aware of any device or entity called renamed light', }), }), }), @@ -1252,14 +1252,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test text', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -1292,14 +1292,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test text', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -1312,14 +1312,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test text', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -1352,14 +1352,14 @@ 'card': dict({ }), 'data': dict({ - 'code': 'no_valid_targets', + 'code': 'no_intent_match', }), 'language': 'en', 'response_type': 'error', 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'No device or entity named test text', + 'speech': "Sorry, I couldn't understand that", }), }), }), @@ -1510,29 +1510,7 @@ 'unmatched_slots': dict({ }), }), - dict({ - 'details': dict({ - 'domain': dict({ - 'name': 'domain', - 'text': '', - 'value': 'scene', - }), - }), - 'intent': dict({ - 'name': 'HassTurnOn', - }), - 'match': False, - 'sentence_template': '[activate|] [scene] [on]', - 'slots': dict({ - 'domain': 'scene', - }), - 'source': 'builtin', - 'targets': dict({ - }), - 'unmatched_slots': dict({ - 'name': 'this will not match anything', - }), - }), + None, ]), }) # --- diff --git a/tests/components/conversation/test_default_agent.py b/tests/components/conversation/test_default_agent.py index 1bd8b5263e5..b992b0086d7 100644 --- a/tests/components/conversation/test_default_agent.py +++ b/tests/components/conversation/test_default_agent.py @@ -147,8 +147,8 @@ async def test_conversation_agent( conversation.HOME_ASSISTANT_AGENT ) with patch( - "homeassistant.components.conversation.default_agent.get_domains_and_languages", - return_value={"homeassistant": ["dwarvish", "elvish", "entish"]}, + "homeassistant.components.conversation.default_agent.get_languages", + return_value=["dwarvish", "elvish", "entish"], ): assert agent.supported_languages == ["dwarvish", "elvish", "entish"] @@ -440,7 +440,7 @@ async def test_error_missing_entity(hass: HomeAssistant, init_components) -> Non assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS assert ( result.response.speech["plain"]["speech"] - == "No device or entity named missing entity" + == "Sorry, I am not aware of any device or entity called missing entity" ) @@ -452,7 +452,10 @@ async def test_error_missing_area(hass: HomeAssistant, init_components) -> None: assert result.response.response_type == intent.IntentResponseType.ERROR assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS - assert result.response.speech["plain"]["speech"] == "No area named missing area" + assert ( + result.response.speech["plain"]["speech"] + == "Sorry, I am not aware of any area called missing area" + ) async def test_error_no_exposed_for_domain( @@ -467,7 +470,8 @@ async def test_error_no_exposed_for_domain( assert result.response.response_type == intent.IntentResponseType.ERROR assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS assert ( - result.response.speech["plain"]["speech"] == "kitchen does not contain a light" + result.response.speech["plain"]["speech"] + == "Sorry, I am not aware of any light in the kitchen area" ) @@ -483,7 +487,8 @@ async def test_error_no_exposed_for_device_class( assert result.response.response_type == intent.IntentResponseType.ERROR assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS assert ( - result.response.speech["plain"]["speech"] == "bedroom does not contain a window" + result.response.speech["plain"]["speech"] + == "Sorry, I am not aware of any window in the bedroom area" ) @@ -596,5 +601,5 @@ async def test_all_domains_loaded( assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS assert ( result.response.speech["plain"]["speech"] - == "No device or entity named test light" + == "Sorry, I am not aware of any device or entity called test light" ) diff --git a/tests/components/conversation/test_init.py b/tests/components/conversation/test_init.py index b654f50f8fe..58e94d27aac 100644 --- a/tests/components/conversation/test_init.py +++ b/tests/components/conversation/test_init.py @@ -581,6 +581,7 @@ async def test_http_api_no_match( assert data == snapshot assert data["response"]["response_type"] == "error" + assert data["response"]["data"]["code"] == "no_intent_match" async def test_http_api_handle_failure( @@ -738,6 +739,7 @@ async def test_ws_api( assert msg["success"] assert msg["result"] == snapshot + assert msg["result"]["response"]["data"]["code"] == "no_intent_match" @pytest.mark.parametrize("agent_id", AGENT_ID_OPTIONS) @@ -1180,7 +1182,7 @@ async def test_ws_hass_agent_debug( "turn my cool light off", "turn on all lights in the kitchen", "how many lights are on in the kitchen?", - "this will not match anything", # unmatched in results + "this will not match anything", # None in results ], } ) @@ -1190,6 +1192,9 @@ async def test_ws_hass_agent_debug( assert msg["success"] assert msg["result"] == snapshot + # Last sentence should be a failed match + assert msg["result"]["results"][-1] is None + # Light state should not have been changed assert len(on_calls) == 0 assert len(off_calls) == 0