diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 4333b0afc16..b749ddf2562 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -211,7 +211,7 @@ general_settings: | pass_through_endpoints | List[Dict[str, Any]] | Define the pass through endpoints. [Docs](./pass_through) | | enable_oauth2_proxy_auth | boolean | (Enterprise Feature) If true, enables oauth2.0 authentication | | forward_openai_org_id | boolean | If true, forwards the OpenAI Organization ID to the backend LLM call (if it's OpenAI). | -| forward_client_headers_to_llm_api | boolean | If true, forwards the client headers (any `x-` headers) to the backend LLM call | +| forward_client_headers_to_llm_api | boolean | If true, forwards the client headers (any `x-` headers and `anthropic-beta` headers) to the backend LLM call | | maximum_spend_logs_retention_period | str | Used to set the max retention time for spend logs in the db, after which they will be auto-purged | | maximum_spend_logs_retention_interval | str | Used to set the interval in which the spend log cleanup task should run in. | ### router_settings - Reference diff --git a/litellm/proxy/db/db_spend_update_writer.py b/litellm/proxy/db/db_spend_update_writer.py index a5398fa7f2f..e3338a84607 100644 --- a/litellm/proxy/db/db_spend_update_writer.py +++ b/litellm/proxy/db/db_spend_update_writer.py @@ -875,7 +875,8 @@ class DBSpendUpdateWriter: ), "mcp_namespaced_tool_name": transaction.get( "mcp_namespaced_tool_name" - ), + ) + or "", } } diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index f7ab4e06eb6..13bbf97beb3 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -141,28 +141,41 @@ def convert_key_logging_metadata_to_callback( return team_callback_settings_obj + class KeyAndTeamLoggingSettings: """ Helper class to get the dynamic logging settings for the key and team """ + @staticmethod def get_key_dynamic_logging_settings(user_api_key_dict: UserAPIKeyAuth): - if user_api_key_dict.metadata is not None and "logging" in user_api_key_dict.metadata: + if ( + user_api_key_dict.metadata is not None + and "logging" in user_api_key_dict.metadata + ): return user_api_key_dict.metadata["logging"] return None @staticmethod def get_team_dynamic_logging_settings(user_api_key_dict: UserAPIKeyAuth): - if user_api_key_dict.team_metadata is not None and "logging" in user_api_key_dict.team_metadata: + if ( + user_api_key_dict.team_metadata is not None + and "logging" in user_api_key_dict.team_metadata + ): return user_api_key_dict.team_metadata["logging"] return None + def _get_dynamic_logging_metadata( user_api_key_dict: UserAPIKeyAuth, proxy_config: ProxyConfig ) -> Optional[TeamCallbackMetadata]: callback_settings_obj: Optional[TeamCallbackMetadata] = None - key_dynamic_logging_settings: Optional[dict] = KeyAndTeamLoggingSettings.get_key_dynamic_logging_settings(user_api_key_dict) - team_dynamic_logging_settings: Optional[dict] = KeyAndTeamLoggingSettings.get_team_dynamic_logging_settings(user_api_key_dict) + key_dynamic_logging_settings: Optional[dict] = ( + KeyAndTeamLoggingSettings.get_key_dynamic_logging_settings(user_api_key_dict) + ) + team_dynamic_logging_settings: Optional[dict] = ( + KeyAndTeamLoggingSettings.get_team_dynamic_logging_settings(user_api_key_dict) + ) ######################################################################################### # Key-based callbacks ######################################################################################### @@ -267,6 +280,8 @@ class LiteLLMProxyRequestSetup: Get the headers that should be forwarded to the LLM Provider. Looks for any `x-` headers and sends them to the LLM Provider. + + [07/09/2025] - Support 'anthropic-beta' header as well. """ forwarded_headers = {} for header, value in headers.items(): @@ -274,6 +289,8 @@ class LiteLLMProxyRequestSetup: "x-stainless" ): # causes openai sdk to fail forwarded_headers[header] = value + elif header.lower().startswith("anthropic-beta"): + forwarded_headers[header] = value return forwarded_headers diff --git a/tests/proxy_unit_tests/test_proxy_server.py b/tests/proxy_unit_tests/test_proxy_server.py index a515f6bbaa3..ca3df5e8cf8 100644 --- a/tests/proxy_unit_tests/test_proxy_server.py +++ b/tests/proxy_unit_tests/test_proxy_server.py @@ -211,6 +211,7 @@ def test_add_headers_to_request(litellm_key_header_name): "Authorization": "Bearer 1234", "X-Custom-Header": "Custom-Value", "X-Stainless-Header": "Stainless-Value", + "anthropic-beta": "beta-value", } request = Request(scope={"type": "http"}) request._url = URL(url="/chat/completions") @@ -219,7 +220,10 @@ def test_add_headers_to_request(litellm_key_header_name): forwarded_headers = LiteLLMProxyRequestSetup._get_forwardable_headers( request_headers ) - assert forwarded_headers == {"X-Custom-Header": "Custom-Value"} + assert forwarded_headers == { + "X-Custom-Header": "Custom-Value", + "anthropic-beta": "beta-value", + } @pytest.mark.parametrize(