Set tool metadata in vacuum (#182706)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Paulus Schoutsen
2026-09-24 21:26:51 +02:00
committed by GitHub
co-authored by Claude
parent 6f9bda36c3
commit 5dd48e2ca9
2 changed files with 42 additions and 8 deletions
+23 -7
View File
@@ -4,7 +4,13 @@ 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 (
@@ -13,12 +19,16 @@ from .intent import (
INTENT_VACUUM_START,
)
# Each intent dispatches a command to the user's own vacuum, and the command
# runs again on every call.
LLM_ANNOTATIONS = ToolAnnotations(open_world=False)
# Intents owned by this integration that are exposed as LLM tools.
LLM_INTENTS = (
INTENT_VACUUM_CLEAN_AREA,
INTENT_VACUUM_RETURN_TO_BASE,
INTENT_VACUUM_START,
)
LLM_INTENTS = {
INTENT_VACUUM_CLEAN_AREA: "Clean area",
INTENT_VACUUM_RETURN_TO_BASE: "Return vacuum to base",
INTENT_VACUUM_START: "Start vacuum",
}
@callback
@@ -39,7 +49,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
]
+19 -1
View File
@@ -48,7 +48,25 @@ 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 vacuum entity."""
assert await _tool_names(hass) >= TOOL_NAMES
result = await llm_component.async_get_tools(hass, _llm_context(), "assist")
tools = {tool.name: tool for tool in result.tools}
assert tools.keys() >= TOOL_NAMES
# A vacuum command runs again on every call, so none of these is idempotent.
annotations = llm.ToolAnnotations(open_world=False)
assert {
name: (tool.title, tool.integration, tool.annotations)
for name, tool in tools.items()
if name in TOOL_NAMES
} == {
"vacuum__HassVacuumCleanArea": ("Clean area", "vacuum", annotations),
"vacuum__HassVacuumReturnToBase": (
"Return vacuum to base",
"vacuum",
annotations,
),
"vacuum__HassVacuumStart": ("Start vacuum", "vacuum", annotations),
}
async def test_intent_tool_not_exposed(hass: HomeAssistant) -> None: