---
title: "Input Guardrails"
description: "Validate incoming messages before they reach the agent."
icon: "arrow-right-to-bracket"
---
Input guardrails validate incoming messages **before** they reach the agent. They screen both user input and inter-agent communication.
## Simplified Input Processing
Agency Swarm automatically extracts text content from messages, so your guardrails receive clean text instead of full message objects.
## Function Signature
Each input guardrail receives three parameters:
```python
from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, input_guardrail
@input_guardrail
async def my_input_guardrail(
context: RunContextWrapper,
agent: Agent,
user_input: str | list[str],
) -> GuardrailFunctionOutput:
"""Validate user input."""
return GuardrailFunctionOutput(output_info="", tripwire_triggered=False)
```
**Parameters:**
- `context`: Run context wrapper with access to shared state.
- `agent`: The Agent instance receiving the input.
- `user_input`: Extracted text content.
- Single message: a string containing the message content.
- Multiple consecutive messages: a list of strings, one per message.
**Return:**
- `GuardrailFunctionOutput` with:
- `tripwire_triggered` (bool): `True` if validation failed.
- `output_info` (str): Guidance message returned to the caller.
File and image inputs inside messages are not passed to input guardrails.
## Input Types
When a user sends multiple messages:
```json
[
{"role": "user", "content": "Hi"},
{"role": "user", "content": "How are you?"}
]
```
Your guardrail receives:
```python
["Hi", "How are you?"]
```
This allows you to process each new input message individually or validate them as a group.
## Basic Input Guardrail
```python
from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, input_guardrail
@input_guardrail
async def require_task_prefix(
context: RunContextWrapper, agent: Agent, user_input: str | list[str]
) -> GuardrailFunctionOutput:
text = user_input if isinstance(user_input, str) else " ".join(user_input)
blocked = not text.startswith("Request:")
return GuardrailFunctionOutput(
output_info="Prefix your request with 'Request:' describing what you need." if blocked else "",
tripwire_triggered=blocked,
)
agent = Agent(
name="CustomerSupportAgent",
instructions="You are a helpful customer support agent.",
input_guardrails=[require_task_prefix],
)
```
## Practical Example: Filtering Off-Topic Questions
Use input guardrails to keep agents focused on their domain. This example delegates relevance decisions to an evaluator agent:
```python
from agency_swarm import (
Agent,
GuardrailFunctionOutput,
ModelSettings,
Reasoning,
RunContextWrapper,
input_guardrail,
)
from pydantic import BaseModel
class RelevanceDecision(BaseModel):
is_relevant: bool
reason: str
guardrail_agent = Agent(
name="GuardrailAgent",
instructions=(
"You screen incoming messages for a customer-support assistant. "
"Treat questions about account access, billing, and troubleshooting as relevant. "
"Flag any unrelated requests as irrelevant."
),
model="gpt-5.4-mini",
model_settings=ModelSettings(reasoning=Reasoning(effort="low")),
output_type=RelevanceDecision,
)
@input_guardrail
async def require_support_topic(
context: RunContextWrapper, agent: Agent, user_input: str | list[str]
) -> GuardrailFunctionOutput:
candidate = user_input if isinstance(user_input, str) else "\n".join(user_input)
guardrail_result = await guardrail_agent.get_response(candidate, context=context.context)
decision = RelevanceDecision.model_validate(guardrail_result.final_output)
if not decision.is_relevant:
return GuardrailFunctionOutput(
output_info="Only support questions are allowed. Ask about billing, account access, or troubleshooting.",
tripwire_triggered=True,
)
return GuardrailFunctionOutput(output_info="", tripwire_triggered=False)
support_agent = Agent(
name="CustomerSupportAgent",
instructions="You help customers resolve account, billing, and troubleshooting issues.",
model="gpt-5.4-mini",
input_guardrails=[require_support_topic],
raise_input_guardrail_error=False, # Non-strict mode: guidance returned as assistant message
)
```
See the full example at [`examples/guardrails_input.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/guardrails_input.py).
## Non-strict vs Strict Mode
Input guardrails support two modes that control how guidance is delivered. Use `raise_input_guardrail_error` to control this behavior.
### Non-strict Mode (Default)
**Setting:** `raise_input_guardrail_error=False`
In non-strict mode, guardrail guidance flows naturally as assistant output:
- Guidance is returned as `final_output` (non-streaming) or `message_output_created` event (streaming).
- No exception is raised.
- Guidance persists as an assistant message with `message_origin="input_guardrail_message"`.
### Strict Mode
**Setting:** `raise_input_guardrail_error=True`
In strict mode, guardrail failures abort the turn immediately:
- `InputGuardrailTripwireTriggered` is raised.
- Guidance persists as a system message with `message_origin="input_guardrail_error"`.
- The turn is aborted before the agent processes input.
- The caller must handle the exception.
```python
from agency_swarm import Agent, InputGuardrailTripwireTriggered
agent = Agent(
name="CustomerSupportAgent",
instructions="You are a helpful customer support agent.",
input_guardrails=[require_task_prefix],
raise_input_guardrail_error=True,
)
try:
response = await agency.get_response("Hello!")
except InputGuardrailTripwireTriggered as exc:
print(f"Validation failed: {exc.guardrail_result.output_info}")
```
### Comparison Table
| Mode | `raise_input_guardrail_error` | Caller sees | Persisted entry | Role | Use case |
|------|-------------------------------|-------------|-----------------|------|----------|
| **Non-strict** | `False` (default) | Guardrail text as `final_output` or streaming event | Assistant message (`input_guardrail_message`) | `assistant` | Conversational flows, helpful guidance |
| **Strict** | `True` | `InputGuardrailTripwireTriggered` exception | System message (`input_guardrail_error`) | `system` | Hard requirements, compliance, security |
**Use non-strict mode when:**
- You want a conversational user experience.
- Agents are communicating with each other internally.
- Guardrail feedback is helpful guidance, not a hard block.
- You do not want to write exception handling code.
**Use strict mode when:**
- You are enforcing non-negotiable requirements.
- Security or compliance rules must block processing.
- You want explicit control over error handling.
- The caller should know immediately that validation failed.
```text
RunItemStreamEvent(
name='message_output_created',
item=MessageOutputItem(
raw_item=ResponseOutputMessage(
id='msg_input_guardrail_guidance',
content=[ResponseOutputText(text="Prefix your request...")],
role='assistant',
status='completed'
)
)
)
```
## Guardrails in Message History
Each guardrail trigger is recorded in chat history with a guidance entry. Every entry carries `message_origin` to identify which guardrail fired.
For most use cases, `role`, `content`, and `message_origin` are enough. Additional metadata is mainly for tracing multi-agent runs.
### Message Origin Values
- `input_guardrail_message`: Input guardrail in non-strict mode.
- `input_guardrail_error`: Input guardrail in strict mode.
- `output_guardrail_error`: Output guardrail failure (always a system message).
### Persistence Behavior
| Mode | `raise_input_guardrail_error` | Streaming Event | Persisted Entry |
|------|-------------------------------|-----------------|-----------------|
| **Non-strict** | `False` (default) | `message_output_created` with guidance text | Assistant message, `message_origin="input_guardrail_message"` |
| **Strict** | `True` | `{"type": "error", "content": guidance}` | System message, `message_origin="input_guardrail_error"` |
`validation_attempts` does not apply to input guardrails. Input guardrails trigger immediately on validation failure.
### Message History After Guardrails Trip
When an input guardrail trips, agent-to-agent request messages remain in history alongside guardrail guidance. This preserves context so calling agents can adjust their approach.
Output guardrail messages also persist in history to guide retry attempts.
```json
[
{
"role": "assistant",
"content": "Please, prefix your request with 'Support:' describing what you need.",
"message_origin": "input_guardrail_message",
"agent": "CustomerSupportAgent"
},
{
"role": "assistant",
"content": "When chatting with this agent, provide your name first.",
"message_origin": "input_guardrail_message",
"agent": "DatabaseAgent",
"callerAgent": "CustomerSupportAgent"
},
{
"role": "system",
"content": "Do not include email addresses in your response.",
"message_origin": "output_guardrail_error",
"agent": "DatabaseAgent",
"callerAgent": "CustomerSupportAgent"
}
]
```
## Internal Agent Communication
For many agent-to-agent flows, non-strict mode (`raise_input_guardrail_error=False`) is easier to work with because guidance is returned inline instead of raising exceptions mid-chain.
Due to the nature of handoffs, using `Handoff` for agent-to-agent communication can bypass input guardrails between agents.