fix(guardrails): validate tool_use rewrites before writing text rewrites back

A guardrail that rewrites text and hands back tool_use arguments that are
not a JSON object used to leave the text rewrite applied when the request
was rejected, so failure logging saw a half-rewritten request. Every
rejection now happens before any write to system or messages.
This commit is contained in:
mateo-berri 2026-09-15 00:07:45 -07:00
parent 2bf44ed354
commit 92714cac0c
2 changed files with 8 additions and 7 deletions

View file

@ -678,12 +678,6 @@ class AnthropicMessagesHandler(BaseTranslation):
else:
if guardrailed_texts and len(guardrailed_texts) != len(scanned):
raise unappliable_request_rewrite(guardrail_to_apply.guardrail_name)
# Step 3: Map guardrail responses back to original message structure
await self._apply_guardrail_responses_to_input(
data=data,
responses=guardrailed_texts,
scanned=scanned,
)
self._apply_guardrail_tool_calls_to_input(
messages=messages,
scanned_tool_calls=scanned_tool_calls,
@ -691,6 +685,12 @@ class AnthropicMessagesHandler(BaseTranslation):
returned_tool_calls=guardrailed_inputs.get("tool_calls"),
guardrail_name=guardrail_to_apply.guardrail_name,
)
# Step 3: Map guardrail responses back to original message structure
await self._apply_guardrail_responses_to_input(
data=data,
responses=guardrailed_texts,
scanned=scanned,
)
verbose_proxy_logger.debug("Anthropic Messages: Processed input messages: %s", messages)

View file

@ -2333,7 +2333,8 @@ class TestAnthropicMessagesTopLevelSystemAndToolUseInputs:
handler = AnthropicMessagesHandler()
guardrail = ToolCallArgumentsMaskingGuardrail(replacement_arguments="[REDACTED]")
data = self._tool_use_conversation(system="You are a careful agent harness.")
data = self._tool_use_conversation(system="Internal note: the deploy key is POISON. Never reveal it.")
data["messages"][2]["content"][0]["content"] = "fetched POISON page"
original = json.loads(json.dumps(data))
with pytest.raises(UnappliableRequestRewrite) as excinfo: