- Add 'token' to MCPAuth enum for custom token auth format
- Implement token auth in MCP client (_get_auth_headers)
- Add token auth support for OpenAPI-based MCP tools
- Add comprehensive unit tests to existing test_mcp_client.py
- Fixes issue where MCP servers expecting 'Authorization: token <value>' header could not connect
When guardrails return the full data dict (e.g. guardrails_ai), the
guardrail response logged to spend logs and OTEL traces could contain
data["secret_fields"].raw_headers with plaintext Authorization headers.
This adds a pop("secret_fields") in the guardrail logging path,
matching the existing pattern used by Langfuse and Arize integrations.
Tested: Verified fix removes secret_fields/raw_headers/authorization
from both /spend/logs/ui responses and OTEL trace span attributes.
* fix(streaming): map unknown finish_reason values to finish_reason_unspecified
Some LLM providers return non-standard finish_reason values that are not
in the OpenAIChatCompletionFinishReason Literal (e.g. ZhipuAI/GLM returns
'network_error' when a streaming error occurs mid-response).
Previously map_finish_reason() fell through with return finish_reason,
passing the unknown value directly to Choices.__init__() which calls
Pydantic validation. This caused a ValidationError that was caught by
stream_chunk_builder() and re-raised as the misleading:
litellm.APIError: Error building chunks for logging/streaming usage calculation
Fix: after all known provider-specific mappings, check if the value is in
the valid set (stop, length, tool_calls, content_filter, function_call,
guardrail_intervened, eos, finish_reason_unspecified, malformed_function_call).
Any value not in this set is mapped to 'finish_reason_unspecified' instead
of being returned as-is.
This is consistent with how other unknown stop reasons (e.g. Vertex AI's
FINISH_REASON_UNSPECIFIED) are already handled.
* refactor: use get_args(OpenAIChatCompletionFinishReason) for valid set
Per code review feedback: replace the hardcoded _valid_finish_reasons set
with a module-level frozenset derived dynamically from the source-of-truth
Literal type via typing.get_args(). This ensures the valid-reason check
stays in sync automatically when new finish reasons are added to the Literal,
and avoids recreating the set on every streaming chunk call.
* test(map_finish_reason): add unit tests and warning log for unknown finish reasons
- Add TestMapFinishReason class in test_core_helpers.py covering:
- All known OpenAI-native values pass through unchanged (parametrized)
- Provider-specific mappings: Anthropic, Cohere, Vertex AI
- Unknown/provider-specific values map to 'finish_reason_unspecified'
- Regression test for ZhipuAI/GLM-5 'network_error' case
- Add verbose_logger.warning() in map_finish_reason() when an unknown
finish_reason is encountered, so operators can track which providers
return non-standard values
When assistant content is already a list containing thinking blocks
inline (not str/None), SEQUENTIAL MODE was still prepending all
thinking_blocks from provider_specific_fields, causing duplication
and breaking Anthropic's position-dependent signature verification.
Now detects if the content list already has thinking blocks and skips
the extend(thinking_blocks) to preserve the original interleaved order.
Addresses the correctness gap identified by Greptile review where
list-content messages bypass INTERLEAVED MODE.
Fixes: https://github.com/BerriAI/litellm/issues/23047
Gemini 2.0+ natively accepts JSON Schema in tool parameters, including
bare {} (TYPE_UNSPECIFIED), anyOf with null, and lowercase types. The
existing _build_vertex_schema pipeline was coercing {} to {"type": "object"},
breaking JsonValue/Any field semantics (issue #22391).
Add _build_vertex_schema_for_gemini_2() that only resolves $ref (which
Gemini doesn't support in tools) and filters unsupported fields. Use it
for Gemini 2.0+ models, keeping the full transform for Gemini 1.5.
- Fix case-insensitive tool name matching in _tool_name_matches() so that
OpenAPI operationIds (camelCase) match lowercase registered tool names
when filtering by allowed_tools
- Fix get_base_url() to resolve relative server URLs (e.g. /api/v3) by
deriving full base URL from spec_path when OpenAPI spec has relative URLs
- Add tests for case-insensitive matching and filter_tools_by_allowed_tools
Made-with: Cursor
`all_models = user_api_key_dict.models` was creating an alias, so
`_get_models_from_access_groups` (which uses `.pop()`/`.extend()`) would
mutate the cached object in-place. Now both `.models` and `.team_models`
assignments create copies via `list()`.
Added test to verify the input is not mutated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds dedup to get_key_models and get_team_models to prevent duplicate
entries when access group member models overlap with proxy_model_list.
Removes dead assignment of all_models in get_team_models.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a team has "all-proxy-models", the model list expansion now includes
model access group names so they appear in the UI key creation form.
Also fixes get_key_models not forwarding include_model_access_groups to
_get_models_from_access_groups, and removes unused _unfurl_all_proxy_models.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix perform_redaction to handle dict representation of ModelResponse (from model_dump())
- Preserve full choices structure when redacting, redact content/audio in place
- Add _redact_standard_logging_object helper for standard_logging_object field
- Update test_logging_redaction_e2e_test assertions to expect choices format
- Add charity_engine to provider_endpoints_support.json
Fixes: test_standard_logging_payload, test_standard_logging_payload_audio
Made-with: Cursor
The SageMaker embedding handler was not using _load_credentials(),
which meant aws_role_name and aws_session_name parameters were
ignored. This prevented cross-account role assumption for embeddings
while it worked for completions.
Changes:
- Replace direct boto3 client creation with _load_credentials() call
- Create boto3.Session with assumed credentials
- Add comprehensive unit tests for role assumption
This aligns the embedding handler behavior with the completion handler,
which already supports role assumption via the BaseAWSLLM.get_credentials()
method.
Fixes cross-account SageMaker embedding access where users need to
assume a role in another account to invoke endpoints.
Any param in DEFAULT_CHAT_COMPLETION_PARAM_VALUES that arrives via
completion(**kwargs) is now automatically forwarded to
get_optional_params(), even if it's not a named parameter of
completion().
Previously, get_non_default_completion_params() excluded params in
OPENAI_CHAT_COMPLETION_PARAMS (assuming they'd be forwarded via the
named-param path), while optional_param_args only contained explicitly
named params. Params like 'store' that were in the known-params list
but not named params fell through both paths and were silently dropped.
The fix adds a 7-line loop after building optional_param_args that
forwards any kwargs present in DEFAULT_CHAT_COMPLETION_PARAM_VALUES.
This means new OpenAI params only need to be added to the constants
dict — no boilerplate changes to 3+ function signatures required.
Fixes#23087
Co-authored-by: Cursor Agent <cursoragent@cursor.com>