TypeScript SDK for runtime action authorization
Wrap any TypeScript tool call with Veto. Every tool call is decided in-process — allow, block, or pause for a human — under 10 ms per decision, signed on every decision.
TypeScript runtime action authorization with veto-sdk
The Veto TypeScript SDK adds runtime action authorization for agents built in JavaScript or TypeScript. It intercepts tool calls before execution, validates them against your policies, and returns allow, block, or 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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
// 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
Full TypeScript types. Wrapped tools have identical signatures to originals.
Local mode has no runtime dependencies. Cloud mode adds a single HTTP client.
Policies evaluate in-process with no network hop. Under 10 ms per decision.
Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge. Standard Web APIs.
Frequently asked questions
How do I add runtime action authorization to existing TypeScript agents?
Can I use veto-sdk without an API key?
Does the SDK work with streaming responses?
How do I test policy enforcement in development?
What runtimes are supported?
Related
Add runtime action authorization to your TypeScript agent in minutes.