fix(responses): stop agentic follow-up from passing request params twice

This commit is contained in:
Tejas Chopra 2026-09-16 21:27:45 -07:00
parent 821bcf5d78
commit bbee8692a8
2 changed files with 56 additions and 10 deletions

View file

@ -5573,17 +5573,19 @@ class BaseLLMHTTPHandler:
internal_keys: Final = {"litellm_logging_obj"}
kwargs_for_followup: Final = {
k: v
for k, v in kwargs.items()
if not is_interception_internal_key(k, prefixes=NON_CODE_INTERPRETER_INTERCEPTION_INTERNAL_PREFIXES)
and k != "_code_interpreter_interception_converted_stream"
and k not in internal_keys
and k not in optional_params
**{
k: v
for k, v in kwargs.items()
if not is_interception_internal_key(k, prefixes=NON_CODE_INTERPRETER_INTERCEPTION_INTERNAL_PREFIXES)
and k != "_code_interpreter_interception_converted_stream"
and k not in internal_keys
and k not in optional_params
},
**{k: v for k, v in patch.kwargs.items() if k not in optional_params},
"_agentic_loop_depth": depth + 1,
"max_agentic_loops": max_loops,
"_agentic_loop_fingerprints": fingerprints + [fingerprint],
}
kwargs_for_followup.update(patch.kwargs)
kwargs_for_followup["_agentic_loop_depth"] = depth + 1
kwargs_for_followup["max_agentic_loops"] = max_loops
kwargs_for_followup["_agentic_loop_fingerprints"] = fingerprints + [fingerprint]
try:
response: ResponsesAPIResponse | BaseResponsesAPIStreamingIterator = await litellm.aresponses(

View file

@ -3713,3 +3713,47 @@ def test_image_edit_handler_keeps_the_sync_transform():
assert config.transform_calls == ["sync"]
assert captured["body"] == {"transformed_by": "sync"}
assert response.data[0].b64_json == "sync"
@pytest.mark.asyncio
async def test_responses_agentic_followup_does_not_repeat_request_params_from_plan_kwargs(monkeypatch):
"""A plan whose kwargs repeat a request param must not crash the Responses follow-up with a duplicate keyword"""
from litellm.integrations.custom_logger import CustomLogger
from litellm.types.integrations.custom_logger import AgenticLoopPlan, AgenticLoopRequestPatch
followup_calls: list[dict[str, object]] = []
async def fake_aresponses(**kwargs: object) -> str:
followup_calls.append(kwargs)
return "followup-response"
monkeypatch.setattr(litellm, "aresponses", fake_aresponses)
request_kwargs: Final = {"prompt_cache_key": "thread-1", "metadata": {"user": "u1"}}
plan: Final = AgenticLoopPlan(
run_agentic_loop=True,
request_patch=AgenticLoopRequestPatch(
model="gpt-5",
messages=[{"role": "user", "content": "x"}],
optional_params={"prompt_cache_key": "thread-1"},
kwargs=dict(request_kwargs),
),
)
response: Final = await BaseLLMHTTPHandler()._execute_responses_agentic_plan(
plan=plan,
model="gpt-5",
response_api_optional_request_params={"prompt_cache_key": "thread-1"},
logging_obj=Mock(litellm_call_id="call-1"),
kwargs=dict(request_kwargs),
depth=0,
max_loops=3,
fingerprints=[],
fingerprint="fp",
callback=CustomLogger(),
)
assert response == "followup-response"
assert len(followup_calls) == 1
assert followup_calls[0]["prompt_cache_key"] == "thread-1"
assert followup_calls[0]["metadata"] == {"user": "u1"}
assert followup_calls[0]["_agentic_loop_depth"] == 1