import json import pytest from aioresponses import aioresponses from hass.errors import HomeAssistantAuthError from hass.ha_client import HomeAssistantClient from hass.memory import ConversationMemory from hass.typing import HomeAssistantConfig @pytest.mark.asyncio async def test_process_text_updates_conversation_id(tmp_path): state_path = tmp_path / "state.json" memory = ConversationMemory(str(state_path)) await memory.load() config = HomeAssistantConfig( url="http://ha.local:8123", access_token="token", assistant_entity_id="home_assistant", language="zh-cn", timeout_seconds=2.5, ) client = HomeAssistantClient(config, memory, concurrency=2) await client.start() url = "http://ha.local:8123/api/conversation/process" with aioresponses() as mocked: mocked.post( url, payload={ "continue_conversation": True, "conversation_id": "cid-1", "response": { "response_type": "action_done", "speech": {"plain": {"speech": "好的"}}, }, }, status=200, ) reply = await client.process_text("打开客厅灯") assert reply.speech == "好的" assert reply.continue_conversation is True assert memory.conversation_id == "cid-1" await client.close() @pytest.mark.asyncio async def test_process_text_unauthorized(tmp_path): memory = ConversationMemory(str(tmp_path / "state.json")) await memory.load() config = HomeAssistantConfig(url="http://ha.local:8123", access_token="bad-token") client = HomeAssistantClient(config, memory) await client.start() url = "http://ha.local:8123/api/conversation/process" with aioresponses() as mocked: mocked.post(url, payload={"message": "unauthorized"}, status=401) with pytest.raises(HomeAssistantAuthError): await client.process_text("hi") await client.close() @pytest.mark.asyncio async def test_process_text_with_prefix_prompt(tmp_path): memory = ConversationMemory(str(tmp_path / "state.json")) await memory.load() config = HomeAssistantConfig(url="http://ha.local:8123", access_token="token") client = HomeAssistantClient(config, memory) await client.start() url = "http://ha.local:8123/api/conversation/process" with aioresponses() as mocked: mocked.post( url, payload={ "continue_conversation": False, "conversation_id": "cid-2", "response": { "response_type": "query_answer", "speech": {"plain": {"speech": "在客厅"}}, }, }, status=200, ) await client.process_text( "灯开了吗", prefix_prompt="当前用户对话所在区域:客厅,如后续对话未明确指定区域,则默认为此区域", ) request = mocked.requests[("POST", url)][0] payload = json.loads(request.kwargs["data"].decode("utf-8")) assert payload["text"].startswith("当前用户对话所在区域:客厅") assert "用户请求:灯开了吗" in payload["text"] await client.close() @pytest.mark.asyncio async def test_reset_conversation(tmp_path): state_path = tmp_path / "state.json" memory = ConversationMemory(str(state_path)) await memory.load() memory.conversation_id = "cid-old" await memory.save() config = HomeAssistantConfig(url="http://ha.local:8123", access_token="token") client = HomeAssistantClient(config, memory) await client.start() await client.reset_conversation() assert memory.conversation_id is None saved = json.loads(state_path.read_text(encoding="utf-8")) assert saved["conversation_id"] is None await client.close()