Use LLM fallback when local matching matches intent but not targets (#136045)
LLM fallback to be used when local matching matches intent but finds no targetspull/136054/head
parent
53ad02a1eb
commit
85f10cf60a
|
@ -1350,14 +1350,25 @@ class DefaultAgent(ConversationEntity):
|
||||||
"""Try to match sentence against registered intents and return response.
|
"""Try to match sentence against registered intents and return response.
|
||||||
|
|
||||||
Only performs strict matching with exposed entities and exact wording.
|
Only performs strict matching with exposed entities and exact wording.
|
||||||
Returns None if no match occurred.
|
Returns None if no match or a matching error occurred.
|
||||||
"""
|
"""
|
||||||
result = await self.async_recognize_intent(user_input, strict_intents_only=True)
|
result = await self.async_recognize_intent(user_input, strict_intents_only=True)
|
||||||
if not isinstance(result, RecognizeResult):
|
if not isinstance(result, RecognizeResult):
|
||||||
# No error message on failed match
|
# No error message on failed match
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return await self._async_process_intent_result(result, user_input)
|
response = await self._async_process_intent_result(result, user_input)
|
||||||
|
if (
|
||||||
|
response.response_type == intent.IntentResponseType.ERROR
|
||||||
|
and response.error_code
|
||||||
|
not in (
|
||||||
|
intent.IntentResponseErrorCode.FAILED_TO_HANDLE,
|
||||||
|
intent.IntentResponseErrorCode.UNKNOWN,
|
||||||
|
)
|
||||||
|
):
|
||||||
|
# We ignore no matching errors
|
||||||
|
return None
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def _make_error_result(
|
def _make_error_result(
|
||||||
|
|
|
@ -3104,3 +3104,51 @@ async def test_turn_on_off(
|
||||||
)
|
)
|
||||||
assert len(off_calls) == 1
|
assert len(off_calls) == 1
|
||||||
assert off_calls[0].data.get("entity_id") == [entity_id]
|
assert off_calls[0].data.get("entity_id") == [entity_id]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("error_code", "return_response"),
|
||||||
|
[
|
||||||
|
(intent.IntentResponseErrorCode.NO_INTENT_MATCH, False),
|
||||||
|
(intent.IntentResponseErrorCode.NO_VALID_TARGETS, False),
|
||||||
|
(intent.IntentResponseErrorCode.FAILED_TO_HANDLE, True),
|
||||||
|
(intent.IntentResponseErrorCode.UNKNOWN, True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.usefixtures("init_components")
|
||||||
|
async def test_handle_intents_with_response_errors(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
init_components: None,
|
||||||
|
area_registry: ar.AreaRegistry,
|
||||||
|
error_code: intent.IntentResponseErrorCode,
|
||||||
|
return_response: bool,
|
||||||
|
) -> None:
|
||||||
|
"""Test that handle_intents does not return response errors."""
|
||||||
|
assert await async_setup_component(hass, "climate", {})
|
||||||
|
area_registry.async_create("living room")
|
||||||
|
|
||||||
|
agent: default_agent.DefaultAgent = hass.data[DATA_DEFAULT_ENTITY]
|
||||||
|
|
||||||
|
user_input = ConversationInput(
|
||||||
|
text="What is the temperature in the living room?",
|
||||||
|
context=Context(),
|
||||||
|
conversation_id=None,
|
||||||
|
device_id=None,
|
||||||
|
language=hass.config.language,
|
||||||
|
agent_id=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.conversation.default_agent.DefaultAgent._async_process_intent_result",
|
||||||
|
return_value=default_agent._make_error_result(
|
||||||
|
user_input.language, error_code, "Mock error message"
|
||||||
|
),
|
||||||
|
) as mock_process:
|
||||||
|
response = await agent.async_handle_intents(user_input)
|
||||||
|
|
||||||
|
assert len(mock_process.mock_calls) == 1
|
||||||
|
|
||||||
|
if return_response:
|
||||||
|
assert response is not None and response.error_code == error_code
|
||||||
|
else:
|
||||||
|
assert response is None
|
||||||
|
|
Loading…
Reference in New Issue