Skip to content

Commit

Permalink
Allow @llm_tool with @callback decorator to run in the same thread
Browse files Browse the repository at this point in the history
  • Loading branch information
Shulyaka committed Dec 19, 2024
1 parent eb86144 commit c28c5ae
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ There are two options:

* Extend the `custom_components.powerllm.PowerLLMTool` class to implement the functionality, then call `custom_components.powerllm.async_register_tool` to register the object of the class. See the [memory tool](https://github.com/Shulyaka/powerllm/blob/master/custom_components/powerllm/tools/memory.py) for an example

* Use the `custom_components.powerllm.llm_tool` decorator for any python function. The function is recommended to have type annotations for all parameters. If a parameter name is "hass", "llm_context", or any of the `homeassistant.helpers.llm.LLMContext` attributes, then the value for that parameter will be provided by the conversation agent ("pytest-style"). All other arguments will be provided by the LLM. Refer to the [python code tool](https://github.com/Shulyaka/powerllm/blob/master/custom_components/powerllm/tools/python_code.py) as an example. A synchronous function will be executed in a separate thread, while an async function will be run concurrently in the main event loop and therefore is not allowed to use any blocking operations.
* Use the `custom_components.powerllm.llm_tool` decorator for any python function. The function is recommended to have type annotations for all parameters. If a parameter name is "hass", "llm_context", or any of the `homeassistant.helpers.llm.LLMContext` attributes, then the value for that parameter will be provided by the conversation agent ("pytest-style"). All other arguments will be provided by the LLM. Refer to the [python code tool](https://github.com/Shulyaka/powerllm/blob/master/custom_components/powerllm/tools/python_code.py) as an example. A synchronous function should be declared as `@callback`, or it will be executed in a separate thread than the main hass loop, while an async function will be run concurrently in the main event loop and therefore is not allowed to use any blocking operations. If using both `@llm_tool` and `@callback`, `@llm_tool` should be the outer decorator.

The tools in this repository use various techniques for demonstration.

Expand Down
4 changes: 2 additions & 2 deletions custom_components/powerllm/llm_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from typing import Any, TypeVar, Union, get_args, get_origin, get_type_hints

import voluptuous as vol
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.core import HomeAssistant, State, callback, is_callback
from homeassistant.helpers import (
area_registry as ar,
device_registry as dr,
Expand Down Expand Up @@ -377,7 +377,7 @@ async def async_call(
if inspect.iscoroutinefunction(self.function):
return await self.function(**kwargs)

if hass.loop != asyncio.get_running_loop():
if is_callback(self.function) or hass.loop != asyncio.get_running_loop():
return self.function(**kwargs)

return await hass.loop.run_in_executor(None, lambda: self.function(**kwargs))
Expand Down

0 comments on commit c28c5ae

Please sign in to comment.