Skip to content

Commit

Permalink
Ensure intent tools have safe names (#119144)
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob authored Jun 8, 2024
1 parent fff2c11 commit c49ca5e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
13 changes: 11 additions & 2 deletions homeassistant/helpers/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from functools import cache, partial
from typing import Any

import slugify as unicode_slug
import voluptuous as vol

from homeassistant.components.climate.intent import INTENT_GET_TEMPERATURE
Expand Down Expand Up @@ -175,10 +177,11 @@ class IntentTool(Tool):

def __init__(
self,
name: str,
intent_handler: intent.IntentHandler,
) -> None:
"""Init the class."""
self.name = intent_handler.intent_type
self.name = name
self.description = (
intent_handler.description or f"Execute Home Assistant {self.name} intent"
)
Expand Down Expand Up @@ -261,6 +264,9 @@ def __init__(self, hass: HomeAssistant) -> None:
id=LLM_API_ASSIST,
name="Assist",
)
self.cached_slugify = cache(
partial(unicode_slug.slugify, separator="_", lowercase=False)
)

async def async_get_api_instance(self, llm_context: LLMContext) -> APIInstance:
"""Return the instance of the API."""
Expand Down Expand Up @@ -373,7 +379,10 @@ def _async_get_tools(
or intent_handler.platforms & exposed_domains
]

return [IntentTool(intent_handler) for intent_handler in intent_handlers]
return [
IntentTool(self.cached_slugify(intent_handler.intent_type), intent_handler)
for intent_handler in intent_handlers
]


def _get_exposed_entities(
Expand Down
33 changes: 33 additions & 0 deletions tests/helpers/test_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,39 @@ async def test_assist_api_get_timer_tools(
assert "HassStartTimer" in [tool.name for tool in api.tools]


async def test_assist_api_tools(
hass: HomeAssistant, llm_context: llm.LLMContext
) -> None:
"""Test getting timer tools with Assist API."""
assert await async_setup_component(hass, "homeassistant", {})
assert await async_setup_component(hass, "intent", {})

llm_context.device_id = "test_device"

async_register_timer_handler(hass, "test_device", lambda *args: None)

class MyIntentHandler(intent.IntentHandler):
intent_type = "Super crazy intent with unique nåme"
description = "my intent handler"

intent.async_register(hass, MyIntentHandler())

api = await llm.async_get_api(hass, "assist", llm_context)
assert [tool.name for tool in api.tools] == [
"HassTurnOn",
"HassTurnOff",
"HassSetPosition",
"HassStartTimer",
"HassCancelTimer",
"HassIncreaseTimer",
"HassDecreaseTimer",
"HassPauseTimer",
"HassUnpauseTimer",
"HassTimerStatus",
"Super_crazy_intent_with_unique_name",
]


async def test_assist_api_description(
hass: HomeAssistant, llm_context: llm.LLMContext
) -> None:
Expand Down

0 comments on commit c49ca5e

Please sign in to comment.