Files
ha-openai-compatible/tests/test_entity.py
T
pc-heiniandClaude Opus 5.5 235c536cab
validate / hassfest (push) Failing after 32s
validate / hacs (push) Failing after 1m50s
test / pytest (push) Successful in 3m56s
fix: make the integration work against a Claude proxy
- Treat an empty tool argument string as no parameters instead of raising
  JSONDecodeError; the proxy sends "" for tools like the timer status
  (upstream issue #3).
- Do not replay earlier web searches in the history. The chat log keeps only
  their status, and a search without results makes the model disown the
  answers it based on it and search again (upstream issue #4).
- Look up the home location for web search with the subentry's model instead
  of gpt-4o-mini, and save the options without city/region if the lookup
  fails (upstream issue #5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 08:38:01 +02:00

93 lines
2.9 KiB
Python

"""Tests for the fork's chat log conversion fixes in entity.py."""
from unittest.mock import MagicMock
from homeassistant.components import conversation
from homeassistant.helpers import llm
from custom_components.openai_compatible.entity import (
_convert_content_to_param,
_transform_stream,
)
from . import create_function_tool_call_item
async def _stream(events):
for event in events:
yield event
async def test_tool_call_without_arguments() -> None:
"""Test an empty argument string means a call without parameters.
Some OpenAI-compatible endpoints send "" instead of "{}" for tools that
take no parameters, e.g. the timer status intent.
"""
events = create_function_tool_call_item(
id="fc_1",
arguments=[],
call_id="call_1",
name="HassTimerStatus",
output_index=0,
)
deltas = [delta async for delta in _transform_stream(MagicMock(), _stream(events))]
tool_calls = [call for delta in deltas for call in delta.get("tool_calls", [])]
assert len(tool_calls) == 1
assert tool_calls[0].tool_name == "HassTimerStatus"
assert tool_calls[0].tool_args == {}
def test_web_search_not_replayed() -> None:
"""Test earlier web searches are left out of the history.
The chat log keeps only a search's status, not its results. Replaying the
bare search makes the model disown the answer it based on that search.
"""
content = [
conversation.UserContent(content="How did the match go?"),
conversation.AssistantContent(
agent_id="conversation.test",
tool_calls=[
llm.ToolInput(
id="ws_1",
tool_name="web_search_call",
tool_args={"action": {"type": "search", "query": "match"}},
external=True,
)
],
),
conversation.ToolResultContent(
agent_id="conversation.test",
tool_call_id="ws_1",
tool_name="web_search_call",
result=llm.ToolResult(data={"status": "completed"}),
),
conversation.AssistantContent(
agent_id="conversation.test",
content="It ended 2 to 2.",
tool_calls=[
llm.ToolInput(id="call_1", tool_name="GetLiveContext", tool_args={})
],
),
conversation.ToolResultContent(
agent_id="conversation.test",
tool_call_id="call_1",
tool_name="GetLiveContext",
result=llm.ToolResult(data={"success": True}),
),
]
messages = _convert_content_to_param(content)
assert [message["type"] for message in messages] == [
"message",
"message",
"function_call",
"function_call_output",
]
assert messages[1]["content"] == "It ended 2 to 2."
assert messages[2]["call_id"] == "call_1"