mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-05 10:24:03 +00:00
fix(proxy): strip LiteLLM policy tracking from OpenAI batch metadata (#28425)
* fix(proxy): strip LiteLLM policy tracking from OpenAI batch metadata Batch create was failing with `Invalid type for 'metadata.applied_policies': expected a string, but got an array instead` whenever a policy attachment matched the request. The policy engine helpers wrote `applied_policies`, `applied_guardrails`, and `policy_sources` into `data["metadata"]` unconditionally, and `/v1/batches` forwarded that dict straight to OpenAI, which only accepts string values. - Route proxy-internal tracking into `litellm_metadata` for batch/file routes via a shared `_get_or_create_proxy_metadata_bucket` helper. - Sanitize `data["metadata"]` in `create_batch` to drop known internal keys and non-string values before building the OpenAI request. - Cover both behaviors with unit + endpoint tests. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(proxy): merge metadata buckets for batch policy response headers Ensure get_logging_caching_headers reads both metadata and litellm_metadata so policy/guardrail headers are emitted on batch routes with user metadata, and log dropped non-string OpenAI metadata at debug level. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,11 +8,14 @@ sys.path.insert(
|
||||
) # Adds the parent directory to the system path
|
||||
|
||||
from litellm.proxy.common_utils.callback_utils import (
|
||||
add_policy_to_applied_policies_header,
|
||||
decrypt_callback_vars,
|
||||
encrypt_callback_vars,
|
||||
get_logging_caching_headers,
|
||||
initialize_callbacks_on_proxy,
|
||||
get_remaining_tokens_and_requests_from_request_data,
|
||||
normalize_callback_names,
|
||||
sanitize_openai_provider_metadata,
|
||||
)
|
||||
import litellm
|
||||
|
||||
@@ -92,6 +95,50 @@ def test_normalize_callback_names_lowercases_strings():
|
||||
]
|
||||
|
||||
|
||||
def test_add_policy_to_applied_policies_header_uses_litellm_metadata_bucket():
|
||||
request_data = {
|
||||
"input_file_id": "file-abc123",
|
||||
"litellm_metadata": {},
|
||||
}
|
||||
|
||||
add_policy_to_applied_policies_header(
|
||||
request_data=request_data, policy_name="global-baseline"
|
||||
)
|
||||
|
||||
assert request_data["litellm_metadata"]["applied_policies"] == ["global-baseline"]
|
||||
assert "applied_policies" not in request_data.get("metadata", {})
|
||||
|
||||
|
||||
def test_sanitize_openai_provider_metadata_strips_internal_tracking_fields():
|
||||
metadata = {
|
||||
"customer_id": "cust-123",
|
||||
"applied_policies": ["global-baseline"],
|
||||
"applied_guardrails": ["pii_blocker"],
|
||||
"note": 42,
|
||||
}
|
||||
|
||||
sanitized = sanitize_openai_provider_metadata(metadata)
|
||||
|
||||
assert sanitized == {"customer_id": "cust-123"}
|
||||
|
||||
|
||||
def test_get_logging_caching_headers_merges_metadata_and_litellm_metadata():
|
||||
request_data = {
|
||||
"metadata": {"customer_id": "cust-123"},
|
||||
"litellm_metadata": {
|
||||
"applied_policies": ["global-baseline"],
|
||||
"applied_guardrails": ["pii_blocker"],
|
||||
"policy_sources": {"global-baseline": "team_default"},
|
||||
},
|
||||
}
|
||||
|
||||
headers = get_logging_caching_headers(request_data)
|
||||
|
||||
assert headers["x-litellm-applied-policies"] == "global-baseline"
|
||||
assert headers["x-litellm-applied-guardrails"] == "pii_blocker"
|
||||
assert headers["x-litellm-policy-sources"] == "global-baseline=team_default"
|
||||
|
||||
|
||||
def test_initialize_callbacks_on_proxy_instantiates_compression_interception(
|
||||
monkeypatch,
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user