Policy-Based Tool Approvals

Purpose and Scope

Policy-based tool approvals are for teams that need authorization rules around agent tools to be understandable, reviewable, and testable outside the application code that defines the agent. The documented feature uses @ai-sdk/policy-opa to move approval logic into Open Policy Agent policies written in .rego, while still relying on the AI SDK public toolApproval callback. That distinction matters: the agent, model, tools, and stream protocol do not become a separate policy system. Instead, policy evaluation becomes the decision layer that runs before tool dispatch and returns the same approval outcomes the rest of the SDK already understands.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

Use this approach when tool authorization is not just a local programming convenience. A code callback is often enough for a prototype or a small internal tool, but policy-as-code is better when security, compliance, operations, or finance teams need to inspect and test the rule set. The docs call out three motivations: rules can be a separate artifact, they can be tested in continuous integration with opa test, and they can be edited without a full application deploy when evaluated by a running OPA instance. The result is a cleaner separation between agent behavior and organizational authorization policy.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

Relevant Source Files

  • content/docs/03-agents/06-policy-tool-approvals.mdx - Defines the reader-facing policy approval guide, including the motivation for @ai-sdk/policy-opa, install commands, decision mapping, deterministic-policy guidance, and the quick-start pattern.

Core Concepts

The core concept is the tool boundary. A model may decide that it wants to call a tool, but the SDK can still evaluate whether that call should execute, be denied automatically, or pause for human review. The policy receives structured input, including the current tool name and arguments, and the documentation notes that it also receives messages, which represent the full model and tool-call history for the run. That history-aware input lets policies enforce run-level constraints, such as limiting repeated writes, blocking a second irreversible action, or tracking accumulated usage across multiple steps.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

OPA is strongest when the rule can be expressed as a deterministic check over structured fields. Good examples include permissions, roles, numeric thresholds, path allowlists, tenant boundaries, time windows, and counts of prior actions. Weak examples include judgments about free-form meaning, such as toxicity or vague content quality, because those decisions are semantic and easier to bypass. The documentation’s rule of thumb is practical: if a rule can point to a field in the policy input and compare it exactly, it belongs in policy. If it depends on interpreting meaning, use moderation or classification first, then gate the resulting structured signal.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

Installation and Backends

The package is installed separately from the main SDK package because it is an optional policy adapter rather than a required agent runtime dependency. The documented installation adds @ai-sdk/policy-opa, then asks the application to choose one or both OPA backends. The WASM backend evaluates compiled policy in-process, which is useful when the application should not depend on a separate policy service at runtime. The HTTP backend talks to a running OPA server, which can fit environments where policy owners want to update or serve policies independently from the agent deployment.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

pnpm add @ai-sdk/policy-opa
pnpm add @open-policy-agent/opa-wasm
pnpm add @open-policy-agent/opa

The documentation explicitly says the OPA backends are optional peer dependencies and that only the backend imported by the application is loaded. That design keeps the adapter flexible for different deployment models. A local command-line or serverless workload might prefer the in-process WASM client because it packages evaluation with the application. A larger platform may prefer an OPA server so that policy updates can be managed as an operational asset. In both cases, the public AI SDK surface remains the same: create a policy-backed toolApproval configuration, then pass it into generation or agent execution.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

Decision Mapping and Execution Flow

Policy results map onto the standard approval states used by AI SDK tool approvals. The guide describes three explicit policy decisions: allow, deny, and requires-approval. Allow runs the tool. Deny produces a denied result that the model can reason about without involving a human. Requires approval pauses execution and waits for a human tool-approval-response. If no matching policy rule is found, the result normalizes to not-applicable, which the SDK treats as allow. For stricter systems, the docs recommend adding a default deny decision in the policy itself.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

A useful mental model is that the policy is consulted before every tool dispatch. Without policy, a model calls a tool and the tool executes if it has an execution function and normal SDK conditions are met. With policy, there is an inserted authorization step between the model’s requested tool call and the tool implementation. That step can approve, deny, or request a human decision while preserving the same wire flow as built-in approvals: tool-approval-request and tool-approval-response. This is why policy approvals compose with existing agent and UI approval flows instead of requiring a custom transport.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

API Usage Pattern

The quick-start pattern has three parts. First, load or connect to the OPA policy backend. In the documented WASM path, the application reads a compiled policy bundle and creates a policy client with wasmPolicyClient. Second, build the toolApproval configuration by calling opaPolicy with that client and the policy decision path, such as agent/call/decision. Third, pass the resulting configuration into a normal model call, alongside the model, tools, and prompt. The important point is that generation code stays recognizable; the policy adapter supplies authorization behavior through the existing approval hook.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { opaPolicy, wasmPolicyClient } from '@ai-sdk/policy-opa';
import { readFile } from 'node:fs/promises';
 
const wasm = await readFile('./policy.wasm');
const client = await wasmPolicyClient({ wasm });
 
const toolApproval = opaPolicy({
  client,
  path: 'agent/call/decision',
});
 
const result = await generateText({
  model: anthropic('claude-sonnet-4-5'),
  tools: { git, bash, queryLogs },
  toolApproval,
  prompt: 'find the failing test and push the fix',
});

Design Guidance and Edge Cases

Default behavior is an important edge case. Because unmatched rules become not-applicable and are treated as allow, teams with sensitive tools should not assume that a missing rule is safe. The docs explicitly mention adding a default deny decision when the intended posture is deny unless allowed. This is especially relevant for tools that modify data, spend money, call external systems, access private resources, or perform irreversible operations. A practical rollout is to begin by inventorying tool names and argument schemas, then write policies for high-risk tools first, then decide whether the remaining surface should default allow or default deny.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

Policy should also be scoped to what the SDK actually executes. The feature sits on top of toolApproval, so it applies at the AI SDK tool boundary. Provider-executed tools are a separate category in the broader tool approval documentation, and they do not use SDK-side approval callbacks. For applications mixing local tools, provider-defined tools, and human approval UI, document which boundary owns each decision. A policy rule can be excellent for local execution, shell access, database mutation, or business workflows, but it should not be treated as a universal guard for actions that bypass the SDK tool dispatcher.

Sources: content/docs/03-agents/06-policy-tool-approvals.mdx

Next Steps

After adopting policy-based approvals, write tests for the Rego rules independently from the application, then exercise the agent path with representative tool calls. Review whether each rule is deterministic, whether the policy should default deny, and whether human approval responses need additional protection in the surrounding application. Read the general Tool Approvals page next to understand the human-in-the-loop statuses and security model, then return to this page when the approval function grows into a policy artifact that needs review, CI testing, or operational updates outside normal code deploys.