From 9f5f52057692255fd32e197d87eee599a4424699 Mon Sep 17 00:00:00 2001 From: Sakura-RanChen <1908198662@qq.com> Date: Thu, 5 Nov 2026 15:36:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dha=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../providers/intent/intent_llm/intent_llm.py | 14 ++--- .../plugins_func/functions/hass_init.py | 52 +++++++++++-------- .../tests/plugins_func/test_hass_init.py | 8 +++ 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py b/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py index cd150bc59..1dd5bb172 100644 --- a/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py +++ b/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py @@ -5,6 +5,7 @@ if TYPE_CHECKING: from core.connection import ConnectionHandler from ..base import IntentProviderBase from plugins_func.functions.play_music import initialize_music_handler +from plugins_func.functions.hass_init import _devices_text, _hass_plugin_config from config.logger import setup_logging from core.utils.util import get_system_error_response import re @@ -181,16 +182,11 @@ class IntentProvider(IntentProviderBase): music_file_names = music_config["music_file_names"] prompt_music = f"{self.promot}\n{music_file_names}\n" - home_assistant_cfg = conn.config["plugins"].get("home_assistant") - if home_assistant_cfg: - devices = home_assistant_cfg.get("devices", []) - else: - devices = [] - if len(devices) > 0: + plugin_config = _hass_plugin_config(conn.config.get("plugins", {})) + devices_text = _devices_text(plugin_config.get("devices", "")) + if devices_text: hass_prompt = "\n下面是我家智能设备列表(位置,设备名,entity_id),可以通过homeassistant控制\n" - for device in devices: - hass_prompt += device + "\n" - prompt_music += hass_prompt + prompt_music += hass_prompt + devices_text + "\n" logger.bind(tag=TAG).debug(f"User prompt: {prompt_music}") diff --git a/main/xiaozhi-server/plugins_func/functions/hass_init.py b/main/xiaozhi-server/plugins_func/functions/hass_init.py index 2487b5ee7..2a0c2edd4 100644 --- a/main/xiaozhi-server/plugins_func/functions/hass_init.py +++ b/main/xiaozhi-server/plugins_func/functions/hass_init.py @@ -1,10 +1,19 @@ from config.logger import setup_logging from core.utils.util import check_model_key +from plugins_func.register import module_func_map TAG = __name__ logger = setup_logging() +def _expand_module_names(funcs): + """把 functions 列表里的模块名(如 hass_state)展开成具体函数名,与工具加载口径一致。""" + expanded = [] + for name in funcs: + expanded.extend(module_func_map.get(name, [name])) + return expanded + + def _devices_text(devices) -> str: """把 devices 配置转成拼进提示词的文字。 @@ -12,29 +21,33 @@ def _devices_text(devices) -> str: 网页端智控台和 HA 集成文档是一段字符串,原样用;其它(如 None)当空。 """ if isinstance(devices, (list, tuple)): - return "\n".join(str(d).strip() for d in devices if str(d).strip()) + return "\n".join( + str(d).strip() for d in devices if d is not None and str(d).strip() + ) return devices if isinstance(devices, str) else "" +def _hass_plugin_config(plugins_config: dict) -> dict: + """取 HA 插件配置:优先本地 config.yaml 的 home_assistant,其次智控台下发的 hass_state。""" + for key in ("home_assistant", "hass_state"): + cfg = plugins_config.get(key) + if cfg: + return cfg + return {} + + def append_devices_to_prompt(conn): if conn.intent_type == "function_call": - funcs = conn.config["Intent"][conn.config["selected_module"]["Intent"]].get( - "functions", [] - ) - - # 安全地获取插件配置 - plugins_config = conn.config.get("plugins", {}) - config_source = ( - "home_assistant" - if plugins_config.get("home_assistant") - else "hass_state" + funcs = _expand_module_names( + conn.config["Intent"][conn.config["selected_module"]["Intent"]].get( + "functions", [] + ) ) if "hass_get_state" in funcs or "hass_set_state" in funcs: prompt = "\n下面是我家智能设备列表(位置,设备名,entity_id),可以通过homeassistant控制\n" - deviceStr = _devices_text( - plugins_config.get(config_source, {}).get("devices", "") - ) + plugin_config = _hass_plugin_config(conn.config.get("plugins", {})) + deviceStr = _devices_text(plugin_config.get("devices", "")) conn.prompt += prompt + deviceStr + "\n" # 更新提示词 conn.dialogue.update_system_message(conn.prompt) @@ -45,17 +58,10 @@ def initialize_hass_handler(conn): if not conn.load_function_plugin: return ha_config - # 安全地获取插件配置 - plugins_config = conn.config.get("plugins", {}) - # 确定配置来源 - config_source = ( - "home_assistant" if plugins_config.get("home_assistant") else "hass_state" - ) - if not plugins_config.get(config_source): + plugin_config = _hass_plugin_config(conn.config.get("plugins", {})) + if not plugin_config: return ha_config - # 统一获取配置 - plugin_config = plugins_config[config_source] ha_config["base_url"] = plugin_config.get("base_url") ha_config["api_key"] = plugin_config.get("api_key") diff --git a/main/xiaozhi-server/tests/plugins_func/test_hass_init.py b/main/xiaozhi-server/tests/plugins_func/test_hass_init.py index 49b5b2989..4e2ee69e9 100644 --- a/main/xiaozhi-server/tests/plugins_func/test_hass_init.py +++ b/main/xiaozhi-server/tests/plugins_func/test_hass_init.py @@ -5,6 +5,7 @@ can only concatenate str (not "list") to str,设备清单进不了提示词, """ import pytest +import plugins_func.functions.hass_state # noqa: F401 注册 hass_state 模块,填充 module_func_map from plugins_func.functions.hass_init import append_devices_to_prompt HEADER = "\n下面是我家智能设备列表(位置,设备名,entity_id),可以通过homeassistant控制\n" @@ -62,6 +63,13 @@ def test_mobile_console_hass_state_list(): assert conn.prompt.endswith(HEADER + "客厅,玩具灯,switch.toy_lamp\n") +def test_module_name_in_functions(): + # functions 里写模块名 hass_state(config.yaml 注释的写法),展开后应能匹配 + conn = FakeConn(_plugin(devices=["客厅,玩具灯,switch.toy_lamp"]), functions=("hass_state",)) + append_devices_to_prompt(conn) + assert conn.prompt.endswith(HEADER + "客厅,玩具灯,switch.toy_lamp\n") + + @pytest.mark.parametrize("plugin", [_plugin(), _plugin(devices=None), _plugin(devices=[])]) def test_missing_or_empty_devices_does_not_raise(plugin): conn = FakeConn(plugin)