> ## Documentation Index
> Fetch the complete documentation index at: https://agency-swarm.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Input Guardrails

> Validate incoming messages before they reach the agent.

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 theme={null}
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.

<Note>
  File and image inputs inside messages are not passed to input guardrails.
</Note>

## Input Types

When a user sends multiple messages:

```json theme={null}
[
  {"role": "user", "content": "Hi"},
  {"role": "user", "content": "How are you?"}
]
```

Your guardrail receives:

```python theme={null}
["Hi", "How are you?"]
```

This allows you to process each new input message individually or validate them as a group.

## Basic Input Guardrail

```python theme={null}
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 theme={null}
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.

<Accordion title="Strict mode usage example">
  ```python theme={null}
  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}")
  ```
</Accordion>

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

<Accordion title="Should I use non-strict or strict mode?">
  **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.
</Accordion>

<Accordion title="Streaming behavior example">
  ```text theme={null}
  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'
          )
      )
  )
  ```
</Accordion>

## 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"`      |

<Note>
  `validation_attempts` does not apply to input guardrails. Input guardrails trigger immediately on validation failure.
</Note>

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

<Accordion title="Example message history entries (illustrative)">
  ```json theme={null}
  [
    {
      "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"
    }
  ]
  ```
</Accordion>

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

<Warning>
  Due to the nature of handoffs, using `Handoff` for agent-to-agent communication can bypass input guardrails between agents.
</Warning>
