From 09db332fb73d141895f74e23e4c554bb0fb6d632 Mon Sep 17 00:00:00 2001 From: kerry Date: Tue, 27 Oct 2026 16:58:39 +0000 Subject: [PATCH] fix(bedrock): walk the guardrail trace iteratively when redacting it Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/litellm_core_utils/redact_messages.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/litellm/litellm_core_utils/redact_messages.py b/litellm/litellm_core_utils/redact_messages.py index 25e4482ab4c..548d088d833 100644 --- a/litellm/litellm_core_utils/redact_messages.py +++ b/litellm/litellm_core_utils/redact_messages.py @@ -125,15 +125,18 @@ _MATCHED_TEXT_KEYS: Final = frozenset({"match", "regex"}) _JSON_OBJECT: Final = TypeAdapter(dict[str, JsonValue]) -def _without_matched_text(node: JsonValue) -> JsonValue: - if isinstance(node, dict): - return { - key: "[REDACTED]" if key in _MATCHED_TEXT_KEYS and isinstance(value, str) else _without_matched_text(value) - for key, value in node.items() - } - if isinstance(node, list): - return [_without_matched_text(item) for item in node] - return node +def _without_matched_text(trace: Mapping[str, JsonValue]) -> Mapping[str, JsonValue]: + redacted: Final = dict(copy.deepcopy(trace)) + stack: Final[list[JsonValue]] = [redacted] # mutable-ok: iterative walk, recursive_detector bans recursion here + while stack: + node = stack.pop() + if isinstance(node, dict): + for key in _MATCHED_TEXT_KEYS & node.keys(): + node[key] = "[REDACTED]" + stack.extend(node.values()) + elif isinstance(node, list): + stack.extend(node) + return redacted def _redacted_bedrock_trace(trace: object) -> object: