litellm/litellm
yucheng-berri 342d8897b6
fix(guardrails): walk Responses-API text taxonomy in shared content helpers (#32542)
* fix(guardrails): walk Responses-API text taxonomy in shared content helpers

Every guardrail sharing litellm/proxy/guardrails/_content_utils.py silently
drops all text on the /v1/responses path. AIM turns it into a loud 422 (
{"error":"No messages in the request"}); every other guardrail (Lakera v2,
Cato, Lasso, Repello, IBM, Azure Content Safety, enterprise secret
detection) scans an empty payload and lets the request through unscanned.

Three defects, all in _content_utils.py:

1. _iter_text_parts_in_content recognised only part.type == "text", but the
   Responses API uses input_text (request) and output_text (assistant).
2. _coerce_input_to_messages gated on "every item has a role key"; any
   Responses input list containing a function_call or function_call_output
   item failed the check and was wrapped as one opaque blob.
3. build_inspection_messages forwarded any role through, including a bare
   tool role missing tool_call_id, which validators like AIM's /fw/v1/analyze
   reject with a schema error.

Fix walks the actual Responses item taxonomy (message, function_call,
function_call_output, bare content parts and strings), recognises
{text, input_text, output_text} everywhere, and coerces any role outside
{system, user, assistant} to user in the outbound inspection payload.

* style: ruff-format changed guardrail files

* test(guardrails): cover function_call_output string form; drop em-dash in new docstring

* fix(guardrails): map function_call_output straight to user role

Avoids ever materialising a schema-invalid bare tool message. The
downstream role-safety coercion in build_inspection_messages still
guards genuinely caller-supplied non-standard roles (developer,
function, custom values); add a regression test covering that path
so the coercion has real coverage after this simplification.

* test(guardrails): pin chat-completions tool-role coercion in build_inspection_messages

* docs(test): soften AIM-specific claims in LIT-4294 test docstrings

Ryan's review flagged that several test docstrings assert AIM's
/fw/v1/analyze validates + rejects specific schema violations. That
behavior is customer-reported in the LIT-4294 writeup, not directly
verified by us. Rephrase to attribute the AIM 422 to the customer's
writeup and describe the underlying constraint as the OpenAI chat
schema; any downstream API that validates against that schema rejects
the same shape.

* refactor(guardrails): move unsupported-role coercion into AIM only

The generic coercion in build_inspection_messages collapsed any role
outside {system, user, assistant} to user for every caller of the
helper. Combined with the pre-existing apply_redacted_messages_back
write-back behavior in Lakera/AIM/Cato, that turned a loud OpenAI 400
on chat-completions tool-message masking into a silent semantic
corruption of the outbound request (role tool with tool_call_id got
rewritten to bare role user, dropping the assistant + tool_calls
sibling).

AIM specifically requires the coercion because its /fw/v1/analyze
validates the payload against the OpenAI chat schema; other guardrails
either do not validate roles or do their own reconstruction. Move the
coercion to AimGuardrail._build_aim_inspection_messages so the shared
helper keeps caller roles intact and no new cross-guardrail role
corruption is introduced. The pre-existing apply_redacted_messages_back
structural flatten remains as separate follow-up work.

function_call_output items still synthesise role user in the shared
helper because they have no natural role field, which is a different
concern from coercing a caller-supplied role.

* refactor(guardrails): preserve role fidelity in shared _content_utils

Shared inspection helpers should extract text and preserve semantic
role signals; role coercion for third-party schema safety stays inside
the guardrail that needs it (AIM).

Three shared-helper changes:
- Bare content-part dicts (input_text/output_text) with an explicit role
  keep it; only role-less parts default to user.
- Responses message items already had their role preserved; the
  behavior is now covered by an explicit test.
- function_call_output items default to role tool (semantic equivalent
  of the chat-completions tool message shape) instead of role user, so
  Responses and chat completions produce symmetric inspection payloads.
  A caller-supplied role on the item is still preserved.

AIM's schema-safe coercion in _build_aim_inspection_messages already
handles the resulting role tool: it collapses to user before the POST
to /fw/v1/analyze so AIM's OpenAI-schema validator does not reject the
bare tool message (no tool_call_id can survive the flatten). Added a
regression test in test_aim.py covering that path.

(cherry picked from commit e84a19acd5)
2026-07-11 12:07:55 -07:00
..
a2a_protocol chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
anthropic_interface feat(context_management): compact_20260112 polyfill for non-Anthropic providers (#28868) 2026-05-30 09:20:05 -07:00
assistants
batch_completion fix: prompt registry 2026-02-18 00:34:54 +05:30
batches fix(vertex/files): stream OpenAI->Vertex batch JSONL uploads (#31036) 2026-06-29 17:56:01 -07:00
caching feat(caching): add valkey-semantic cache backend and fix semantic cache scope keys (#30675) 2026-06-19 17:09:17 -07:00
completion_extras chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
compression build(deps-dev): bump black to 26.3.1 and apply formatting (#28525) 2026-05-21 17:24:18 -07:00
containers style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
endpoints/speech/speech_to_completion_bridge
evals style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
experimental_mcp_client fix(mcp): stop logging tool-call input in MCP client (#31393) 2026-07-02 21:41:21 -07:00
files fix(vertex/files): stream OpenAI->Vertex batch JSONL uploads (#31036) 2026-06-29 17:56:01 -07:00
fine_tuning address greptile review feedback (greploop iteration 1) 2026-03-27 20:04:41 +05:30
google_genai fix(google_genai): preserve complete SSE events in Vertex/Gemini image streaming (#30270) 2026-06-12 07:49:30 -07:00
images chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
integrations fix(otel): one v2 logger owns the global provider; scope tenant OTLP creds per exporter (#30590) 2026-06-19 11:15:29 -07:00
interactions fix(a2a): forward agent_extra_headers through completion bridge (#28277) 2026-06-11 21:56:18 -07:00
litellm_core_utils fix(bedrock/converse): drop toolSpec.strict for Opus 4.7/4.8 (#31582) (#31923) 2026-07-02 21:07:31 -07:00
llms fix(bedrock): honor ttl for tool_config cache injection points (#31929) 2026-07-02 21:22:01 -07:00
models feat(litellm): add models and repository layers (#29686) 2026-06-06 20:59:33 -07:00
ocr chore: reject bare str at file-input sinks to prevent local-file read (#27762) 2026-05-12 16:40:07 -07:00
passthrough feat(passthrough): add configurable pass-through request timeouts (#30266) 2026-06-12 07:40:02 -07:00
proxy fix(guardrails): walk Responses-API text taxonomy in shared content helpers (#32542) 2026-07-11 12:07:55 -07:00
proxy_auth fix: prompt registry 2026-02-18 00:34:54 +05:30
rag chore: litellm oss staging (#30745) 2026-06-18 13:55:35 -07:00
realtime_api chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
repositories feat(litellm): add models and repository layers (#29686) 2026-06-06 20:59:33 -07:00
rerank_api chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
responses chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
router_strategy chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
router_utils fix(vertex/files): stream OpenAI->Vertex batch JSONL uploads (#31036) 2026-06-29 17:56:01 -07:00
sandbox feat(sandbox): e2b code execution primitive (#30898) 2026-06-20 16:30:01 -07:00
search Litellm oss staging 050626 (#29774) 2026-06-05 13:51:51 -07:00
secret_managers ci: drop mypy entirely, standardize type checking on basedpyright (#30648) 2026-06-17 09:42:00 -07:00
skills chore(proxy): scope skills and container resources 2026-04-30 18:23:58 -07:00
types fix(bedrock): honor ttl for tool_config cache injection points (#31929) 2026-07-02 21:22:01 -07:00
vector_store_files build(deps-dev): bump black to 26.3.1 and apply formatting (#28525) 2026-05-21 17:24:18 -07:00
vector_stores feat(litellm): add models and repository layers (#29686) 2026-06-06 20:59:33 -07:00
videos ci(lint): add blanket-noqa, dataclass-default, and unused-noqa Ruff rules (#30516) 2026-06-16 12:07:22 -07:00
__init__.py feat(sandbox): e2b code execution primitive (#30898) 2026-06-20 16:30:01 -07:00
_internal_context.py fix(proxy): harden request parameter handling 2026-04-16 01:38:12 +00:00
_lazy_imports.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
_lazy_imports_registry.py chore(oss): litellm oss staging 150626 (#30463) 2026-06-16 12:06:41 -07:00
_logging.py ci(lint): add blanket-noqa, dataclass-default, and unused-noqa Ruff rules (#30516) 2026-06-16 12:07:22 -07:00
_redis.py chore(lint): remove PLR0915 too-many-statements ruff rule (#30574) 2026-06-16 16:52:49 -07:00
_redis_credential_provider.py feat: add ability to auth to azure with token (#27556) 2026-05-09 22:34:09 +00:00
_service_logger.py fix: missing span for guardrail passthrough (#29552) 2026-06-03 01:25:15 +00:00
_uuid.py build(deps-dev): bump black to 26.3.1 and apply formatting (#28525) 2026-05-21 17:24:18 -07:00
_version.py
anthropic_beta_headers_config.json chore(oss): litellm oss staging 120626 (#30292) 2026-06-12 09:49:25 -07:00
anthropic_beta_headers_manager.py Refactor: Filtering beta header after transformation 2026-03-16 10:47:15 +05:30
blog_posts.json docs(blog): add WebRTC blog post link 2026-03-13 17:54:33 +05:30
budget_manager.py docs(budget_manager): add docstring to BudgetManager.reset_cost (#27867) 2026-05-13 13:28:22 -07:00
constants.py chore: litellm oss staging (#30745) 2026-06-18 13:55:35 -07:00
cost.json
cost_calculator.py fix(cost): stop non-string response service_tier from dropping cost tracking (#30706) 2026-06-17 19:35:57 -07:00
exceptions.py feat: standardize rate limit errors with category, rate_limit_type, model, and llm_provider fields (#27687) 2026-06-06 17:50:29 -07:00
main.py fix(health): correct bedrock embedding health checks (#30583) 2026-06-17 14:34:09 -07:00
model_prices_and_context_window_backup.json fix(bedrock): honor ttl for tool_config cache injection points (#31929) 2026-07-02 21:22:01 -07:00
policy_templates_backup.json feat(add-new-block_code_execution-guardrail): prevent agent from executing code (#22154) 2026-02-25 22:02:14 -08:00
provider_endpoints_support_backup.json chore(oss): litellm oss staging 150626 (#30463) 2026-06-16 12:06:41 -07:00
py.typed
router.py chore: litellm oss 170626 (#30637) 2026-06-17 21:11:12 -07:00
scheduler.py style: run black formatter on entire codebase 2026-03-11 17:07:57 -03:00
setup_wizard.py Add Claude Fable 5 across Anthropic, Bedrock, Vertex AI, and Azure AI (#30064) 2026-06-10 08:50:15 +05:30
timeout.py docs: add class docstring to _LoopWrapper (#27870) 2026-05-13 13:54:00 -07:00
utils.py fix(bedrock/converse): drop toolSpec.strict for Opus 4.7/4.8 (#31582) (#31923) 2026-07-02 21:07:31 -07:00