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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
// 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
Typed API surface. Wrapped tools preserve the callable shape of the originals.
Production wrappers call Veto Cloud before tools run and fail closed with an explicit credential error.
Deterministic helpers are available for simulations, tests, and custom runtimes.
Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge. Standard Web APIs.
Frequently asked questions
How do I add runtime 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
Wrap one TypeScript tool path and inspect the decision record.