mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 10:13:52 -05:00
Add lawn_mower LLM tools platform (#175523)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
79ae3cd3d4
commit
f57701e32f
@@ -0,0 +1,33 @@
|
||||
"""LLM tools for the lawn_mower integration."""
|
||||
|
||||
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 IntentTool, LLMContext, Tool
|
||||
|
||||
from .const import DOMAIN
|
||||
from .intent import INTENT_LANW_MOWER_DOCK, INTENT_LANW_MOWER_START_MOWING
|
||||
|
||||
# Intents owned by this integration that are exposed as LLM tools.
|
||||
LLM_INTENTS = (INTENT_LANW_MOWER_DOCK, INTENT_LANW_MOWER_START_MOWING)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_tools(hass: HomeAssistant, llm_context: LLMContext) -> LLMTools:
|
||||
"""Return LLM tools for the integration's intents when its domain is exposed."""
|
||||
if not llm_context.assistant:
|
||||
return LLMTools(tools=[])
|
||||
|
||||
if not any(
|
||||
async_should_expose(hass, llm_context.assistant, state.entity_id)
|
||||
for state in hass.states.async_all(DOMAIN)
|
||||
):
|
||||
return LLMTools(tools=[])
|
||||
|
||||
tools: list[Tool] = [
|
||||
IntentTool(handler.intent_type, handler)
|
||||
for handler in intent.async_get(hass)
|
||||
if handler.intent_type in LLM_INTENTS
|
||||
]
|
||||
return LLMTools(tools=tools)
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Tests for the lawn_mower LLM tools platform."""
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import llm as llm_component
|
||||
from homeassistant.components.homeassistant.exposed_entities import async_expose_entity
|
||||
from homeassistant.core import Context, HomeAssistant
|
||||
from homeassistant.helpers import llm
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
ENTITY_ID = "lawn_mower.test"
|
||||
INTENTS = {"HassLawnMowerDock", "HassLawnMowerStartMowing"}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_integrations(hass: HomeAssistant) -> None:
|
||||
"""Set up the integrations and expose a lawn_mower entity."""
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
assert await async_setup_component(hass, "intent", {})
|
||||
assert await async_setup_component(hass, "lawn_mower", {})
|
||||
assert await async_setup_component(hass, "llm", {})
|
||||
hass.states.async_set(ENTITY_ID, "on", {"friendly_name": "Test lawn_mower"})
|
||||
async_expose_entity(hass, "conversation", ENTITY_ID, True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
def _llm_context() -> llm.LLMContext:
|
||||
"""Return an LLM context for the conversation assistant."""
|
||||
return llm.LLMContext(
|
||||
platform="test_platform",
|
||||
context=Context(),
|
||||
language="*",
|
||||
assistant="conversation",
|
||||
device_id=None,
|
||||
)
|
||||
|
||||
|
||||
async def _tool_names(hass: HomeAssistant) -> set[str]:
|
||||
"""Return the names of the tools offered by the lawn_mower platform."""
|
||||
result = await llm_component.async_get_tools(hass, _llm_context())
|
||||
return {tool.name for tool in result.tools}
|
||||
|
||||
|
||||
async def test_intent_tool_exposed(hass: HomeAssistant) -> None:
|
||||
"""Test the intent tool is offered for an exposed lawn_mower entity."""
|
||||
assert await _tool_names(hass) >= INTENTS
|
||||
|
||||
|
||||
async def test_intent_tool_not_exposed(hass: HomeAssistant) -> None:
|
||||
"""Test the intent tool is hidden when no lawn_mower entity is exposed."""
|
||||
async_expose_entity(hass, "conversation", ENTITY_ID, False)
|
||||
assert not INTENTS & await _tool_names(hass)
|
||||
Reference in New Issue
Block a user