From 5062a7fec8ec952387f10ba07e89a1045ee117c0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 9 Dec 2024 23:21:27 -0500 Subject: [PATCH] Add new api to fetch sentence triggers (#132764) * Add new api to fetch sentence triggers * With latest packages --- .../components/conversation/default_agent.py | 12 +++++----- homeassistant/components/conversation/http.py | 22 +++++++++++++++++++ .../conversation/snapshots/test_http.ambr | 8 +++++++ tests/components/conversation/test_http.py | 13 +++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/conversation/default_agent.py b/homeassistant/components/conversation/default_agent.py index 624fa3c3555305..66ffb25fa1a894 100644 --- a/homeassistant/components/conversation/default_agent.py +++ b/homeassistant/components/conversation/default_agent.py @@ -246,7 +246,7 @@ def __init__( self._unexposed_names_trie: Trie | None = None # Sentences that will trigger a callback (skipping intent recognition) - self._trigger_sentences: list[TriggerData] = [] + self.trigger_sentences: list[TriggerData] = [] self._trigger_intents: Intents | None = None self._unsub_clear_slot_list: list[Callable[[], None]] | None = None self._load_intents_lock = asyncio.Lock() @@ -1188,7 +1188,7 @@ def register_trigger( ) -> core.CALLBACK_TYPE: """Register a list of sentences that will trigger a callback when recognized.""" trigger_data = TriggerData(sentences=sentences, callback=callback) - self._trigger_sentences.append(trigger_data) + self.trigger_sentences.append(trigger_data) # Force rebuild on next use self._trigger_intents = None @@ -1205,7 +1205,7 @@ def _rebuild_trigger_intents(self) -> None: # This works because the intents are rebuilt on every # register/unregister. str(trigger_id): {"data": [{"sentences": trigger_data.sentences}]} - for trigger_id, trigger_data in enumerate(self._trigger_sentences) + for trigger_id, trigger_data in enumerate(self.trigger_sentences) }, } @@ -1228,7 +1228,7 @@ def _rebuild_trigger_intents(self) -> None: @core.callback def _unregister_trigger(self, trigger_data: TriggerData) -> None: """Unregister a set of trigger sentences.""" - self._trigger_sentences.remove(trigger_data) + self.trigger_sentences.remove(trigger_data) # Force rebuild on next use self._trigger_intents = None @@ -1241,7 +1241,7 @@ async def async_recognize_sentence_trigger( Calls the registered callbacks if there's a match and returns a sentence trigger result. """ - if not self._trigger_sentences: + if not self.trigger_sentences: # No triggers registered return None @@ -1286,7 +1286,7 @@ async def _handle_trigger_result( # Gather callback responses in parallel trigger_callbacks = [ - self._trigger_sentences[trigger_id].callback(user_input, trigger_result) + self.trigger_sentences[trigger_id].callback(user_input, trigger_result) for trigger_id, trigger_result in result.matched_triggers.items() ] diff --git a/homeassistant/components/conversation/http.py b/homeassistant/components/conversation/http.py index ebc5d70f1efef9..d9873c5cbce52e 100644 --- a/homeassistant/components/conversation/http.py +++ b/homeassistant/components/conversation/http.py @@ -36,6 +36,7 @@ def async_setup(hass: HomeAssistant) -> None: websocket_api.async_register_command(hass, websocket_process) websocket_api.async_register_command(hass, websocket_prepare) websocket_api.async_register_command(hass, websocket_list_agents) + websocket_api.async_register_command(hass, websocket_list_sentences) websocket_api.async_register_command(hass, websocket_hass_agent_debug) @@ -150,6 +151,27 @@ async def websocket_list_agents( connection.send_message(websocket_api.result_message(msg["id"], {"agents": agents})) +@websocket_api.websocket_command( + { + vol.Required("type"): "conversation/sentences/list", + } +) +@websocket_api.require_admin +@websocket_api.async_response +async def websocket_list_sentences( + hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict +) -> None: + """List custom registered sentences.""" + agent = hass.data.get(DATA_DEFAULT_ENTITY) + assert isinstance(agent, DefaultAgent) + + sentences = [] + for trigger_data in agent.trigger_sentences: + sentences.extend(trigger_data.sentences) + + connection.send_result(msg["id"], {"trigger_sentences": sentences}) + + @websocket_api.websocket_command( { vol.Required("type"): "conversation/agent/homeassistant/debug", diff --git a/tests/components/conversation/snapshots/test_http.ambr b/tests/components/conversation/snapshots/test_http.ambr index 8023d1ee6fa834..9cebfd9abd105e 100644 --- a/tests/components/conversation/snapshots/test_http.ambr +++ b/tests/components/conversation/snapshots/test_http.ambr @@ -693,6 +693,14 @@ }) # --- # name: test_ws_hass_agent_debug_sentence_trigger + dict({ + 'trigger_sentences': list([ + 'hello', + 'hello[ world]', + ]), + }) +# --- +# name: test_ws_hass_agent_debug_sentence_trigger.1 dict({ 'results': list([ dict({ diff --git a/tests/components/conversation/test_http.py b/tests/components/conversation/test_http.py index e792d8c6913bd8..6d69ec3c739765 100644 --- a/tests/components/conversation/test_http.py +++ b/tests/components/conversation/test_http.py @@ -501,6 +501,19 @@ async def test_ws_hass_agent_debug_sentence_trigger( client = await hass_ws_client(hass) + # List sentence + await client.send_json_auto_id( + { + "type": "conversation/sentences/list", + } + ) + await hass.async_block_till_done() + + msg = await client.receive_json() + + assert msg["success"] + assert msg["result"] == snapshot + # Use trigger sentence await client.send_json_auto_id( {