From 91e6bc5cba1f0be546837727ef5ae8371fb3265c Mon Sep 17 00:00:00 2001 From: mkzung <103102868+mkzung@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:52:53 +0500 Subject: [PATCH] fix(a2a): don't claim sampling params the protocol has no field for get_supported_openai_params listed temperature, max_tokens and top_p. map_openai_params only ever reads stream, and transform_request builds a JSON-RPC body of just {message}, so the three values went nowhere. A2A has no sampling controls by design: SendMessageConfiguration is acceptedOutputModes, taskPushNotificationConfig, historyLength and returnImmediately, because the remote agent owns its own model config. Advertising them suppressed the UnsupportedParamsError and dropped them in silence. stream stays, it selects message/stream over message/send. --- litellm/llms/a2a/chat/transformation.py | 12 ++++++--- tests/llm_translation/test_a2a.py | 35 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/litellm/llms/a2a/chat/transformation.py b/litellm/llms/a2a/chat/transformation.py index 3de584d1d5f..778f6c5324e 100644 --- a/litellm/llms/a2a/chat/transformation.py +++ b/litellm/llms/a2a/chat/transformation.py @@ -91,12 +91,16 @@ class A2AConfig(BaseConfig): return api_base, api_key, headers def get_supported_openai_params(self, model: str) -> list[str]: - """Return list of supported OpenAI parameters""" + """Return list of supported OpenAI parameters. + + A2A has no sampling controls. SendMessageConfiguration carries + acceptedOutputModes, taskPushNotificationConfig, historyLength and + returnImmediately, nothing else, because the remote agent owns its own + model config. Only stream is real here: it picks message/stream over + message/send. + """ return [ "stream", - "temperature", - "max_tokens", - "top_p", ] def map_openai_params( diff --git a/tests/llm_translation/test_a2a.py b/tests/llm_translation/test_a2a.py index ec260acd1ae..df77db5b292 100644 --- a/tests/llm_translation/test_a2a.py +++ b/tests/llm_translation/test_a2a.py @@ -130,3 +130,38 @@ def test_a2a_completion_sync_streaming(): pytest.skip(f"A2A agent not reachable at {api_base}: {e}") except Exception as e: pytest.fail(f"Error occurred: {e}") + + +def test_a2a_only_claims_stream(): + """A2A has no sampling params, so it must not advertise any. + + Claiming one suppresses the UnsupportedParamsError and the value is + dropped without telling the caller. + """ + from litellm.llms.a2a.chat.transformation import A2AConfig + + supported = A2AConfig().get_supported_openai_params("test-agent") + assert "stream" in supported + for param in ("temperature", "max_tokens", "top_p"): + assert param not in supported + + +@pytest.mark.parametrize("param,value", [("temperature", 0.5), ("max_tokens", 100), ("top_p", 0.9)]) +def test_a2a_sampling_params_raise(param, value): + """Sampling params should surface an error rather than vanish.""" + from litellm.utils import get_optional_params + + with pytest.raises(litellm.UnsupportedParamsError): + get_optional_params( + model="test-agent", custom_llm_provider="a2a", **{param: value} + ) + + +def test_a2a_stream_still_maps(): + """stream is the one real param, it must survive.""" + from litellm.utils import get_optional_params + + params = get_optional_params( + model="test-agent", custom_llm_provider="a2a", stream=True + ) + assert params["stream"] is True