* feat: add opus 4.5 and 4.6 to use outout_format param
* generate poetry lock with 2.3.2 poetry
* restore poetry lock
* e2e tests, key delete, update tpm rpm, and regenerate
* Split e2e ui testing for browser
* new login with sso button in login page
* option to hide usage indicator
* fix(cloudzero): update CBF field mappings per LIT-1907 (#20906)
* fix(cloudzero): update CBF field mappings per LIT-1907
Phase 1 field updates for CloudZero integration:
ADD/UPDATE:
- resource/account: Send concat(api_key_alias, '|', api_key_prefix)
- resource/service: Send model_group instead of service_type
- resource/usage_family: Send provider instead of hardcoded 'llm-usage'
- action/operation: NEW - Send team_id
- resource/id: Send model name instead of CZRN
- resource/tag:organization_alias: Add if exists
- resource/tag:project_alias: Add if exists
- resource/tag:user_alias: Add if exists
REMOVE:
- resource/tag:total_tokens: Removed
- resource/tag:team_id: Removed (team_id now in action/operation)
Fixes LIT-1907
* Update litellm/integrations/cloudzero/transform.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: define api_key_alias variable, update CBFRecord docstring
- Fix F821 lint error: api_key_alias was used but not defined
- Update CBFRecord docstring to reflect LIT-1907 field mappings
- Remove unused Optional import
---------
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Add banner notifying of breaking change
* Add semgrep & Fix OOMs (#20912)
* [Feat] Policies - Allow connecting Policies to Tags, Simulating Policies, Viewing how many keys, teams it applies on (#20904)
* init schema with TAGS
* ui: add policy test
* resolvePoliciesCall
* add_policy_sources_to_metadata + headers
* types Policy
* preview Impact
* def _describe_match_reason(
* match based on TAGs
* TestTagBasedAttachments
* test fixes
* add policy_resolve_router
* add_guardrails_from_policy_engine
* TestMatchAttribution
* refactor
* fix
* fix: address Greptile review feedback on policy resolve endpoints
- Track unnamed keys/teams as separate counts instead of inflating
affected_keys_count with duplicate "(unnamed key)" placeholders.
Added unnamed_keys_count and unnamed_teams_count to response.
- Push alias pattern matching to DB via _build_alias_where() which
converts exact patterns to Prisma "in" and suffix wildcards to
"startsWith" filters.
- Gate sync_policies_from_db/sync_attachments_from_db behind
force_sync query param (default false) to avoid 2 DB round-trips
on every /policies/resolve request.
- Remove worktree-only conftest.py that cleared sys.modules at import
time — no longer needed since code moved to main repo.
- Rename MAX_ESTIMATE_IMPACT_ROWS → MAX_POLICY_ESTIMATE_IMPACT_ROWS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: eliminate duplicate DB queries and fix header delimiter ambiguity
- Fetch teams table once in estimate_attachment_impact and reuse for
both tag-based and alias-based lookups (was querying teams twice when
both tag_patterns and team_patterns were provided).
- Convert tag/team filter functions from async DB queries to sync
filters that operate on pre-fetched data (_filter_keys_by_tags,
_filter_teams_by_tags).
- Fix comma ambiguity in x-litellm-policy-sources header: use '; '
as entry delimiter since matched_via values can contain commas.
- Use '+' as the within-value separator in matched_via reason strings
(e.g. "tag:healthcare+team:health-team") to avoid conflict with
header delimiters.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update litellm/proxy/policy_engine/policy_resolve_endpoints.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: type error & better error handling (#20689)
* [Docs] Add docs guide for using policies (#20914)
* init schema with TAGS
* ui: add policy test
* resolvePoliciesCall
* add_policy_sources_to_metadata + headers
* types Policy
* preview Impact
* def _describe_match_reason(
* match based on TAGs
* TestTagBasedAttachments
* test fixes
* add policy_resolve_router
* add_guardrails_from_policy_engine
* TestMatchAttribution
* refactor
* fix
* fix: address Greptile review feedback on policy resolve endpoints
- Track unnamed keys/teams as separate counts instead of inflating
affected_keys_count with duplicate "(unnamed key)" placeholders.
Added unnamed_keys_count and unnamed_teams_count to response.
- Push alias pattern matching to DB via _build_alias_where() which
converts exact patterns to Prisma "in" and suffix wildcards to
"startsWith" filters.
- Gate sync_policies_from_db/sync_attachments_from_db behind
force_sync query param (default false) to avoid 2 DB round-trips
on every /policies/resolve request.
- Remove worktree-only conftest.py that cleared sys.modules at import
time — no longer needed since code moved to main repo.
- Rename MAX_ESTIMATE_IMPACT_ROWS → MAX_POLICY_ESTIMATE_IMPACT_ROWS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: eliminate duplicate DB queries and fix header delimiter ambiguity
- Fetch teams table once in estimate_attachment_impact and reuse for
both tag-based and alias-based lookups (was querying teams twice when
both tag_patterns and team_patterns were provided).
- Convert tag/team filter functions from async DB queries to sync
filters that operate on pre-fetched data (_filter_keys_by_tags,
_filter_teams_by_tags).
- Fix comma ambiguity in x-litellm-policy-sources header: use '; '
as entry delimiter since matched_via values can contain commas.
- Use '+' as the within-value separator in matched_via reason strings
(e.g. "tag:healthcare+team:health-team") to avoid conflict with
header delimiters.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs v1 guide with UI imgs
* docs fix
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add dashscope/qwen3-max model with tiered pricing (#20919)
Add support for Alibaba Cloud's Qwen3-Max model with:
- 258K input tokens, 65K output tokens
- Tiered pricing based on context window usage (0-32K, 32K-128K, 128K-252K)
- Function calling and tool choice support
- Reasoning capabilities enabled
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix linting
* docs: add Greptile review requirement to PR template (#20762)
* fix(azure): preserve content_policy_violation error details from Azure OpenAI
Closes#20811
Azure OpenAI returns rich error payloads for content policy violations
(inner_error with ResponsibleAIPolicyViolation, content_filter_results,
revised_prompt). Previously these details were lost when:
1. The top-level error code was not "content_policy_violation" but the
inner_error.code was "ResponsibleAIPolicyViolation" -- the structured
check only examined the top-level code.
2. The DALL-E image generation polling path stringified the error JSON
into the message field instead of setting the structured body, making
it impossible for exception_type() to extract error details.
3. The string-based fallback detector used "invalid_request_error" as a
content-policy indicator, which is too broad and could misclassify
regular bad-request errors.
Changes:
- exception_mapping_utils.py: Check inner_error.code for
ResponsibleAIPolicyViolation when top-level code is not
content_policy_violation. Replace overly broad "invalid_request_error"
string match with specific Azure safety-system messages.
- azure.py: Set structured body on AzureOpenAIError in both async and
sync DALL-E polling paths so exception_type() can inspect error details.
- test_azure_exception_mapping.py: Add regression tests covering the
exact error payloads from issue #20811.
- Fix pre-existing lint: duplicate PerplexityResponsesConfig dict key,
unused RouteChecks top-level import.
---------
Co-authored-by: Kelvin Tran <kelvin-tran@users.noreply.github.com>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: shin-bot-litellm <shin-bot-litellm@berri.ai>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Harshit Jain <48647625+Harshit28j@users.noreply.github.com>
Co-authored-by: ken <122603020@qq.com>
Co-authored-by: Sameer Kankute <sameer@berri.ai>
2026-02-10 22:47:03 -08:00
Cesar GarciaGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: reasoning_effort=None returns None for Opus 4.6
Previously, _map_reasoning_effort would return adaptive thinking
for Opus 4.6 even when reasoning_effort was None, which breaks the
expected contract where None means no thinking is sent.
* fix: handle reasoning_effort="none" string for Opus 4.6
The string "none" is a valid OpenAI reasoning_effort value meaning
"disable thinking". Previously it was mapped to adaptive for Opus 4.6.
* Update tests/litellm/llms/anthropic/test_anthropic_reasoning_effort.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Generic Guardrails: Forward request headers + litellm_version to generic guardrail API
* Generic Guardrail: Change the request headers addition to be with allowlist instead denylist
* fix(scheduler): remove timed-out requests from queue to prevent memory leak
Fixes#20059
* fix(scheduler): use actual model param instead of hardcoded gpt-3.5-turbo in schedule_acompletion
* trigger CLA recheck
---------
Co-authored-by: Piyush Bhawsar <piyush100x@Piyushs-MacBook-Pro-3.local>
Adds a new config option to exclude specific fields from StandardLoggingPayload
before any callback receives it. This provides a general approach to control
what data is logged across ALL integrations (S3, GCS, Datadog, etc.).
## Changes
1. **litellm/__init__.py**: Added new global setting
`standard_logging_payload_excluded_fields: Optional[List[str]] = None`
2. **litellm/integrations/custom_logger.py**: Modified
`redact_standard_logging_payload_from_model_call_details()` to:
- Remove specified fields entirely from the StandardLoggingPayload
- Works alongside existing `turn_off_message_logging` feature
- Excluded fields take precedence (removed rather than redacted)
3. **tests/**: Added comprehensive test suite with 17 tests covering:
- Single/multiple field exclusion
- Interaction with turn_off_message_logging
- Original payload immutability
- Config loading via setattr (proxy pattern)
- Edge cases (empty list, non-existent fields, None standard_logging_object)
## Usage
```yaml
litellm_settings:
success_callback: ["s3"]
standard_logging_payload_excluded_fields: ["response", "messages"]
```
This removes the `response` and `messages` fields from logs before any
callback processes them, reducing log size and improving privacy compliance.
## Available Fields
The fields match StandardLoggingPayload TypedDict keys including:
- messages, response (large payload fields)
- metadata, hidden_params, model_parameters
- error_str, error_information
- And all other StandardLoggingPayload fields
Closes the need for per-integration flags like `s3_log_response`.
* [Fix] handle metadata=None in SDK path retry/error logic (utils.py)
Fixes#20871
Same class of bug as #9717 (fixed by #9764 for the proxy path).
The SDK path in utils.py has the same fragile pattern at 7 locations.
Replace `kwargs.get("metadata", {})` with `(kwargs.get("metadata") or {})`
to handle the case where metadata key exists with value None (e.g. from
Azure OpenAI streaming responses).
This is consistent with the existing correct pattern at line 602:
`metadata = kwargs.get("metadata") or {}`
Adds TestMetadataNoneHandling with 6 unit tests in test_utils.py.
* fix: remove duplicate PerplexityResponsesConfig key in lazy imports registry
Removes duplicate dictionary key added in commit be0ebb15 (PR #20860).
The entry at line 1042 is identical to the existing entry at line 906.
This causes ruff F601 lint failure on all PRs targeting main.
* feat(guardrail_hooks/): add guardrail logging to all unified guardrails
ensures unified guardrails use the 'log_guardrail_information' decorator for logging
* fix(custom_guardrail.py): don't log inputs on guardrail response - just emit state
* refactor: don't double log bedrock guardrail information
* feat: add in-product nudges for contributing + trying community custom code guardrails
allows users to contribute / share custom code guardrails
* fix(aiohttp): respect ssl_verify with shared sessions
* fix(aiohttp): resolve mypy error for ssl parameter type
Pass ssl kwarg conditionally to aiohttp request() only when explicitly
configured, since None is not a valid value for the ssl parameter
(expected SSLContext | bool | Fingerprint).
When OpenTelemetry is configured via the UI, only OTEL_ENDPOINT and
OTEL_HEADERS are set, but OTEL_EXPORTER is not specified. This caused
the exporter to default to "console", meaning traces were printed to
stdout instead of being sent to the configured endpoint.
This fix adds logic in OpenTelemetryConfig.__post_init__ to automatically
infer "otlp_http" as the exporter when an endpoint is specified but the
exporter is still the default "console".
Fixes issue reported by Elastic team where traces weren't being sent
to their OTEL endpoint when configured through the LiteLLM UI.
* fix:Parse embedded JSON in the message field of logs
* Update litellm/_logging.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
When transforming chat completion responses to Responses API format,
image_tokens from completion_tokens_details was not being included
in output_tokens_details. This affected Vertex AI/Gemini models that
return image token counts in candidatesTokensDetails with modality="IMAGE".
The fix adds image_tokens handling alongside existing reasoning_tokens
and text_tokens transformation.
* fix(responses): preserve streamed tool deltas when id is omitted
* fix(responses): guard ambiguous tool-call index reuse
* add missing indexes on VerificationToken table
* fix(bedrock): handle concatenated JSON in tool call arguments
When using Bedrock Claude Sonnet 4.5 with tools enabled, the model
sometimes returns multiple tool call arguments as concatenated JSON
objects in a single arguments string, e.g.
'{"command":["curl",...]}{"command":["curl",...]}{"command":["curl",...]}'
json.loads() fails on this with "Extra data", crashing the entire
request in _convert_to_bedrock_tool_call_invoke.
This commit:
- Adds split_concatenated_json_objects() helper in common_utils.py
that uses json.JSONDecoder.raw_decode() to walk a string and extract
each JSON object individually.
- Updates _convert_to_bedrock_tool_call_invoke() to catch JSONDecodeError
and attempt splitting concatenated objects into separate Bedrock
toolUse blocks (first block keeps original ID, subsequent blocks get
suffixed IDs).
- Fixes duplicate json.loads calls and a shadowed 'id' builtin.
- Adds 12 unit tests covering normal, empty, concatenated, and edge cases.
Fixes#20543
---------
Co-authored-by: Emerson Gomes <emerson.gomes@thalesgroup.com>
Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Carlo Alberto Ferraris <cafxx@mercari.com>
OIDC providers like Logto may return opaque (non-JWT) access tokens,
which caused jwt.decode() to raise DecodeError and crash the SSO
callback with a 500 error. Catch DecodeError and skip JWT-based
extraction gracefully, since user info is already available from
the UserInfo endpoint.
Fixes#20724
* Add chat completion support for websearch
* Add chat completion tool calls support and response transformation
* Add new methods in chat completion
* Add chat completion tool format
* Add callback for websearch in completion method
* Add test for web search
* Potential fix for code scanning alert no. 4046: Clear-text logging of sensitive information
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Update litellm/integrations/websearch_interception/tools.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20567)
* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20304)
The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.
Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.
UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.
Fixes#20304
* fix: allow clearing fields with empty collections while skipping enterprise check
Address PR review feedback:
1. Move the empty-collection guard into _update_metadata_field (singular)
so that empty lists/dicts skip only the premium license check but still
get written into metadata. This lets users intentionally clear a
previously-set field (e.g. guardrails: []) without being blocked, while
the UI's default empty arrays still don't trigger a false enterprise
error.
2. Remove sys.path hack from test file; use standard imports that work
with pytest discovery.
3. Add tests verifying that empty collections are moved into metadata
(field clearing works) even though they bypass the premium check.
Fixes#20304
* fix critical CVE vulnerabliltes (#20683)
* fix: add hook to handle db case (#20635)
* Add team policy mapping for zguard (#20608)
* support policy mapping on team key level
* update document
* update document
* address comments
* update document
* add unit test for new feature
* add more test case
* feat: add support for anthropic_messages call type in prompt caching (#19233)
* feat: add support for anthropic_messages call type in prompt caching
* test: move anthropic_messages prompt caching test to main router test file
* add tutorial on using claude code with prompt cache routing
* docs: add SDK proxy authentication (OAuth2/JWT auto-refresh) documentation (#20680)
Adds documentation for the litellm.proxy_auth feature that automatically
obtains and refreshes OAuth2/JWT tokens when connecting to a LiteLLM Proxy.
* Fixes#20582 (#20663)
* fix: show error details instead of Data Not Available for failed requests (#20656)
* fix(ui): add null guard for models in API keys table (#20655)
The VirtualKeysTable crashed when rendering keys with null or undefined
models field. The className expression tried to access .length on null,
throwing a TypeError that broke the entire keys table.
Added Array.isArray() guard before accessing .length on the models value.
Fixes#20611
* Fix: Spend logs pickle error with Pydantic models and redaction (#20685)
* docs: add callback registration optimization to v1.81.9 release notes (#20681)
* docs: add callback registration optimization to v1.81.9 release notes
* Update v1.81.9.md
---------
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
* Fix spend logs pickle error with Pydantic models
Replace copy.deepcopy() with Pydantic-safe serialization to avoid
"cannot pickle '_thread.RLock' object" errors when request/response
redaction is enabled.
Changes:
- Add _convert_to_json_serializable_dict() helper that uses
model_dump() for Pydantic models instead of pickle
- Replace copy.deepcopy() calls in request and response redaction
paths with the new helper function
- Recursively handles nested dicts, lists, and Pydantic models
Root cause: Pydantic v2 BaseModel instances contain internal
_thread.RLock objects for thread-safety. When copy.deepcopy()
attempts to pickle these objects, it fails because threading
primitives cannot be pickled.
Fixes#20647
* chore: remove unused copy import
Remove unused copy import that was causing lint failure. The copy.deepcopy()
calls were replaced with _convert_to_json_serializable_dict() helper function
in the previous commit, making the copy module no longer needed.
---------
Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
* fix(vertex_ai): propagate extra_headers anthropic-beta to request body (#20666)
Vertex AI requires Anthropic beta flags in the request body
(anthropic_beta array), not as HTTP headers. The Bedrock handler
already extracts user-specified beta headers from the headers dict,
but the Vertex handler was missing this, causing extra_headers like
interleaved-thinking-2025-05-14 to be silently dropped.
This extracts anthropic-beta values from optional_params extra_headers
and merges them into the anthropic_beta request body field, and also
removes extra_headers from the request body since the parent's
transform_request spreads optional_params into data.
* fix(streaming): preserve interleaved thinking/redacted blocks
* test(streaming): build thinking chunks with typed Delta/StreamingChoices
* Fix video list pagination cursors not encoded with provider metadata
first_id and last_id in the video list response were returned as raw
provider IDs while data[].id was properly wrapped with
encode_video_id_with_provider(). This caused pagination to break when
clients passed unencoded cursors back as the `after` parameter.
- Encode first_id/last_id in transform_video_list_response
- Decode the `after` param in transform_video_list_request via
extract_original_video_id()
- Add 6 unit tests covering encoding, decoding, passthrough, and
full round-trip pagination
Fixes#20708
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(responses): preserve streamed tool deltas when id is omitted
* fix(responses): guard ambiguous tool-call index reuse
* Add compaction for vertex ai
* Add all new feat for v1/messages
* Add inference_geo as supported messages param
* Add inference based costing
* Add inference_geo as supported messages param
* Add support for fast param
* Add fast mode for other providers
* Add documentation for Fast Mode
* add missing indexes on VerificationToken table
* Fix structured response of tool call
* Add tests for WebSearch interception with chat completions API
* Add doc for chat completion web search
* Fix: is_web_search_tool_chat_completion
* Fix double json import
* Add new vercel ai anthropic models
* Fix: base_model name for body and deplyment name in URL
* Add output_config as supported param
* Add response schema for vercel ai sonnet 4.5
* handle when litellm_parrams might be none
* Fix : litellm/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py
* fix: Missing return statement for async streaming
* Fix: get_supported_anthropic_messages_params
* Fix mypy issues
* Fix mypy issues
* Add support for extra fields in Generic SSO via GENERIC_USER_EXTRA_ATTRIBUTES
Enables extraction of additional fields from the Generic SSO userinfo endpoint response beyond the standard 8 fields (id, email, name, etc.). Custom handlers can now access these fields via CustomOpenID.extra_fields dict.
Changes:
- Add extra_fields: Optional[Dict[str, Any]] to CustomOpenID type
- Add GENERIC_USER_EXTRA_ATTRIBUTES env var (comma-separated field names)
- Extract specified fields using get_nested_value() with dot notation support
- Add 4 test cases covering basic, nested, and missing field scenarios
- Update custom_sso.py example showing how to access extra_fields
Backward compatible: extra_fields is None when env var not set
* docs: Add documentation for GENERIC_USER_EXTRA_ATTRIBUTES
Document the new GENERIC_USER_EXTRA_ATTRIBUTES environment variable for Generic SSO
- Add to admin_ui_sso.md: explanation and usage examples
- Add to config_settings.md: environment variable reference
- Add to custom_sso.md: code example showing how to access extra_fields
- Includes examples for nested field paths with dot notation
---------
Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Varun Chawla <34209028+veeceey@users.noreply.github.com>
Co-authored-by: Harshit Jain <48647625+Harshit28j@users.noreply.github.com>
Co-authored-by: jwang-gif <j.wang@zscaler.com>
Co-authored-by: nuernber <benjamin.nuernberger@jpl.nasa.gov>
Co-authored-by: Cesar Garcia <128240629+Chesars@users.noreply.github.com>
Co-authored-by: John Lathouwers <john.lathouwers@oracle.com>
Co-authored-by: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
Co-authored-by: Elias Högbom Aronsson <elias.aronson@gmail.com>
Co-authored-by: Emerson Gomes <emerson.gomes@thalesgroup.com>
Co-authored-by: tshushan <tshushan@outbrain.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Carlo Alberto Ferraris <cafxx@mercari.com>
When MCP SDK hits root-level /register, /authorize, /token without
server name prefix, auto-resolve to the single configured OAuth2
server. Also fix WWW-Authenticate header to use correct public URL
behind reverse proxy.
* fix(prometheus): sanitize label values to prevent metric scrape failures
Unicode characters like U+2028 (Line Separator) in Prometheus label values
break the text exposition format, causing scrapers (e.g. Datadog) to fail
parsing the entire /metrics endpoint. One bad label value causes ALL metrics
to be lost, not just the affected metric.
Add _sanitize_prometheus_label_value() and apply it in prometheus_label_factory()
and all direct .labels() call sites.
* fix(prometheus): handle non-string label values in sanitization
Coerce non-string values (int, bool, float) to str before applying
sanitization, preventing AttributeError on .replace() calls.
* fix(prometheus): run sanitization on coerced non-string values
Non-string values should be coerced to str and then sanitized (not
returned early), so their string representations also get cleaned.
* fix(prometheus): widen type hint to Optional[Any] for label value sanitization