mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 18:27:09 +00:00
Add entity deduplication by assist device ID in conversation agent (#123957)
* Add entities deduplication by assist device ID in default conversation agent * Updated test.
This commit is contained in:
parent
b4afca3e7e
commit
254aa8c9ea
@ -349,6 +349,9 @@ class DefaultAgent(ConversationEntity):
|
|||||||
}
|
}
|
||||||
for entity in result.entities_list
|
for entity in result.entities_list
|
||||||
}
|
}
|
||||||
|
device_area = self._get_device_area(user_input.device_id)
|
||||||
|
if device_area:
|
||||||
|
slots["preferred_area_id"] = {"value": device_area.id}
|
||||||
async_conversation_trace_append(
|
async_conversation_trace_append(
|
||||||
ConversationTraceEventType.TOOL_CALL,
|
ConversationTraceEventType.TOOL_CALL,
|
||||||
{
|
{
|
||||||
@ -917,18 +920,26 @@ class DefaultAgent(ConversationEntity):
|
|||||||
if not user_input.device_id:
|
if not user_input.device_id:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
devices = dr.async_get(self.hass)
|
device_area = self._get_device_area(user_input.device_id)
|
||||||
device = devices.async_get(user_input.device_id)
|
|
||||||
if (device is None) or (device.area_id is None):
|
|
||||||
return None
|
|
||||||
|
|
||||||
areas = ar.async_get(self.hass)
|
|
||||||
device_area = areas.async_get_area(device.area_id)
|
|
||||||
if device_area is None:
|
if device_area is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return {"area": {"value": device_area.name, "text": device_area.name}}
|
return {"area": {"value": device_area.name, "text": device_area.name}}
|
||||||
|
|
||||||
|
def _get_device_area(self, device_id: str | None) -> ar.AreaEntry | None:
|
||||||
|
"""Return area object for given device identifier."""
|
||||||
|
if device_id is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
devices = dr.async_get(self.hass)
|
||||||
|
device = devices.async_get(device_id)
|
||||||
|
if (device is None) or (device.area_id is None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
areas = ar.async_get(self.hass)
|
||||||
|
|
||||||
|
return areas.async_get_area(device.area_id)
|
||||||
|
|
||||||
def _get_error_text(
|
def _get_error_text(
|
||||||
self,
|
self,
|
||||||
error_key: ErrorKey | str,
|
error_key: ErrorKey | str,
|
||||||
|
@ -308,6 +308,72 @@ async def test_unexposed_entities_skipped(
|
|||||||
assert result.response.matched_states[0].entity_id == exposed_light.entity_id
|
assert result.response.matched_states[0].entity_id == exposed_light.entity_id
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("init_components")
|
||||||
|
async def test_duplicated_names_resolved_with_device_area(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
area_registry: ar.AreaRegistry,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test entities deduplication with device ID context."""
|
||||||
|
area_kitchen = area_registry.async_get_or_create("kitchen_id")
|
||||||
|
area_bedroom = area_registry.async_get_or_create("bedroom_id")
|
||||||
|
|
||||||
|
kitchen_light = entity_registry.async_get_or_create("light", "demo", "1234")
|
||||||
|
bedroom_light = entity_registry.async_get_or_create("light", "demo", "5678")
|
||||||
|
|
||||||
|
# Same name and alias
|
||||||
|
for light in (kitchen_light, bedroom_light):
|
||||||
|
light = entity_registry.async_update_entity(
|
||||||
|
light.entity_id,
|
||||||
|
name="top light",
|
||||||
|
aliases={"overhead light"},
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
light.entity_id,
|
||||||
|
"off",
|
||||||
|
attributes={ATTR_FRIENDLY_NAME: light.name},
|
||||||
|
)
|
||||||
|
# Different areas
|
||||||
|
kitchen_light = entity_registry.async_update_entity(
|
||||||
|
kitchen_light.entity_id,
|
||||||
|
area_id=area_kitchen.id,
|
||||||
|
)
|
||||||
|
bedroom_light = entity_registry.async_update_entity(
|
||||||
|
bedroom_light.entity_id,
|
||||||
|
area_id=area_bedroom.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pipeline device in bedroom area
|
||||||
|
entry = MockConfigEntry()
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
assist_device = device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
connections=set(),
|
||||||
|
identifiers={("demo", "id-1234")},
|
||||||
|
)
|
||||||
|
assist_device = device_registry.async_update_device(
|
||||||
|
assist_device.id,
|
||||||
|
area_id=area_bedroom.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check name and alias
|
||||||
|
for name in ("top light", "overhead light"):
|
||||||
|
# Only one light should be turned on
|
||||||
|
calls = async_mock_service(hass, "light", "turn_on")
|
||||||
|
result = await conversation.async_converse(
|
||||||
|
hass, f"turn on {name}", None, Context(), device_id=assist_device.id
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(calls) == 1
|
||||||
|
assert calls[0].data["entity_id"][0] == bedroom_light.entity_id
|
||||||
|
|
||||||
|
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
assert result.response.intent is not None
|
||||||
|
assert result.response.intent.slots.get("name", {}).get("value") == name
|
||||||
|
assert result.response.intent.slots.get("name", {}).get("text") == name
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("init_components")
|
@pytest.mark.usefixtures("init_components")
|
||||||
async def test_trigger_sentences(hass: HomeAssistant) -> None:
|
async def test_trigger_sentences(hass: HomeAssistant) -> None:
|
||||||
"""Test registering/unregistering/matching a few trigger sentences."""
|
"""Test registering/unregistering/matching a few trigger sentences."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user