From 098d554aaccd1b0705574e828e281e604921aa9a Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Mon, 20 Apr 2026 12:02:40 +0530 Subject: [PATCH] test: cover vision config temperature wiring\n\n- add regression tests for auxiliary.vision.temperature and timeout\n- add bugkill3r to AUTHOR_MAP for the salvaged commit --- scripts/release.py | 1 + tests/tools/test_vision_tools.py | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/scripts/release.py b/scripts/release.py index 4467ad610..a18dd564b 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -209,6 +209,7 @@ AUTHOR_MAP = { "kagura.chen28@gmail.com": "kagura-agent", "1342088860@qq.com": "youngDoo", "kamil@gwozdz.me": "kamil-gwozdz", + "skmishra1991@gmail.com": "bugkill3r", "karamusti912@gmail.com": "MustafaKara7", "kira@ariaki.me": "kira-ariaki", "knopki@duck.com": "knopki", diff --git a/tests/tools/test_vision_tools.py b/tests/tools/test_vision_tools.py index 8238f1158..d8977f849 100644 --- a/tests/tools/test_vision_tools.py +++ b/tests/tools/test_vision_tools.py @@ -366,6 +366,66 @@ class TestErrorLoggingExcInfo: assert warning_records[0].exc_info is not None +class TestVisionConfig: + @pytest.mark.asyncio + async def test_vision_uses_configured_temperature_and_timeout(self, tmp_path): + img = tmp_path / "test.png" + img.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 8) + + mock_response = MagicMock() + mock_choice = MagicMock() + mock_choice.message.content = "Configured image analysis" + mock_response.choices = [mock_choice] + + with ( + patch("hermes_cli.config.load_config", return_value={ + "auxiliary": {"vision": {"temperature": 1, "timeout": 77}} + }), + patch( + "tools.vision_tools._image_to_base64_data_url", + return_value="data:image/png;base64,abc", + ), + patch( + "tools.vision_tools.async_call_llm", + new_callable=AsyncMock, + return_value=mock_response, + ) as mock_llm, + ): + result = json.loads(await vision_analyze_tool(str(img), "describe this", "test/model")) + + assert result["success"] is True + assert mock_llm.await_args.kwargs["temperature"] == 1.0 + assert mock_llm.await_args.kwargs["timeout"] == 77.0 + + @pytest.mark.asyncio + async def test_vision_defaults_temperature_when_config_omits_it(self, tmp_path): + img = tmp_path / "test.png" + img.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 8) + + mock_response = MagicMock() + mock_choice = MagicMock() + mock_choice.message.content = "Default image analysis" + mock_response.choices = [mock_choice] + + with ( + patch("hermes_cli.config.load_config", return_value={"auxiliary": {"vision": {}}}), + patch( + "tools.vision_tools._image_to_base64_data_url", + return_value="data:image/png;base64,abc", + ), + patch( + "tools.vision_tools.async_call_llm", + new_callable=AsyncMock, + return_value=mock_response, + ) as mock_llm, + ): + result = json.loads(await vision_analyze_tool(str(img), "describe this", "test/model")) + + assert result["success"] is True + assert mock_llm.await_args.kwargs["temperature"] == 0.1 + assert mock_llm.await_args.kwargs["timeout"] == 120.0 + + class TestVisionSafetyGuards: @pytest.mark.asyncio async def test_local_non_image_file_rejected_before_llm_call(self, tmp_path):