From 01a577c4e69d5c3d3d026c8e61014d46d5d6750e Mon Sep 17 00:00:00 2001 From: Priyansh Nandwana Date: Sun, 30 Aug 2026 14:13:55 +0530 Subject: [PATCH] test(websearch): cover the agentic follow-up call site The helper had unit tests but the call site did not, so the two changed lines in _execute_chat_completion_agentic_plan were uncovered. Drive the real follow-up with mock_response instead of patching litellm, which keeps the test on the behaviour: against the old code the sub-path case raises "LLM Provider NOT provided", and the ordinary-model case passes either way as a guard. --- .../custom_httpx/test_llm_http_handler.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/unit/llms/custom_httpx/test_llm_http_handler.py b/tests/unit/llms/custom_httpx/test_llm_http_handler.py index 399e4dbf206..433cd467730 100644 --- a/tests/unit/llms/custom_httpx/test_llm_http_handler.py +++ b/tests/unit/llms/custom_httpx/test_llm_http_handler.py @@ -4302,3 +4302,51 @@ async def test_async_text_to_speech_handler_records_upstream_response_headers(): assert response.content == b"audio-bytes" _assert_upstream_headers_recorded(response) + + +class TestAgenticFollowUpKeepsTheProviderPrefix: + """#38829: the follow-up re-dispatched the provider-stripped model. For a provider that + routes through a sub-path the remainder still holds a slash, so the old + "a slash means already qualified" test dropped the prefix and the follow-up raised + "LLM Provider NOT provided".""" + + @staticmethod + def _plan(): + from litellm.types.integrations.custom_logger import ( + AgenticLoopPlan, + AgenticLoopRequestPatch, + ) + + return AgenticLoopPlan( + run_agentic_loop=True, + request_patch=AgenticLoopRequestPatch(messages=[{"role": "user", "content": "hi"}]), + ) + + async def _run_followup(self, model: str, custom_llm_provider: str): + from litellm.llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler + + return await BaseLLMHTTPHandler()._execute_chat_completion_agentic_plan( + plan=self._plan(), + model=model, + messages=[{"role": "user", "content": "hi"}], + optional_params={"mock_response": "ok from followup"}, + kwargs={}, + custom_llm_provider=custom_llm_provider, + depth=0, + max_loops=2, + fingerprints=[], + fingerprint="fp", + ) + + @pytest.mark.asyncio + async def test_a_sub_path_model_still_resolves_a_provider(self): + """bedrock/mantle/... reaches the handler as mantle/..., which alone is unroutable.""" + response = await self._run_followup("mantle/anthropic.claude-sonnet-5", "bedrock") + + assert response.choices[0].message.content == "ok from followup" + + @pytest.mark.asyncio + async def test_an_ordinary_model_still_resolves_a_provider(self): + response = await self._run_followup("gpt-4o-mini", "openai") + + assert response.choices[0].message.content == "ok from followup"