From 4a6ce24d97ff803007ff17e9d6e44c7322d7a1ee Mon Sep 17 00:00:00 2001 From: parisni Date: Thu, 14 May 2026 21:09:22 +0200 Subject: [PATCH] test(core_helpers): cover `client_metadata` filtering in `filter_internal_params` Add three regression tests next to the existing helper coverage: - `client_metadata` is removed from a representative Bedrock-style payload while every other field (model, messages, temperature, ...) is preserved. - The previously known internal markers (`skip_mcp_handler`, ...) are still filtered alongside `client_metadata` in the same call. - The `additional_internal_params` extension point keeps working when `client_metadata` is part of the default set. These tests pin the contract documented in the production fix so a future refactor of `filter_internal_params` cannot silently drop the Bedrock Converse compatibility behaviour. --- .../litellm_core_utils/test_core_helpers.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/test_litellm/litellm_core_utils/test_core_helpers.py b/tests/test_litellm/litellm_core_utils/test_core_helpers.py index b67ea91bb0b..22587405f84 100644 --- a/tests/test_litellm/litellm_core_utils/test_core_helpers.py +++ b/tests/test_litellm/litellm_core_utils/test_core_helpers.py @@ -4,6 +4,7 @@ import pytest from litellm.litellm_core_utils.core_helpers import ( _FINISH_REASON_MAP, + filter_internal_params, map_finish_reason, reconstruct_model_name, redact_nested_match_and_regex_keys, @@ -201,3 +202,64 @@ class TestRedactNestedMatchAndRegexKeys: def test_passes_through_none_and_str(self): assert redact_nested_match_and_regex_keys(None) is None assert redact_nested_match_and_regex_keys("plain") == "plain" + + +def test_filter_internal_params_strips_client_metadata(): + """``client_metadata`` must never leak into provider payloads. + + Bedrock Converse with custom application inference profiles rejects any + field in ``additionalModelRequestFields`` that the inference profile + does not whitelist. Some clients (OpenAI Codex CLI, Claude Code, ...) + send a ``client_metadata`` field for run-level telemetry; ``drop_params`` + does not cover it because it is not a known OpenAI param. Filtering it + here means every provider path sees the same sanitization. + """ + + data = { + "model": "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + "messages": [{"role": "user", "content": "hi"}], + "client_metadata": {"user_id": "u-123", "session_id": "s-456"}, + "temperature": 0.2, + } + + filtered = filter_internal_params(data) + + assert "client_metadata" not in filtered + # Other parameters must be preserved untouched. + assert filtered["model"] == data["model"] + assert filtered["messages"] == data["messages"] + assert filtered["temperature"] == data["temperature"] + + +def test_filter_internal_params_still_strips_known_internal_params(): + """Regression guard: previously known internal params keep being filtered.""" + + data = { + "skip_mcp_handler": True, + "_skip_mcp_handler": True, + "mcp_handler_context": {"foo": "bar"}, + "client_metadata": {"user_id": "u-1"}, + "temperature": 0.1, + } + + filtered = filter_internal_params(data) + + assert filtered == {"temperature": 0.1} + + +def test_filter_internal_params_supports_additional_internal_params(): + """The ``additional_internal_params`` extension point must keep working.""" + + data = { + "client_metadata": {"user_id": "u-1"}, + "extra_secret": "shhh", + "temperature": 0.1, + } + + filtered = filter_internal_params( + data, additional_internal_params={"extra_secret"} + ) + + assert "client_metadata" not in filtered + assert "extra_secret" not in filtered + assert filtered == {"temperature": 0.1}