Veto TypeScript SDK

Native TypeScript SDK for AI agent authorization. Works with OpenAI, Anthropic, Vercel AI SDK, LangChain.js, and MCP. Type-safe, zero dependencies in local mode, two lines of code to add runtime guardrails.

TypeScript AI agent guardrails with veto-sdk

The Veto TypeScript SDK provides runtime authorization for AI agents built in JavaScript or TypeScript. It intercepts tool calls before execution, validates them against your policies, and enforces allow/deny/approval decisions. Works with OpenAI, Anthropic, Vercel AI SDK, LangChain.js, MCP, and custom agents. Runs in Node.js, Deno, Bun, Cloudflare Workers, and Vercel Edge.

Installation

Terminalbash
npm install veto-sdk

Also available via pnpm add veto-sdk, yarn add veto-sdk, or bun add veto-sdk. Zero runtime dependencies in local mode. Cloud mode requires network access.

Quick start

The protect function wraps any tool definition and returns a guarded version with identical types. The wrapped tools are drop-in replacements.

Basic usagetypescript
import { protect } from 'veto-sdk';

const tools = [
  {
    name: 'transfer_funds',
    description: 'Transfer money between accounts',
    parameters: {
      type: 'object',
      properties: {
        amount: { type: 'number' },
        recipient: { type: 'string' },
      },
      required: ['amount', 'recipient'],
    },
    execute: async (args: { amount: number; recipient: string }) => {
      // Your transfer logic
      return { success: true, txId: 'tx_...' };
    },
  },
];

// Add guardrails in one line
const safeTools = await protect(tools);

OpenAI integration

Wrap OpenAI function calling tools directly. The SDK understands OpenAI's tool format and returns compatible definitions.

OpenAI function calling with Vetotypescript
import OpenAI from 'openai';
import { protect } from 'veto-sdk';

const client = new OpenAI();

const tools = await protect([
  {
    type: 'function',
    function: {
      name: 'search_database',
      description: 'Query the customer database',
      parameters: {
        type: 'object',
        properties: {
          query: { type: 'string' },
          include_pii: { type: 'boolean' },
        },
        required: ['query'],
      },
    },
  },
  {
    type: 'function',
    function: {
      name: 'send_notification',
      description: 'Send a push notification to a user',
      parameters: {
        type: 'object',
        properties: {
          user_id: { type: 'string' },
          message: { type: 'string' },
        },
        required: ['user_id', 'message'],
      },
    },
  },
]);

const response = await client.chat.completions.create({
  model: 'gpt-5.4',
  messages: [{ role: 'user', content: 'Look up order #4521 and notify the customer' }],
  tools,
});

Anthropic Claude integration

Works with Anthropic's tool use format. Wrap tool definitions before passing them to Claude. The SDK handles the format differences between providers.

Claude tool use with Vetotypescript
import Anthropic from '@anthropic-ai/sdk';
import { protect } from 'veto-sdk';

const client = new Anthropic();

const tools = await protect([
  {
    name: 'execute_sql',
    description: 'Run a SQL query against the database',
    input_schema: {
      type: 'object',
      properties: {
        query: { type: 'string', description: 'SQL query to execute' },
        database: { type: 'string', enum: ['analytics', 'production'] },
      },
      required: ['query', 'database'],
    },
  },
]);

const response = await client.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Get last month revenue from analytics' }],
  tools,
});

// Handle tool use blocks
for (const block of response.content) {
  if (block.type === 'tool_use') {
    // Veto already validated this call. Execute safely.
    const result = await executeQuery(block.input);
  }
}

Vercel AI SDK integration

Use veto.guard() inside Vercel AI tool execute functions for pre-flight validation. Works with streaming responses and all Vercel AI providers.

Vercel AI SDK with Veto guardtypescript
import { openai } from '@ai-sdk/openai';
import { generateText, tool } from 'ai';
import { Veto } from 'veto-sdk';
import { z } from 'zod';

const veto = await Veto.init();

const result = await generateText({
  model: openai('gpt-5.4'),
  tools: {
    weather: tool({
      description: 'Get weather for a location',
      parameters: z.object({
        location: z.string(),
      }),
      execute: async ({ location }) => {
        // Pre-flight check before execution
        const decision = await veto.guard('weather', { location });
        if (decision.decision === 'deny') {
          return { error: decision.reason };
        }
        return fetchWeather(location);
      },
    }),
    sendEmail: tool({
      description: 'Send an email',
      parameters: z.object({
        to: z.string().email(),
        subject: z.string(),
        body: z.string(),
      }),
      execute: async (args) => {
        const decision = await veto.guard('sendEmail', args);
        if (decision.decision === 'deny') {
          return { error: decision.reason };
        }
        return sendEmail(args);
      },
    }),
  },
  prompt: 'Check weather in NYC and email the report to team@company.com',
});

Initialization modes

The SDK supports multiple initialization patterns depending on your deployment needs.

Local mode (default)

No API key required. Policies loaded from your local ./veto config directory.

Local modetypescript
import { Veto } from 'veto-sdk';

// Local mode: no API key, policies from ./veto directory
const veto = await Veto.init();
const safeTools = veto.wrap(tools);

Cloud mode

Policies managed in the Veto dashboard. Supports human-in-the-loop approvals, team collaboration, and real-time policy updates.

Cloud modetypescript
import { Veto } from 'veto-sdk';

// Cloud mode: dashboard-managed policies, approval workflows
const veto = await Veto.init({
  apiKey: 'veto_...',
  onApprovalRequired: (context, approvalId) => {
    console.log(`Tool "${context.toolName}" needs approval (id: ${approvalId})`);
    // Notify Slack, email, or in-app
  },
});

const safeTools = veto.wrap(tools);

Policy packs

Pre-built policy packs for common use cases. Start with sensible defaults, customize as needed.

Policy packstypescript
import { protect } from 'veto-sdk';

// Financial transactions with built-in limits
const safeTools = await protect(tools, { pack: 'financial' });

// Browser automation guardrails
const safeBrowserTools = await protect(browserTools, { pack: 'browser' });

// File system operations
const safeFileTools = await protect(fileTools, { pack: 'filesystem' });

Operating modes

Control how the SDK handles policy violations during development and rollout.

Operating modestypescript
import { protect } from 'veto-sdk';

// strict (default) - Block violations, throw ToolCallDeniedError
const strict = await protect(tools, { mode: 'strict' });

// log - Allow execution but log violations for monitoring
const logging = await protect(tools, { mode: 'log' });

// shadow - Allow, log, and track what would have been blocked
const shadow = await protect(tools, { mode: 'shadow' });

Standalone validation

Use guard to validate tool calls without wrapping. Returns a decision object for conditional logic, custom workflows, or pre-flight checks.

Standalone guardtypescript
import { Veto } from 'veto-sdk';

const veto = await Veto.init();

// Pre-flight validation without wrapping
const result = await veto.guard('transfer_funds', {
  amount: 25000,
  recipient: 'vendor-123',
});

if (result.decision === 'deny') {
  console.log('Blocked:', result.reason);
  console.log('Rule:', result.ruleId);
  console.log('Severity:', result.severity);
}

if (result.decision === 'require_approval') {
  console.log('Needs approval:', result.approvalId);
  // Poll or webhook for approval status
}

Error handling

In strict mode, blocked tool calls throw typed errors you can catch and handle. Return the error to the LLM so it can retry with compliant parameters.

Error handlingtypescript
import { ToolCallDeniedError, BudgetExceededError } from 'veto-sdk';

try {
  await safeTools[0].execute({ amount: 50000, recipient: '...' });
} catch (error) {
  if (error instanceof ToolCallDeniedError) {
    console.log('Tool:', error.toolName);
    console.log('Reason:', error.reason);
    console.log('Rule:', error.ruleId);
    // Return error to the LLM so it can retry with different params
  }

  if (error instanceof BudgetExceededError) {
    console.log('Budget:', error.spent, '/', error.limit);
    // Agent should stop spending operations
  }
}

Edge runtime support

The SDK uses standard Web APIs and works in any JavaScript runtime. Deploy guarded agents to Cloudflare Workers, Vercel Edge Functions, Deno Deploy, or Bun.

Cloudflare Workertypescript
// Works in Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge
import { protect } from 'veto-sdk';

export default {
  async fetch(request: Request): Promise<Response> {
    const safeTools = await protect(myTools);

    // Process the request with guarded tools
    const result = await runAgent(safeTools, request);
    return new Response(JSON.stringify(result));
  },
};

Framework integrations

First-class integrations with popular TypeScript agent frameworks.

Features

Type-safe

Full TypeScript types. Wrapped tools have identical signatures to originals.

Zero dependencies

Local mode has no runtime dependencies. Cloud mode adds a single HTTP client.

Deterministic local

Policies evaluate locally with no network latency. Sub-millisecond overhead.

Universal runtime

Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge. Standard Web APIs.

Frequently asked questions

How do I add guardrails to existing TypeScript agents?
Install veto-sdk, then wrap your tools with protect() or Veto.init().wrap(). The wrapped tools have identical types and are drop-in compatible. No changes to your agent logic required.
Can I use veto-sdk without an API key?
Yes. Local mode requires no API key. Policies are loaded from your ./veto config directory. Cloud mode with an API key enables team collaboration, dashboard management, and human-in-the-loop approvals.
Does the SDK work with streaming responses?
Yes. Tool calls are validated before execution, not during streaming. The SDK is compatible with OpenAI streaming, Anthropic streaming, and Vercel AI's streamText/streamObject patterns.
How do I test guardrails in development?
Use shadow mode to log violations without blocking. Tools execute normally while you collect data on what would have been denied. Switch to strict mode when ready to enforce in production.
What runtimes are supported?
Node.js 18+, Deno, Bun, Cloudflare Workers, Vercel Edge Functions, and any runtime supporting standard Web APIs (fetch, crypto). The SDK has zero Node.js-specific dependencies.

Related

Add guardrails to your TypeScript agent in minutes.