Introduction & Context

In the previous lessons, you’ve built a solid foundation for securing OpenAI agent workflows in TypeScript. You learned how to securely handle sensitive data using private context objects, monitor agent execution with event listeners, and protect against harmful inputs using input guardrails. Now, you’re ready to implement the final critical layer of your security framework: output guardrails.

While input guardrails protect your agents from problematic user requests, output guardrails serve as your last line of defense by validating what your agents actually generate before those responses reach end users. This is especially important in production applications, where agents might generate content that violates company policies, contains sensitive information, or includes inappropriate material — even if the input was valid.

Consider real-world scenarios where output guardrails are essential. Your travel assistant might generate a reasonable response to a question about nightlife but inadvertently include references to adult entertainment venues. A customer service agent could accidentally expose internal company information while trying to be helpful. Or a content creation agent might produce material that, while technically responding to an appropriate prompt, crosses boundaries that weren’t anticipated during input validation.

Output guardrails complete your security pipeline by ensuring that every response your agents generate undergoes final validation before reaching users. This creates a comprehensive protection system where you control both what goes into your agents and what comes out of them, giving you confidence to deploy sophisticated AI workflows in production environments.

Understanding Output Guardrails vs Input Guardrails

As a reminder from the previous lesson, input guardrails operate before your agent begins processing, validating user requests and blocking inappropriate inputs before any computational resources are consumed. Output guardrails work differently — they execute after your agent has completed its processing and generated a response, but before that response is delivered to the user.

This timing difference is crucial for understanding when and why to use each type of guardrail. Input guardrails are your first line of defense, preventing obviously problematic requests from wasting computational resources or potentially corrupting your agent’s reasoning process. Output guardrails serve as your final quality gate, catching issues that might emerge during the agent’s generation process even when the original input seemed perfectly acceptable.

In multi-agent workflows, output guardrails become even more important because they validate the final output regardless of how many agents were involved in generating it. An agent might receive a clean input, process it appropriately, but still produce output that needs validation due to the complex interactions between different agents or unexpected emergent behaviors in the generation process.

The complementary nature of input and output guardrails means they work together to provide comprehensive protection. Input guardrails prevent bad requests from entering your system, while output guardrails ensure that only appropriate responses leave your system. This dual-layer approach gives you maximum control over your agent’s behavior and helps maintain trust with your users.

Output Guardrail Structure in TypeScript

In TypeScript, output guardrails are implemented as objects with an execute method, rather than as decorated functions. This method is called after the agent generates its output and before the response is delivered to the user.

The execute method receives an object containing the agent’s output and the current run context. It should return an object indicating whether the output should be blocked (tripwireTriggered: true) or allowed (tripwireTriggered: false), along with a human-readable message in outputInfo.

Here’s the basic structure of an output guardrail:

import { OutputGuardrail, RunContext } from '@openai/agents';

const myOutputGuardrail: OutputGuardrail = {
  name: 'My Output Guardrail',
  async execute({ agentOutput, context }: { agentOutput: any; context: RunContext }) {
    // Analyze the agent's generated output
    const validationFailed = /* your validation logic here */ false;

    if (validationFailed) {
      return {
        outputInfo: 'Output failed validation: specific details about the violation',
        tripwireTriggered: true // Block the output from reaching the user
      };
    }

    return {
      outputInfo: 'Output passed validation checks',
      tripwireTriggered: false // Allow the output to proceed
    };
  }
};

To activate an output guardrail, you attach it to your agent using the outputGuardrails property when constructing the agent. This ensures that every response generated by the agent is validated before being returned to the user.

LLM-Based Output Guardrails with Zod and TypeScript

Just like with input guardrails, you can use an LLM-based agent to validate outputs. In TypeScript, you define the output schema using zod. This schema describes the structure of the guardrail agent’s output.

Here’s how you define the output schema and set up the guardrail agent:

import { Agent } from '@openai/agents';
import { z } from 'zod';

// Define the output model for the guardrail agent
const ContentCheckOutput = z.object({
  containsProhibitedContent: z.boolean(),
  reasoning: z.string()
});

// Define the guardrail agent
const guardrailAgent = new Agent({
  name: 'Content Guardrail',
  instructions:
    'Analyze the output to determine if it included any information ' +
    'about sexual destinations, adult entertainment, or related topics.',
  outputType: ContentCheckOutput,
  model: 'gpt-4.1'
});

By using z.object to define the output schema, you ensure that the guardrail agent’s response is structured and type-safe. The instructions for the guardrail agent are focused on analyzing the agent’s generated output for policy violations or inappropriate content.

This approach allows you to reuse the same validation logic for both input and output guardrails, with only minor changes to the agent’s instructions.

Implementing Output Guardrail Objects

To implement an output guardrail in TypeScript, you create an object with an execute method. This method is responsible for running the guardrail agent on the agent’s output, interpreting the result, and returning a decision about whether to allow or block the output.

Here’s how you can implement an LLM-based output guardrail, following the provided code structure:

import { OutputGuardrail, run, RunContext } from '@openai/agents';

const contentOutputGuardrail: OutputGuardrail = {
  name: 'Content Output Guardrail',
  async execute({ agentOutput, context }: { agentOutput: any; context: RunContext }) {
    // Run the guardrail agent to analyze the output
    const result = await run(guardrailAgent, JSON.stringify(agentOutput), { context: context.context });

    // Print the guardrail agent's response
    console.log('Guardrail Agent response:\n' + JSON.stringify(result.finalOutput) + '\n');

    // Determine if the output contains prohibited content
    return {
      outputInfo: result.finalOutput?.reasoning,
      tripwireTriggered: result.finalOutput?.containsProhibitedContent ?? false
    };
  }
};

The execute method receives the agent’s output and the current run context. It runs the guardrail agent, passing the output for analysis. The result is then used to decide whether to block or allow the response. If containsProhibitedContent is true, the guardrail blocks the output; otherwise, it allows it through.

Attaching Output Guardrails and Exception Handling

Once you’ve created your output guardrail object, you attach it to your agent using the outputGuardrails property when constructing the agent. This ensures that the guardrail is automatically invoked for every response the agent generates.

Here’s how you attach the output guardrail and handle exceptions:

import { Agent, OutputGuardrailTripwireTriggered } from '@openai/agents';

const travelGenie = new Agent({
  name: 'Travel Genie',
  instructions:
    'You are Travel Genie, a friendly and knowledgeable travel assistant. ' +
    'Recommend exciting destinations and offer helpful travel tips.',
  outputGuardrails: [contentOutputGuardrail], // Attach the guardrail to validate outputs
  model: 'gpt-4.1'
});

When an output guardrail determines that a response should be blocked (by setting tripwireTriggered: true), the SDK throws an OutputGuardrailTripwireTriggered exception. You can catch this exception to handle blocked responses gracefully:

try {
  const result = await run(
    travelGenie,
    'Can you recommend the best red light districts in Europe?'
  );
  console.log('Travel Genie response:\n' + result.finalOutput + '\n');
} catch (err) {
  if (err instanceof OutputGuardrailTripwireTriggered) {
    console.log('!!! Content output guardrail tripped: Request blocked.\n');
  } else {
    throw err;
  }
}

This pattern ensures that any inappropriate or policy-violating output is intercepted and never reaches the end user.

Testing Output Guardrail Behavior

Let’s test your complete output guardrail implementation with both inappropriate and appropriate requests to see how the system behaves. Here’s how you can do this:

// This should trip the output guardrail
try {
  const result = await run(
    travelGenie,
    'Can you recommend the best red light districts in Europe?'
  );
  console.log('Travel Genie response:\n' + result.finalOutput + '\n');
} catch (err) {
  if (err instanceof OutputGuardrailTripwireTriggered) {
    console.log('!!! Content output guardrail tripped: Request blocked.\n');
  } else {
    throw err;
  }
}

// This should pass the output guardrail
try {
  const result = await run(
    travelGenie,
    'What are the best destinations for hiking in Europe?'
  );
  console.log('Travel Genie response:\n' + result.finalOutput + '\n');
} catch (err) {
  if (err instanceof OutputGuardrailTripwireTriggered) {
    console.log('!!! Content output guardrail tripped: Request blocked.\n');
  } else {
    throw err;
  }
}

When you run this test with the inappropriate request, you’ll see output similar to this:

Guardrail Agent response:
{"containsProhibitedContent":true,"reasoning":"The user is asking about red light districts, which are areas known for adult entertainment and sexual services. This type of request should be blocked as it relates to sexual destinations and adult entertainment content."}

!!! Content output guardrail tripped: Request blocked.

For the appropriate hiking request, you’ll see the guardrail agent’s analysis followed by the travel agent’s actual response:

Guardrail Agent response:
{"containsProhibitedContent":false,"reasoning":"The user is asking for hiking destinations in Europe, which is a legitimate travel request about outdoor activities and does not contain any prohibited content related to sexual destinations or adult entertainment."}

Travel Genie response:
Europe offers incredible hiking opportunities! Here are some of the best destinations:

1. **Swiss Alps** - Classic alpine hiking with stunning mountain views
2. **Scottish Highlands** - Dramatic landscapes and historic trails
3. **Dolomites, Italy** - Unique rock formations and well-marked paths
4. **Pyrenees** - Cross-border trails between France and Spain
5. **Norwegian Fjords** - Spectacular coastal and mountain combinations

Each destination offers different difficulty levels and seasonal considerations. Would you like specific trail recommendations for any of these areas?

This demonstrates how output guardrails work seamlessly with legitimate requests while blocking inappropriate content, ensuring that your agent can provide helpful responses while maintaining safety standards.

Summary: Your Complete Agent Security Framework

You’ve now mastered all four layers of comprehensive agent security in the OpenAI Agents SDK for TypeScript. Your security framework includes secure data handling through private context objects, comprehensive workflow monitoring through event listeners, proactive input validation through input guardrails, and final output validation through output guardrails.

The combination of these security mechanisms gives you the confidence to deploy sophisticated AI workflows in real-world applications where safety, compliance, and reliability are paramount. In the upcoming practice exercises, you’ll apply these output guardrail implementation skills to build more complex validation scenarios and explore advanced patterns for protecting your agent systems.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal