Invalidate conversation slot-list cache on device registry changes (#179486)

This commit is contained in:
Erik Montnemery
2026-08-21 20:13:10 +00:00
committed by Franck Nijhof
parent 7ae599382e
commit 6e2121a321
2 changed files with 63 additions and 0 deletions
@@ -83,6 +83,7 @@ _LOGGER = logging.getLogger(__name__)
_DEFAULT_ERROR_TEXT = "Sorry, I couldn't understand that"
_ENTITY_REGISTRY_UPDATE_FIELDS = ["aliases", "name", "original_name"]
_DEVICE_REGISTRY_UPDATE_FIELDS = ["name", "name_by_user"]
_DEFAULT_EXPOSED_ATTRIBUTES = {"device_class"}
@@ -288,6 +289,15 @@ class DefaultAgent(ConversationEntity):
field in event_data["changes"] for field in _ENTITY_REGISTRY_UPDATE_FIELDS
)
@callback
def _filter_device_registry_changes(
self, event_data: dr.EventDeviceRegistryUpdatedData
) -> bool:
"""Filter device registry changed events."""
return event_data["action"] == "update" and any(
field in event_data["changes"] for field in _DEVICE_REGISTRY_UPDATE_FIELDS
)
@callback
def _filter_state_changes(self, event_data: EventStateChangedData) -> bool:
"""Filter state changed events."""
@@ -312,6 +322,11 @@ class DefaultAgent(ConversationEntity):
self._async_clear_slot_list,
event_filter=self._filter_entity_registry_changes,
),
self.hass.bus.async_listen(
dr.EVENT_DEVICE_REGISTRY_UPDATED,
self._async_clear_slot_list,
event_filter=self._filter_device_registry_changes,
),
self.hass.bus.async_listen(
EVENT_STATE_CHANGED,
self._async_clear_slot_list,
@@ -492,6 +492,54 @@ async def test_duplicated_names_resolved_with_device_area(
assert result.response.intent.slots.get("name", {}).get("text") == name
@pytest.mark.usefixtures("init_components")
async def test_device_rename_refreshes_slot_list(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test renaming a device makes the entity matchable by its new computed name."""
config_entry = MockConfigEntry()
config_entry.add_to_hass(hass)
device = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections=set(),
identifiers={("demo", "device-1")},
name="Kitchen",
)
light = entity_registry.async_get_or_create(
"light",
"demo",
"1234",
device_id=device.id,
has_entity_name=True,
original_name="Light",
)
hass.states.async_set(light.entity_id, "off")
expose_entity(hass, light.entity_id, True)
# Populate the slot list cache: the current computed name matches.
calls = async_mock_service(hass, "light", "turn_on")
result = await conversation.async_converse(
hass, "turn on Kitchen Light", None, Context(), None
)
assert result.response.response_type is intent.IntentResponseType.ACTION_DONE
assert len(calls) == 1
# Renaming the device changes the light's computed name to "Bedroom Light".
device_registry.async_update_device(device.id, name_by_user="Bedroom")
await hass.async_block_till_done()
# The new name is now matchable.
calls = async_mock_service(hass, "light", "turn_on")
result = await conversation.async_converse(
hass, "turn on Bedroom Light", None, Context(), None
)
assert result.response.response_type is intent.IntentResponseType.ACTION_DONE
assert len(calls) == 1
@pytest.mark.usefixtures("init_components")
async def test_trigger_sentences(hass: HomeAssistant) -> None:
"""Test registering/unregistering/matching a few trigger sentences."""