fix: clean up description escaping, add string-data tests

Follow-up for cherry-picked PR #8918.
This commit is contained in:
Teknium 2026-04-13 04:44:43 -07:00 committed by Teknium
parent bca22f3090
commit 8dfee98d06
2 changed files with 59 additions and 4 deletions

View file

@ -5,6 +5,7 @@ handler validation, and availability gating.
"""
import json
from unittest.mock import patch
import pytest
@ -304,6 +305,60 @@ class TestEntityIdValidation:
assert "Invalid entity_id" not in result["error"]
# ---------------------------------------------------------------------------
# String-data deserialization (XML tool calling workaround)
# ---------------------------------------------------------------------------
class TestCallServiceStringData:
"""data param may arrive as a JSON string (XML tool calling mode)."""
@patch("tools.homeassistant_tool._run_async", return_value={"success": True})
def test_string_data_deserialized(self, mock_run):
"""JSON string data is parsed into a dict before dispatch."""
_handle_call_service({
"domain": "climate",
"service": "set_hvac_mode",
"entity_id": "climate.living_room",
"data": '{"hvac_mode": "heat"}',
})
call_args = mock_run.call_args[0][0] # the coroutine arg
# _run_async was called, meaning we got past validation
@patch("tools.homeassistant_tool._run_async", return_value={"success": True})
def test_dict_data_passthrough(self, mock_run):
"""Dict data (JSON tool calling mode) still works unchanged."""
_handle_call_service({
"domain": "light",
"service": "turn_on",
"entity_id": "light.bedroom",
"data": {"brightness": 255},
})
mock_run.assert_called_once()
def test_invalid_json_string_returns_error(self):
"""Malformed JSON string in data returns a clear error."""
result = json.loads(_handle_call_service({
"domain": "light",
"service": "turn_on",
"entity_id": "light.bedroom",
"data": "{not valid json}",
}))
assert "error" in result
assert "Invalid JSON" in result["error"]
@patch("tools.homeassistant_tool._run_async", return_value={"success": True})
def test_empty_string_data_becomes_none(self, mock_run):
"""Empty/whitespace string data is treated as None."""
_handle_call_service({
"domain": "light",
"service": "turn_on",
"entity_id": "light.bedroom",
"data": " ",
})
mock_run.assert_called_once()
# ---------------------------------------------------------------------------
# Security: domain/service name format validation
# ---------------------------------------------------------------------------

View file

@ -458,10 +458,10 @@ HA_CALL_SERVICE_SCHEMA = {
"data": {
"type": "string",
"description": (
"Additional service data provided as a valid JSON string. Examples: "
'\'{"brightness": 255, "color_name": "blue"}\' for lights, '
'\'{"temperature": 22, "hvac_mode": "heat"}\' for climate, '
'\'{"volume_level": 0.5}\' for media players.'
"Additional service data as a JSON string. Examples: "
'{"brightness": 255, "color_name": "blue"} for lights, '
'{"temperature": 22, "hvac_mode": "heat"} for climate, '
'{"volume_level": 0.5} for media players.'
),
},
},