SPB Git

Repository Public

guardrails-approvals.md 9.3 KB 275 lines markdown

1# Guardrails and human review23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45Use guardrails for automatic checks and human review for approval decisions. Together, they define when a run should continue, pause, or stop.67- **Guardrails** validate input, output, or tool behavior automatically.8- **Human review** pauses the run so a person or policy can approve or reject a sensitive action.910## Choose the right control1112| Use case                                                                                      | Start with                  |13| --------------------------------------------------------------------------------------------- | --------------------------- |14| Block disallowed user requests before the main model runs                                     | Input guardrails            |15| Validate or redact the final output before it leaves the system                               | Output guardrails           |16| Check arguments or results around a function tool call                                        | Tool guardrails             |17| Pause before side effects like cancellations, edits, shell commands, or sensitive MCP actions | Human-in-the-loop approvals |1819## Add a blocking guardrail2021Use input guardrails when you want a fast validation step to run before the expensive or side-effecting part of the workflow starts.2223Block a request with an input guardrail2425```javascript26import { Agent, InputGuardrailTripwireTriggered, run } from "@openai/agents";27import { z } from "zod";2829const guardrailAgent = new Agent({30  name: "Homework check",31  instructions: "Detect whether the user is asking for math homework help.",32  outputType: z.object({33    isMathHomework: z.boolean(),34    reasoning: z.string(),35  }),36});3738const agent = new Agent({39  name: "Customer support",40  instructions: "Help customers with support questions.",41  inputGuardrails: [42    {43      name: "Math homework guardrail",44      runInParallel: false,45      async execute({ input, context }) {46        const result = await run(guardrailAgent, input, { context });47        return {48          outputInfo: result.finalOutput,49          tripwireTriggered: result.finalOutput?.isMathHomework === true,50        };51      },52    },53  ],54});5556try {57  await run(agent, "Can you solve 2x + 3 = 11 for me?");58} catch (error) {59  if (error instanceof InputGuardrailTripwireTriggered) {60    console.log("Guardrail blocked the request.");61  }62}63```6465```python66import asyncio6768from pydantic import BaseModel6970from agents import (71    Agent,72    GuardrailFunctionOutput,73    InputGuardrailTripwireTriggered,74    RunContextWrapper,75    Runner,76    TResponseInputItem,77    input_guardrail,78)798081class MathHomeworkOutput(BaseModel):82    is_math_homework: bool83    reasoning: str848586guardrail_agent = Agent(87    name="Homework check",88    instructions="Detect whether the user is asking for math homework help.",89    output_type=MathHomeworkOutput,90)919293@input_guardrail94async def math_guardrail(95    ctx: RunContextWrapper[None],96    agent: Agent,97    input: str | list[TResponseInputItem],98) -> GuardrailFunctionOutput:99    result = await Runner.run(guardrail_agent, input, context=ctx.context)100    return GuardrailFunctionOutput(101        output_info=result.final_output,102        tripwire_triggered=result.final_output.is_math_homework,103    )104105106agent = Agent(107    name="Customer support",108    instructions="Help customers with support questions.",109    input_guardrails=[math_guardrail],110)111112113async def main() -> None:114    try:115        await Runner.run(agent, "Can you solve 2x + 3 = 11 for me?")116    except InputGuardrailTripwireTriggered:117        print("Guardrail blocked the request.")118119120if __name__ == "__main__":121    asyncio.run(main())122```123124125Use blocking execution when the cost or risk of starting the main agent is too high. Use parallel guardrails when lower latency matters more than avoiding speculative work.126127## Pause for human review128129Approvals are the human-in-the-loop path for tool calls. The model can still decide that an action is needed, but the run pauses until you approve or reject it.130131Pause for approval before a sensitive action132133```javascript134import { Agent, run, tool } from "@openai/agents";135import { z } from "zod";136137const cancelOrder = tool({138  name: "cancel_order",139  description: "Cancel a customer order.",140  parameters: z.object({ orderId: z.number() }),141  needsApproval: true,142  async execute({ orderId }) {143    return `Cancelled order ${orderId}`;144  },145});146147const agent = new Agent({148  name: "Support agent",149  instructions: "Handle support requests and ask for approval when needed.",150  tools: [cancelOrder],151});152153let result = await run(agent, "Cancel order 123.");154155if (result.interruptions?.length) {156  const state = result.state;157  for (const interruption of result.interruptions) {158    state.approve(interruption);159  }160  result = await run(agent, state);161}162163console.log(result.finalOutput);164```165166```python167import asyncio168169from agents import Agent, Runner, function_tool170171172@function_tool(needs_approval=True)173async def cancel_order(order_id: int) -> str:174    return f"Cancelled order {order_id}"175176177agent = Agent(178    name="Support agent",179    instructions="Handle support requests and ask for approval when needed.",180    tools=[cancel_order],181)182183184async def main() -> None:185    result = await Runner.run(agent, "Cancel order 123.")186187    if result.interruptions:188        state = result.to_state()189        for interruption in result.interruptions:190            state.approve(interruption)191        result = await Runner.run(agent, state)192193    print(result.final_output)194195196if __name__ == "__main__":197    asyncio.run(main())198```199200201This same interruption pattern applies even when the approving tool lives deeper in the workflow, such as after a handoff or inside a nested `agent.asTool()` in TypeScript or `agent.as_tool()` in Python call.202203## Approval lifecycle204205When a tool call needs review, the SDK follows the same pattern every time:2062071. The run records an approval interruption instead of executing the tool.2082. The result returns `interruptions` plus a resumable `state`.2093. Your application approves or rejects the pending items.2104. You resume the same run from `state` instead of starting a new user turn.211212If the review might take time, serialize `state`, store it, and resume later. That's still the same run.213214## Workflow boundaries matter215216Agent-level guardrails don't run everywhere:217218- Input guardrails run only for the first agent in the chain.219- Output guardrails run only for the agent that produces the final output.220- Tool guardrails run on the function tools they're attached to.221222If you need checks around every custom tool call in a manager-style workflow, don't rely only on agent-level input or output guardrails. Put validation next to the tool that creates the side effect.223224## Review cybersecurity actions before execution225226For authorized cybersecurity workflows, evaluate each sensitive tool call227before it executes. Use tool guardrails and approval interruptions to enforce228the written engagement scope at the boundary where side effects occur:2292301. Check the proposed target, action, tool arguments, calling identity, and231   engagement window against the approved scope.2322. Give a separate policy component or reviewer the exact proposed action and233   only the context needed to evaluate it.2343. Deny out-of-scope hosts, credential theft, persistence, data exfiltration,235   destructive changes, production access, and attempts to bypass policy.2364. Pause ambiguous or high-risk actions for explicit human approval before the237   tool runs.2385. Enforce independent filesystem, network, identity, and project boundaries,239   record decisions and execution outcomes, and fail closed if review times out240   or becomes unavailable.241242Responses API and Agents SDK applications don't automatically inherit243[Codex Auto-review](https://developers.openai.com/codex/sandboxing/auto-review). Add review and enforcement244to your own harness. The245[open-source Codex reviewer policy](https://github.com/openai/codex/blob/main/codex-rs/core/src/guardian/policy.md)246illustrates one approach. Review [Models and Trusted Access](https://developers.openai.com/codex/cyber-safety)247for approved model access and [Recommended configuration](https://developers.openai.com/codex/cyber-safety/recommended-configuration)248for safe engagement setup.249250## Streaming and delayed review use the same state model251252Streaming doesn't create a separate approval system. If a streamed run pauses, wait for it to settle, inspect `interruptions`, resolve the approvals, and resume from the same `state`. If the review happens later, store the serialized state and continue the same run when the decision arrives.253254## Next steps255256Once the control boundaries are clear, continue with the guide that covers the runtime or tool surface around them.257258259260  [Running agents261262263264        See how interruptions and resumptions fit into the runtime loop.](https://developers.openai.com/api/docs/guides/agents/running-agents)265  [Results and state266267268269        Learn which result surfaces paused runs return to your application.](https://developers.openai.com/api/docs/guides/agents/results)270  [Using tools271272273274        Decide which tool surfaces need validation or approval before side effects275      happen.](https://developers.openai.com/api/docs/guides/tools#usage-in-the-agents-sdk)
Files main
Menu

Theme