Hey everyone,
I’m using a LangGraph prebuilt supervisor agent with AWS Bedrock and Bedrock Guardrails.
While testing my agent, I noticed an issue — once I trigger a Bedrock guardrail, my supervisor agent rejects everything I say afterward, even if the following messages are appropriate.
After debugging, I found that both the inappropriate human message and the guardrail AI message remain stored in the supervisor agent’s state.
To work around this, I implemented the following function as a pre_model_hook
for my supervisor agent to remove those messages and “reset” the graph state without creating a new thread:
def remove_guardrails_messages(state):
messages = state.get("messages", [])
if not messages:
return {}
removed_ids = []
for i in reversed(range(len(messages))):
msg = messages[i]
if not removed_ids and isinstance(msg, AIMessage):
stop_reason = getattr(msg, "response_metadata", {}).get("stopReason")
if stop_reason == "guardrail_intervened":
removed_ids = [msg.id]
elif removed_ids and isinstance(msg, HumanMessage):
removed_ids += [msg.id]
break
if removed_ids:
logger.debug(f"Removing guardrail AI/Human messages: {removed_ids}")
return {"messages": [RemoveMessage(id=i) for i in removed_ids]}
else:
return {}
However, I found that the removed messages still get passed to the sub-agent, which then triggers its own guardrail, preventing it from responding correctly.
My Questions
-
I use
RemoveMessage(id)
in thepre_model_hook
to remove the previous conversation that triggered the guardrails, but I notice those messages are still being passed into the sub-agent’s state. Why is that happening? Do the supervisor agent and its sub-agents not share the samestate
? -
How can I ensure that once I modify the supervisor’s state, those changes are properly reflected (or passed down) to the sub-agent?
-
Is there a recommended way to clear or sanitize guardrail-triggering messages before sub-agents receive them?
Any insights or best practices for handling this in LangGraph would be greatly appreciated