From 3011431d41c850552ceb9f3edf3b9672ea22fc0c Mon Sep 17 00:00:00 2001 From: Vrajesh Sulakhe Date: Sat, 3 Oct 2026 06:32:22 +0530 Subject: [PATCH] fix(agentic): preserve cross-provider follow-up overrides --- litellm/litellm_core_utils/chat_completion_agentic_loop.py | 7 ++++++- litellm/llms/custom_httpx/llm_http_handler.py | 7 ++++++- tests/test_litellm/test_agentic_loop_prefix_44069.py | 7 ++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/litellm/litellm_core_utils/chat_completion_agentic_loop.py b/litellm/litellm_core_utils/chat_completion_agentic_loop.py index 2e842df4718..b9d03e0cc8a 100644 --- a/litellm/litellm_core_utils/chat_completion_agentic_loop.py +++ b/litellm/litellm_core_utils/chat_completion_agentic_loop.py @@ -171,7 +171,12 @@ async def _execute_chat_completion_agentic_plan( raise ValueError("Agentic loop plan missing patched messages") full_model_name = patch.model or model - if custom_llm_provider and not full_model_name.startswith(f"{custom_llm_provider}/"): + known_providers: Final = getattr(litellm, "provider_list", []) + has_provider_prefix: Final = ( + full_model_name.startswith(f"{custom_llm_provider}/") + or ("/" in full_model_name and full_model_name.split("/", 1)[0] in known_providers) + ) + if custom_llm_provider and not has_provider_prefix: full_model_name = f"{custom_llm_provider}/{full_model_name}" optional_params_for_followup: Final = {**optional_params, **patch.optional_params} diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index bfd60bb0f19..9377bdab6c3 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -5494,7 +5494,12 @@ class BaseLLMHTTPHandler: raise ValueError("Agentic loop plan missing patched messages") full_model_name = patch.model or model - if custom_llm_provider and not full_model_name.startswith(f"{custom_llm_provider}/"): + known_providers: Final = getattr(litellm, "provider_list", []) + has_provider_prefix: Final = ( + full_model_name.startswith(f"{custom_llm_provider}/") + or ("/" in full_model_name and full_model_name.split("/", 1)[0] in known_providers) + ) + if custom_llm_provider and not has_provider_prefix: full_model_name = f"{custom_llm_provider}/{full_model_name}" optional_params_for_followup: Final = dict(optional_params) diff --git a/tests/test_litellm/test_agentic_loop_prefix_44069.py b/tests/test_litellm/test_agentic_loop_prefix_44069.py index c3c5c7ddc7b..74c78f082cb 100644 --- a/tests/test_litellm/test_agentic_loop_prefix_44069.py +++ b/tests/test_litellm/test_agentic_loop_prefix_44069.py @@ -25,8 +25,9 @@ from litellm.types.utils import ModelResponse ("zai-org/GLM-5.3-Flash", "hosted_vllm", "hosted_vllm/zai-org/GLM-5.3-Flash"), ("hosted_vllm/zai-org/GLM-5.3-Flash", "hosted_vllm", "hosted_vllm/zai-org/GLM-5.3-Flash"), ("hosted_vllm/zai-org/GLM-5.3-Flash", "", "hosted_vllm/zai-org/GLM-5.3-Flash"), + ("openai/gpt-4o", "hosted_vllm", "openai/gpt-4o"), ), - ids=("organization-model", "already-prefixed", "no-provider"), + ids=("organization-model", "already-prefixed", "no-provider", "cross-provider"), ) async def test_agentic_followup_preserves_provider_prefix( execution_path: Literal["http", "sdk"], @@ -75,8 +76,8 @@ async def test_agentic_followup_preserves_provider_prefix( ) ) - assert isinstance(response, ModelResponse) - assert response.model == expected_model.removeprefix("hosted_vllm/") followup.assert_awaited_once() assert followup.await_args is not None assert followup.await_args.kwargs["model"] == expected_model + assert isinstance(response, ModelResponse) + assert response.model == expected_model.split("/", 1)[1]