1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-12 17:18:04 +01:00
Files
core/tests/components/script/test_llm.py
T
2026-07-10 07:08:57 +02:00

107 lines
4.2 KiB
Python

"""Tests for the script 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.components.script import llm as script_llm
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import entity_registry as er, llm
from homeassistant.setup import async_setup_component
ENTITY_ID = "script.test_script"
@pytest.fixture(autouse=True)
async def setup_integrations(hass: HomeAssistant) -> None:
"""Set up the integrations and expose a script."""
assert await async_setup_component(hass, "homeassistant", {})
assert await async_setup_component(hass, "intent", {})
assert await async_setup_component(hass, "llm", {})
assert await async_setup_component(
hass,
"script",
{
"script": {
"test_script": {
"alias": "test script",
"description": "This is a test script",
"sequence": [
{"variables": {"result": {"drinks": 2}}},
{"stop": True, "response_variable": "result"},
],
"fields": {
"beer": {"description": "Number of beers", "required": True},
},
},
"unexposed_script": {"sequence": []},
"123456": {"sequence": []},
}
},
)
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 test_script_tool_only_exposed(hass: HomeAssistant) -> None:
"""Test only exposed scripts get a tool."""
result = await llm_component.async_get_tools(hass, _llm_context(), "assist")
names = [tool.name for tool in result.tools]
assert "test_script" in names
assert "unexposed_script" not in names
async def test_script_tool_not_exposed(hass: HomeAssistant) -> None:
"""Test no script tool is offered when the script is not exposed."""
async_expose_entity(hass, "conversation", ENTITY_ID, False)
result = await llm_component.async_get_tools(hass, _llm_context(), "assist")
assert "test_script" not in [tool.name for tool in result.tools]
assert script_llm.async_get_tools(hass, _llm_context(), "assist") is None
async def test_no_tools_for_other_api(hass: HomeAssistant) -> None:
"""Test the platform returns None for an unsupported API."""
assert script_llm.async_get_tools(hass, _llm_context(), "other") is None
async def test_script_tool_call(hass: HomeAssistant) -> None:
"""Test calling the exposed script through its tool."""
llm_context = _llm_context()
result = await llm_component.async_get_tools(hass, llm_context, "assist")
tool = next(tool for tool in result.tools if tool.name == "test_script")
response = await tool.async_call(
hass, llm.ToolInput("test_script", {"beer": 1}), llm_context
)
assert response == {"success": True, "result": {"drinks": 2}}
async def test_script_tool_name_not_started_with_digit(hass: HomeAssistant) -> None:
"""Test a script whose id starts with a digit gets a valid tool name."""
async_expose_entity(hass, "conversation", "script.123456", True)
result = await llm_component.async_get_tools(hass, _llm_context(), "assist")
assert "_123456" in [tool.name for tool in result.tools]
async def test_script_tool_description_includes_aliases(
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
"""Test the script tool description is extended with the entity aliases."""
entity_registry.async_update_entity(ENTITY_ID, aliases=["barkeep", "pour a drink"])
result = await llm_component.async_get_tools(hass, _llm_context(), "assist")
tool = next(tool for tool in result.tools if tool.name == "test_script")
assert tool.description == (
"This is a test script. Aliases: ['barkeep', 'pour a drink']"
)