fix(logging): don't leak redacted reasoning via provider_specific_fields (#47398)

* fix: prevent reasoning field from being copied into provider_specific_fields

* fix: ensure reasoning field in provider_specific_fields is redacted

* fix: redact reasoning_details in provider_specific_fields

* fix: format redact_messages.py

* ci: retrigger

* ci: retrigger

* ci: retrigger

* fix(logging): keep provider_specific_fields.reasoning in chat responses

Redaction already blanks provider_specific_fields.reasoning and reasoning_details in logs, so chat responses can keep the field as they did before.

* fix(logging): redact reasoning_text, citations, and web search results in provider_specific_fields

* fix(logging): redact vector store, RAG, Groq tool, Databricks agent and tool search results in provider_specific_fields

* fix(logging): redact Bedrock streamed reasoningContent and file annotations in provider_specific_fields

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
This commit is contained in:
Jon Richmond 2026-11-04 13:31:09 -05:00 • committed by GitHub
parent b18188dee2
commit 5bc7f6434d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 0 deletions

View file

@ -272,15 +272,31 @@ def _redacted_provider_specific_fields(fields: Mapping[str, object]) -> Mapping[
return {
**fields,
**({"reasoning_content": REDACTED_BY_LITELLM} if fields.get("reasoning_content") is not None else {}),
**({"reasoning": REDACTED_BY_LITELLM} if fields.get("reasoning") is not None else {}),
**({"reasoning_text": REDACTED_BY_LITELLM} if fields.get("reasoning_text") is not None else {}),
**{
key: None
for key in (
"thinking_blocks",
"reasoningContentBlocks",
"reasoningContent",
"annotations",
"citations",
"citation",
"citationsContent",
"compaction_blocks",
"compaction_start",
"compaction_delta",
"reasoning_details",
"web_search_calls",
"web_search_results",
"tool_results",
"code_interpreter_results",
"search_results",
"rerank_results",
"executed_tools",
"custom_outputs",
"tool_search_items",
"token_ids",
)
if key in fields

View file

@ -54,9 +54,25 @@ SIGNATURE: Final = "opaque-thought-signature"
def _provider_fields() -> dict[str, object]:
return {
"reasoning_content": SECRET,
"reasoning": SECRET,
"reasoning_text": SECRET,
"reasoning_details": [{"type": "reasoning.text", "text": SECRET, "index": 0, "format": "unknown"}],
"thinking_blocks": [{"type": "thinking", "thinking": SECRET}],
"reasoningContentBlocks": [{"reasoningText": {"text": SECRET}}],
"reasoningContent": {"reasoningText": {"text": SECRET}},
"annotations": [{"type": "file", "file": {"name": "notes.pdf", "content": [{"type": "text", "text": SECRET}]}}],
"citations": [{"cited_text": SECRET}],
"citationsContent": [{"citations": [{"location": {}}], "content": [{"text": SECRET}]}],
"citation": {"type": "char_location", "cited_text": SECRET},
"web_search_calls": [{"type": "web_search_call", "action": {"type": "search", "query": SECRET}}],
"web_search_results": [{"type": "web_search_tool_result", "content": [{"title": SECRET}]}],
"tool_results": [{"type": "web_fetch_tool_result", "content": {"text": SECRET}}],
"code_interpreter_results": [{"stdout": SECRET}],
"search_results": [{"object": "vector_store.search_results.page", "data": [{"content": [{"text": SECRET}]}]}],
"rerank_results": {"results": [{"document": {"text": SECRET}}]},
"executed_tools": [{"type": "search", "search_results": {"results": [{"content": SECRET}]}}],
"custom_outputs": {"answer": SECRET},
"tool_search_items": [{"type": "tool_search_output", "tools": [{"description": SECRET}]}],
"compaction_blocks": [{"type": "compaction", "content": SECRET, "signature": "compaction-signature"}],
"compaction_start": {"type": "compaction", "content": SECRET},
"compaction_delta": {"type": "compaction_delta", "content": SECRET},