Output Guardrail

Reject responses under 20 characters with a post-hook that raises OutputCheckError.

output_guardrail.py
"""
Output Guardrail
=============================

Output Guardrail.
"""

from agno.agent import Agent
from agno.exceptions import CheckTrigger, OutputCheckError
from agno.models.openai import OpenAIResponses
from agno.run.agent import RunOutput


def enforce_non_empty_output(run_output: RunOutput) -> None:
    """Reject empty or very short responses."""
    content = (run_output.content or "").strip()
    if len(content) < 20:
        raise OutputCheckError(
            "Output is too short to be useful.",
            check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,
        )


# ---------------------------------------------------------------------------
# Create Agent
# ---------------------------------------------------------------------------
agent = Agent(
    name="Output-Checked Agent",
    model=OpenAIResponses(id="gpt-5.2"),
    post_hooks=[enforce_non_empty_output],
)

# ---------------------------------------------------------------------------
# Run Agent
# ---------------------------------------------------------------------------
if __name__ == "__main__":
    agent.print_response("Summarize the key ideas in clean architecture.", stream=True)

Guardrail InputCheckError and OutputCheckError become failed run outputs. They are not caught by the source's try/except around print_response() or aprint_response(). Use run() or arun() and check the returned status before displaying content or declaring success.

Add this helper after your imports:

from agno.run import RunStatus

def show_checked_response(response) -> None:
    if response.status != RunStatus.completed:
        print(f"Run rejected or failed ({response.status.value}).")
        return
    print(response.content)

A generic failed status can also indicate a provider error. Nonstream run outputs do not expose a check_trigger field. Output rejected by a post-hook can remain in the run record; this helper withholds it from the display. Streaming content may already have been emitted before the post-hook runs.

Check output before displaying it

Add the helper above and replace the original if __name__ == "__main__" block with:

if __name__ == "__main__":
    show_checked_response(agent.run('Summarize the key ideas in clean architecture.'))

This checks the final status before displaying the answer. It does not retract streamed content or erase rejected content from stored runs.

Run the Example

Set up your virtual environment

uv venv --python 3.12
source .venv/bin/activate

Install dependencies

uv pip install -U agno openai

Export your OpenAI API key

export OPENAI_API_KEY="your_openai_api_key_here"

Apply the current checks

Add the status helper and apply the replacements described above. Keep the original imports and agent definitions that the replacement uses.

Run the example

Save the adapted code as output_guardrail.py, then run:

python output_guardrail.py

Full source: cookbook/02_agents/08_guardrails/output_guardrail.py