Fix thread-unsafe state writes; use conversation-agent dropdown
- entity.py: decorate the dispatcher target _handle_update with @callback so it runs on the event loop. Without it, async_dispatcher_send offloaded the plain sync callback to an executor thread, and async_write_ha_state raised "calls async_write_ha_state from a thread other than the event loop". - config_flow.py: replace the free-text Assist agent field with ConversationAgentSelector (a proper agent dropdown), and use LanguageSelector for the language field. - README: clarify that the built-in Assist agent only handles device commands; an LLM conversation agent is required for free-form chat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -95,8 +95,12 @@ will answer.
|
||||
### Options (⚙ → Configure)
|
||||
|
||||
- **Route incoming messages to Assist** – turn the chat bridge on/off.
|
||||
- **Assist agent / language** – pick a specific conversation agent, or leave
|
||||
blank for the default pipeline.
|
||||
- **Assist agent / language** – pick the conversation agent from the dropdown.
|
||||
> **Want free-form chat?** The default *Home Assistant* agent only recognises
|
||||
> device-control commands and will answer anything else with "Sorry, I
|
||||
> couldn't understand that". To actually chat, install an LLM conversation
|
||||
> integration (OpenAI, Google Generative AI, Anthropic, Ollama, …), then
|
||||
> select that agent here.
|
||||
- **Reply to any sender** / **Allowed sender addresses** – restrict who Assist
|
||||
will answer.
|
||||
- **Default recipient** – address used by the `notify.reticulum` entity.
|
||||
|
||||
@@ -17,6 +17,10 @@ from homeassistant.core import callback
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.selector import (
|
||||
BooleanSelector,
|
||||
ConversationAgentSelector,
|
||||
ConversationAgentSelectorConfig,
|
||||
LanguageSelector,
|
||||
LanguageSelectorConfig,
|
||||
NumberSelector,
|
||||
NumberSelectorConfig,
|
||||
NumberSelectorMode,
|
||||
@@ -170,16 +174,14 @@ class ReticulumOptionsFlow(OptionsFlow):
|
||||
): BooleanSelector(),
|
||||
vol.Optional(
|
||||
CONF_ASSIST_AGENT,
|
||||
description={
|
||||
"suggested_value": opts.get(CONF_ASSIST_AGENT, "")
|
||||
},
|
||||
): TextSelector(),
|
||||
description={"suggested_value": opts.get(CONF_ASSIST_AGENT)},
|
||||
): ConversationAgentSelector(ConversationAgentSelectorConfig()),
|
||||
vol.Optional(
|
||||
CONF_ASSIST_LANGUAGE,
|
||||
description={
|
||||
"suggested_value": opts.get(CONF_ASSIST_LANGUAGE, "")
|
||||
"suggested_value": opts.get(CONF_ASSIST_LANGUAGE)
|
||||
},
|
||||
): TextSelector(),
|
||||
): LanguageSelector(LanguageSelectorConfig()),
|
||||
vol.Required(
|
||||
CONF_ALLOW_ALL, default=opts.get(CONF_ALLOW_ALL, True)
|
||||
): BooleanSelector(),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
|
||||
@@ -35,5 +36,9 @@ class ReticulumEntity(Entity):
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def _handle_update(self) -> None:
|
||||
# Decorated with @callback so the dispatcher runs it on the event loop
|
||||
# (a plain sync callback would be offloaded to an executor thread, and
|
||||
# async_write_ha_state is not thread-safe).
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"loggers": ["RNS", "LXMF"],
|
||||
"requirements": ["rns>=0.9.0", "lxmf>=0.6.0"],
|
||||
"single_config_entry": true,
|
||||
"version": "1.0.3"
|
||||
"version": "1.0.4"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user