TypeScript SDK for runtime authorization

Wrap TypeScript tools with Veto. Every governed call is checked before execution, then allowed, sent to review, or denied.

TypeScript runtime authorization with veto-sdk

The Veto TypeScript SDK adds runtime authorization for agents built in JavaScript or TypeScript. It intercepts tool calls before execution, validates them against your policies, and returns allow, review, or deny 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

Terminal
npm install veto-sdk

Also available via pnpm add veto-sdk, yarn add veto-sdk, or bun add veto-sdk. Set VETO_API_KEY for cloud guard checks and rule workflows.

Install the SDK

The protect function wraps supported tool definitions and returns a guarded version with matching types. The governed tools are drop-in replacements.

Basic usage
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_000123' };
    },
  },
];

// Add an explicit authorization check
const guardedTools = await protect(tools);

OpenAI integration

Convert Veto tool definitions to OpenAI function tools, then validate each proposed tool call before execution.

OpenAI function calling with Veto
import OpenAI from 'openai';
import { Veto, fromOpenAIToolCall, toOpenAI } from 'veto-sdk';

const client = new OpenAI();
const veto = await Veto.init();

const toolDefinitions = [
  {
    name: 'search_database',
    description: 'Query the customer database',
    inputSchema: {
      type: 'object',
      properties: {
        query: { type: 'string' },
        include_pii: { type: 'boolean' },
      },
      required: ['query'],
    },
  },
];

const response = await client.chat.completions.create({
  model: process.env.OPENAI_MODEL!,
  messages: [{ role: 'user', content: 'Look up order #4521 and notify the customer' }],
  tools: toolDefinitions.map(toOpenAI),
});

for (const toolCall of response.choices[0]?.message.tool_calls ?? []) {
  const call = fromOpenAIToolCall(toolCall);
  const decision = await veto.guard(call.name, call.arguments);
  if (decision.decision !== 'allow') throw new Error(decision.reason);
}

Anthropic Claude integration

Convert Veto tool definitions to Anthropic tool-use format, then validate each tool call before execution.

Claude tool use with Veto
import Anthropic from '@anthropic-ai/sdk';
import { Veto, fromAnthropicToolUse, toAnthropic } from 'veto-sdk';

const client = new Anthropic();
const veto = await Veto.init();

const toolDefinitions = [
  {
    name: 'execute_sql',
    description: 'Run a SQL query against the database',
    inputSchema: {
      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: process.env.ANTHROPIC_MODEL!,
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Get last month revenue from analytics' }],
  tools: toolDefinitions.map(toAnthropic),
});

for (const block of response.content) {
  if (block.type === 'tool_use') {
    const call = fromAnthropicToolUse(block);
    const decision = await veto.guard(call.name, call.arguments);
    if (decision.decision !== 'allow') throw new Error(decision.reason);
  }
}

Vercel AI SDK integration

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

Vercel AI SDK with Veto guard
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(process.env.OPENAI_MODEL!),
  tools: {
    weather: tool({
      description: 'Get weather for a location',
      inputSchema: 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',
      inputSchema: 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@approved.example',
});

Runtime patterns

Use cloud guard checks for production tool execution. Use local rule utilities intentionally for tests, simulations, and custom runtimes.

Cloud guard

Hosted policy management, human approvals, registered tool context, and rule-generated policy drafts.

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

const veto = await Veto.init({
  apiKey: process.env.VETO_API_KEY,
  baseUrl: process.env.VETO_API_URL,
});

const guardedTools = veto.wrap(tools);

MCP tools

MCP tools are schema-only. Guard the `callTool` forwarder before it reaches the upstream MCP server.

MCP guard
import { Veto } from 'veto-sdk';

const veto = await Veto.init();
const { tools, callTool } = veto.wrapMCPTools(mcpTools, {
  callTool: (input) => mcpClient.callTool(input),
});

await callTool({
  name: 'browser_navigate',
  arguments: { url: 'https://approved.example' },
});

Local rules utility

Import deterministic rule helpers directly when you need local simulation or custom policy evaluation.

Local rules
import { evaluateRulesLocally } from 'veto-sdk/rules';

const result = evaluateRulesLocally(rules, 'transfer_funds', {
  amount: 25000,
  recipient: 'vendor-123',
});

if (result.decision === 'deny') {
  throw new Error(result.reason ?? 'Denied by local rule');
}

Standalone validation

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

Standalone guard
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);
}

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

Error handling

Blocked governed tool calls throw typed errors you can catch and handle.

Error handling
import { ToolCallDeniedError } from 'veto-sdk';

try {
  await guardedTools[0].execute({ amount: 50000, recipient: 'vendor@approved.example' });
} catch (error) {
  if (error instanceof ToolCallDeniedError) {
    console.log('Tool:', error.toolName);
    console.log('Reason:', error.reason);
    // Return a concise denial to the agent or UI.
  }
}

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 Worker
// Works in Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge
import { protect } from 'veto-sdk';

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

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

Framework integrations

First-class integrations with popular TypeScript agent frameworks.

Features

Type-safe

Typed API surface. Wrapped tools preserve the callable shape of the originals.

Explicit cloud guard

Production wrappers call Veto Cloud before tools run and fail closed with an explicit credential error.

Local rule utilities

Deterministic helpers are available for simulations, tests, and custom runtimes.

Universal runtime

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

Frequently asked questions

How do I add runtime authorization to existing TypeScript agents?
Install veto-sdk, then wrap your tools with protect() or Veto.init().wrap(). The governed tools have identical types and are type-compatible at the tool boundary. Wire the governed tools at the dispatch point.
Can I use veto-sdk without an API key?
The production wrappers require VETO_API_KEY. The package also exports local rule utilities from veto-sdk/rules for tests and custom runtimes.
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 policy enforcement in development?
Use Veto Cloud test projects or the local rule utilities exported from veto-sdk/rules. Use local rule utilities or a test project for shadow-style testing; check the SDK README for current mode support.
What runtimes are supported?
Node.js 18+ and standard Web API runtimes supported by the current SDK, and any runtime supporting standard Web APIs (fetch, crypto). The SDK has no Node-only dependency in the governed wrapper path.

Related

Wrap one TypeScript tool path and inspect the decision record.