From 3c49717915cb1eceabbd95af3782413817ef8d48 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 21 Sep 2026 12:35:11 -0400 Subject: [PATCH] Set tool metadata in light (#182705) Co-authored-by: Claude --- homeassistant/components/light/llm.py | 24 +++++++++++++++++++++--- tests/components/light/test_llm.py | 9 ++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/light/llm.py b/homeassistant/components/light/llm.py index 17df38c98e96..4fce9f00e7c5 100644 --- a/homeassistant/components/light/llm.py +++ b/homeassistant/components/light/llm.py @@ -4,13 +4,25 @@ from homeassistant.components.homeassistant import async_should_expose from homeassistant.components.llm import LLMTools from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import intent -from homeassistant.helpers.llm import LLM_API_ASSIST, IntentTool, LLMContext, Tool +from homeassistant.helpers.llm import ( + LLM_API_ASSIST, + IntentTool, + LLMContext, + Tool, + ToolAnnotations, +) from .const import DOMAIN from .intent import INTENT_SET +# Each intent sets a value on the user's own entities, so calling one again +# with the same arguments has no further effect. +LLM_ANNOTATIONS = ToolAnnotations(idempotent=True, open_world=False) + # Intents owned by this integration that are exposed as LLM tools. -LLM_INTENTS = (INTENT_SET,) +LLM_INTENTS = { + INTENT_SET: "Set light", +} @callback @@ -31,7 +43,13 @@ def async_get_tools( return None tools: list[Tool] = [ - IntentTool(f"{DOMAIN}__{handler.intent_type}", handler) + IntentTool( + f"{DOMAIN}__{handler.intent_type}", + handler, + title=LLM_INTENTS[handler.intent_type], + integration=DOMAIN, + annotations=LLM_ANNOTATIONS, + ) for handler in intent.async_get(hass) if handler.intent_type in LLM_INTENTS ] diff --git a/tests/components/light/test_llm.py b/tests/components/light/test_llm.py index 3352e278260e..d6f282da7830 100644 --- a/tests/components/light/test_llm.py +++ b/tests/components/light/test_llm.py @@ -43,7 +43,14 @@ async def _tool_names(hass: HomeAssistant) -> set[str]: async def test_intent_tool_exposed(hass: HomeAssistant) -> None: """Test the intent tool is offered for an exposed light entity.""" - assert "light__HassLightSet" in await _tool_names(hass) + result = await llm_component.async_get_tools(hass, _llm_context(), "assist") + tools = {tool.name: tool for tool in result.tools} + assert "light__HassLightSet" in tools + + tool = tools["light__HassLightSet"] + assert tool.title == "Set light" + assert tool.integration == "light" + assert tool.annotations == llm.ToolAnnotations(idempotent=True, open_world=False) async def test_intent_tool_not_exposed(hass: HomeAssistant) -> None: