* fix(bedrock): filter non-serializable objects from request params
- Enhanced filter_exceptions_from_params() to filter callable objects (functions) and Logging objects
- Applied filtering in Bedrock's _prepare_request_params() before deepcopy
- Applied filtering to additional_request_params before JSON serialization
- Prevents TypeError during deepcopy (APIConnectionError objects) and JSON serialization (functions, Logging objects)
- Fixes test_bedrock_tool_calling test failures
Root cause: MCP-related functions (handle_chat_completion_with_mcp, completion_callable) and litellm_logging_obj were incorrectly added to optional_params via add_provider_specific_params_to_optional_params(), which then ended up in additional_request_params. These objects should be in litellm_params, not optional_params.
* fix(bedrock): filter internal MCP parameters from API requests
Filter out LiteLLM internal/MCP-related parameters (skip_mcp_handler,
mcp_handler_context, _skip_mcp_handler) from additional_request_params
before sending to Bedrock API to prevent 'extraneous key' errors.
- Added filter_internal_params() helper function in core_helpers.py
- Applied filtering in Bedrock's _prepare_request_params() method
- Fixes test_bedrock_completion.py::test_bedrock_tool_calling
* fix: mypy type error
* fix: add filter_exceptions_from_params to recursive function ignore list
- Add filter_exceptions_from_params to IGNORE_FUNCTIONS in recursive_detector.py
- Function is safe: has max_depth parameter (default 20) to prevent infinite recursion
* fix: correct Request headers format in JWT auth test
Fix test_jwt_non_admin_team_route_access by converting headers to bytes
format as required by Starlette's ASGI specification. Headers must be
bytes tuples with lowercase header names.
This allows dict(request.headers) to work correctly and enables the
authorization check to run, producing the expected error message.
* fix: ignore UUID trace_id from standard_logging_object, use litellm_call_id
The issue was that standard_logging_object.trace_id contains a UUID
(from litellm_trace_id default), which was being used instead of
falling back to litellm_call_id. This caused the test to fail because
it expected 'my-unique-call-id' but got a UUID.
Now we properly detect UUIDs (36 chars with 4 hyphens in specific positions)
and ignore them, allowing the fallback to litellm_call_id to work correctly.
This ensures we use litellm_call_id when no explicit trace_id is provided,
which gets stored in the cache and returned by _get_trace_id().
* fix: use existing_trace_id when provided instead of litellm_call_id
When existing_trace_id is provided in metadata, it should be used as the
trace_id to return (and store in cache), not litellm_call_id. This fixes
the test case where existing_trace_id is set and should be returned by
_get_trace_id().
Add support for the 'xhigh' reasoning effort level on all gpt-5.2 model
variants, not just gpt-5.2-pro. This enables deeper reasoning capabilities
for the base gpt-5.2 model.
Changes:
- Add is_model_gpt_5_2_model() method to detect gpt-5.2 variants
- Update xhigh validation to allow gpt-5.2 models
- Update documentation with gpt-5.2 reasoning_effort support
- Update tests to reflect new behavior
- Add database and Redis setup to litellm_mapped_tests_proxy job in CircleCI
- Create shared test helpers in tests/test_litellm/proxy/conftest.py for proxy test setup
- Refactor health endpoint tests to use shared helpers from conftest
- Support automatic Redis cache configuration when REDIS_HOST is set
- Ensure minimal config is created when Redis/database is needed
Fixes#17821
The `is_cached_message` function crashed with TypeError when message
content was a string instead of a list of content blocks.
Changes:
- Add explicit `isinstance(content, list)` check before iteration
- Add `isinstance(content_item, dict)` check inside loop to skip non-dict items
- Use `.get()` for safer nested dict access
- Follow same pattern as `extract_ttl_from_cached_messages` (same module)
Tests:
- Add TestIsCachedMessage class with 9 test cases covering:
- String content (the reported bug)
- None content
- Missing content key
- Empty list content
- List with/without cache_control
- Mixed content types (strings + dicts)
- Wrong cache_control type
Moved speechConfig from RequestBody to GenerationConfig TypedDict so that
TTS configuration survives the filtering in _transform_request_body().
This fixes the 400 INVALID_ARGUMENT error when using Gemini TTS models
(gemini-2.5-flash-tts, gemini-2.5-flash-preview-tts, etc.) with both
vertex_ai and gemini providers.
Fixes: speechConfig was being created correctly in map_openai_params()
but then filtered out because GenerationConfig.__annotations__.keys()
didn't include it.
Tested with both preview and non-preview TTS model names and both
vertex_ai and gemini providers.
* feat(langfuse): Add support for custom masking function
Allow users to pass a custom masking function via metadata to selectively
redact sensitive data (credit cards, emails, PII) before sending to Langfuse.
Usage:
```python
def mask_pii(data):
if isinstance(data, str):
data = re.sub(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', '[CARD]', data)
return data
litellm.completion(
model="gpt-4",
messages=[...],
metadata={"langfuse_masking_function": mask_pii}
)
```
* fix(langfuse): Isolate masking function from other logging integrations
Extract langfuse_masking_function from metadata early in the flow and store
it in a dedicated key (_langfuse_masking_function) that only the Langfuse
logger knows to look for. This prevents the callable from leaking to other
logging integrations (Datadog, S3, etc.) which would serialize it as
"<function at 0x...>".
Changes:
- scrub_sensitive_keys_in_metadata() now extracts and stores the function
- Langfuse logger looks in the dedicated key first, falls back to metadata
- Added tests to verify isolation works correctly
* feat(deepseek): add native support for thinking and reasoning_effort params
Add proper parameter mapping for DeepSeek thinking mode, allowing users
to use the unified LiteLLM interface instead of extra_body workarounds.
Supported formats:
- thinking={"type": "enabled"}
- thinking={"type": "enabled", "budget_tokens": X} (budget_tokens ignored)
- reasoning_effort="low|medium|high" (maps to thinking enabled)
DeepSeek only supports {"type": "enabled"} without budget_tokens,
so any budget_tokens are stripped and all reasoning_effort values
(except "none") map to enabled.
Reference: https://api-docs.deepseek.com/guides/thinking_mode
* docs(deepseek): add thinking and reasoning_effort parameter documentation
* fix(openai): use optimized async http client for text completions
OpenAITextCompletion.acompletion was using litellm.aclient_session directly
instead of the optimized http client with aiohttp transport that
OpenAIChatCompletion uses. This fixes inconsistent behavior where custom
SSL configs and the faster aiohttp transport were not applied to async
text completion requests.
Fixes#17676
* test(openai): add test for text completion async http client
Verify that OpenAITextCompletion.acompletion uses the optimized
BaseOpenAILLM._get_async_http_client() instead of litellm.aclient_session.
Related to #17676
* test: move http client test to existing test file
Move test_acompletion_uses_optimized_http_client to
test_text_completion_unit_tests.py instead of separate file.
When using litellm.completion() with model="openai/responses/...", images
in tool message content were not being transformed from Chat Completion
format to Responses API format.
Chat Completion format: {"type": "image_url", "image_url": {"url": "..."}}
Responses API format: {"type": "input_image", "image_url": "..."}
This caused OpenAI to reject the request with error 400 since "image_url"
is not a valid type for function_call_output content.
This fix addresses two issues with Anthropic web search streaming:
1. Fix trailing {} in tool call arguments
- web_search_tool_result blocks have input_json_delta events that were
incorrectly emitted as tool calls
- Added current_content_block_type tracking to only emit tool calls for
tool_use and server_tool_use blocks
2. Capture web_search_tool_result for multi-turn
- The web_search_tool_result content comes ALL AT ONCE in content_block_start
- Now captured in provider_specific_fields.web_search_results
- stream_chunk_builder combines these for final message
- Allows multi-turn conversations to work with streaming web search
Add support for the Bedrock Converse API serviceTier parameter to allow
specifying processing tier (priority, default, or flex).
Changes:
- Add ServiceTierBlock type in litellm/types/llms/bedrock.py
- Add serviceTier to CommonRequestObject
- Add serviceTier to get_config_blocks() in AmazonConverseConfig
- Add comprehensive tests for serviceTier functionality
- Add documentation for serviceTier usage
This allows users to configure service tier via:
- litellm_params in proxy config
- optional_params in SDK calls
* fix(azure_ai): Remove unsupported params from Azure AI Anthropic requests
Azure AI Anthropic endpoint rejects max_retries and stream_options parameters
with "Extra inputs are not permitted" error. These are LiteLLM-internal
parameters that should not be sent to the API.
Fixes 400 Bad Request error when using azure_ai/claude-sonnet-4-5 and other
Azure AI Anthropic models.
* test(azure_ai): Add test for unsupported params removal in Azure AI Anthropic
Verifies that max_retries, stream_options, and extra_body are properly
removed from the request before sending to Azure AI Anthropic endpoint.