--- 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.