Skip to main content
The Veto TypeScript SDK provides guardrails for AI agent tool calls. It intercepts and validates tool calls before execution, blocking, allowing, or routing to human approval based on your policies.

Installation

npm install veto-sdk

Quick Start

import { Veto } from 'veto-sdk';

// Initialize Veto
const veto = await Veto.init();

// Wrap your tools
const wrappedTools = veto.wrap(myTools);

// Use with your agent framework
const agent = createAgent({ tools: wrappedTools });

Core API

Veto.init()

Initialize a Veto instance by loading configuration and rules.
static async init(options?: VetoOptions): Promise<Veto>
options
VetoOptions
Optional configuration options
configDir
string
default:"./veto"
Path to the veto directory containing config and rules
mode
'strict' | 'log' | 'shadow'
default:"strict"
Operating mode:
  • strict: Block denied tool calls
  • log: Only log denials, allow execution
  • shadow: Compute decisions but never block
logLevel
'debug' | 'info' | 'warn' | 'error' | 'silent'
default:"info"
Log verbosity level
sessionId
string
Session ID for tracking (can also use VETO_SESSION_ID env var)
agentId
string
Agent ID for tracking (can also use VETO_AGENT_ID env var)
userId
string
User ID for tracking (can also use VETO_USER_ID env var)
role
string
Role for tracking (can also use VETO_ROLE env var)
validators
Array<Validator | NamedValidator>
Additional custom validators to run
apiKey
string
API key for cloud mode (can also use VETO_API_KEY env var)
endpoint
string
Cloud endpoint override for self-hosted deployments
onApprovalRequired
(context, approvalId) => void | Promise<void>
Hook called when a tool call requires human approval

Examples

const veto = await Veto.init();

veto.wrap()

Wrap an array of tools with Veto validation. Types are preserved for framework compatibility.
wrap<T>(tools: T[]): T[]
tools
T[]
required
Array of tools to wrap. Works with any tool format (LangChain, Vercel AI SDK, custom).
wrapped
T[]
Wrapped tools with validation injected. Same type as input.

Examples

import { tool } from '@langchain/core/tools';
import { Veto } from 'veto-sdk';

const tools = [
  tool(async ({ query }) => {
    return searchDatabase(query);
  }, {
    name: 'search_database',
    description: 'Search the database',
    schema: z.object({ query: z.string() })
  })
];

const veto = await Veto.init();
const wrappedTools = veto.wrap(tools);

// Use with LangChain agent
const agent = createReactAgent({ llm, tools: wrappedTools });

veto.wrapTool()

Wrap a single tool with Veto validation.
wrapTool<T>(tool: T): T
tool
T
required
Single tool to wrap
wrapped
T
Wrapped tool with validation injected
const safeTool = veto.wrapTool(myTool);

veto.wrapTools()

Alternative API that returns both definitions and implementations.
wrapTools(tools: ToolDefinition[]): WrappedTools
tools
ToolDefinition[]
required
Array of tool definitions with schemas
result
WrappedTools
Object containing definitions and implementations
definitions
ToolDefinition[]
Tool schemas to pass to AI provider
implementations
Record<string, WrappedHandler>
Handler functions keyed by tool name
const { definitions, implementations } = veto.wrapTools(myTools);

// Pass definitions to AI provider
const response = await openai.chat.completions.create({
  tools: toOpenAITools(definitions),
  messages: [...]
});

// Execute with implementations
for (const call of response.choices[0].message.tool_calls) {
  const result = await implementations[call.function.name](
    JSON.parse(call.function.arguments)
  );
}

veto.guard()

Standalone validation without execution. Useful for checking if a call would be allowed.
async guard(
  toolName: string,
  args: Record<string, unknown>,
  context?: GuardContext
): Promise<GuardResult>
toolName
string
required
Name of the tool to validate
args
Record<string, unknown>
required
Arguments to validate
context
GuardContext
Optional context for validation
sessionId
string
Session ID for this check
agentId
string
Agent ID for this check
userId
string
User ID for this check
role
string
Role for this check
result
GuardResult
decision
'allow' | 'deny' | 'require_approval'
required
Validation decision
reason
string
Human-readable reason for the decision
ruleId
string
ID of the matched rule
severity
'critical' | 'high' | 'medium' | 'low' | 'info'
Severity level from the matched rule
approvalId
string
Approval ID if decision is require_approval
shadow
boolean
Whether this was evaluated in shadow mode
const result = await veto.guard('transfer_funds', {
  amount: 5000,
  recipient: 'vendor-123'
});

if (result.decision === 'deny') {
  console.log(`Would be blocked: ${result.reason}`);
}

History & Export

veto.getHistoryStats()

Get statistics about tool call history.
getHistoryStats(): HistoryStats
stats
HistoryStats
totalCalls
number
Total number of tool calls validated
allowedCalls
number
Number of allowed calls
deniedCalls
number
Number of denied calls
callsByTool
Record<string, number>
Breakdown by tool name
const stats = veto.getHistoryStats();
console.log(`Blocked ${stats.deniedCalls} out of ${stats.totalCalls} calls`);

veto.clearHistory()

Clear the call history.
clearHistory(): void

veto.exportDecisions()

Export decision history in JSON or CSV format.
exportDecisions(format: 'json' | 'csv'): string
format
'json' | 'csv'
required
Export format
data
string
Serialized decision history
const json = veto.exportDecisions('json');
const csv = veto.exportDecisions('csv');

fs.writeFileSync('decisions.json', json);
fs.writeFileSync('decisions.csv', csv);

protect() Function

One-step wrapper for simple use cases. Automatically detects configuration source and applies appropriate policies.
import { protect } from 'veto-sdk';

async function protect<T extends { name: string }>(
  tools: T | T[],
  options?: ProtectOptions
): Promise<T | T[]>
tools
T | T[]
required
Tool or array of tools to protect
options
ProtectOptions
configDir
string
Path to veto directory
pack
string
Built-in policy pack to apply (e.g., ‘financial’, ‘browser-automation’)
rules
Rule[]
Inline rules array
apiKey
string
Cloud API key
endpoint
string
Self-hosted endpoint
mode
'strict' | 'log' | 'shadow'
Operating mode
logLevel
LogLevel
Log level
sessionId
string
Session ID
agentId
string
Agent ID
userId
string
User ID
role
string
Role
onApprovalRequired
Function
Approval callback

Examples

import { protect } from 'veto-sdk';

const tools = [
  { name: 'transfer_funds', handler: async (args) => {...} },
  { name: 'navigate', handler: async (args) => {...} }
];

// Automatically applies @veto/financial and @veto/browser-automation packs
const protected = await protect(tools);

Framework Integrations

LangChain

import { createVetoLangChainMiddleware } from 'veto-sdk/integrations/langchain';
import { Veto } from 'veto-sdk';

const veto = await Veto.init();
const middleware = createVetoLangChainMiddleware(veto, {
  throwOnDeny: true,
  onAllow: (toolName, args) => console.log(`Allowed: ${toolName}`),
  onDeny: (toolName, args, reason) => console.log(`Denied: ${toolName}`)
});

// Use with LangChain tool nodes
const agent = createReactAgent({ llm, tools: [middleware] });

Vercel AI SDK

import { createVetoMiddleware } from 'veto-sdk/integrations/vercel-ai';
import { Veto } from 'veto-sdk';

const veto = await Veto.init();
const middleware = createVetoMiddleware(veto, {
  throwOnDeny: true,
  onAllow: (toolName, args) => console.log(`Allowed: ${toolName}`),
  onDeny: (toolName, args, reason) => console.log(`Denied: ${toolName}`)
});

const result = await generateText({
  model,
  tools,
  prompt: 'Send an email',
  experimental_providerMetadata: {
    veto: middleware
  }
});

Provider Adapters

Convert between Veto’s tool format and provider-specific formats.

OpenAI

import { toOpenAI, fromOpenAI, toOpenAITools } from 'veto-sdk';

// Convert to OpenAI format
const openaiTools = toOpenAITools(vetoDefinitions);

// Convert from OpenAI tool call
const vetoCall = fromOpenAI(openaiToolCall);

Anthropic

import { toAnthropic, fromAnthropic, toAnthropicTools } from 'veto-sdk';

const anthropicTools = toAnthropicTools(vetoDefinitions);
const vetoCall = fromAnthropic(anthropicToolUse);

Google

import { toGoogleTool, fromGoogleFunctionCall } from 'veto-sdk';

const googleTool = toGoogleTool(vetoDefinition);
const vetoCall = fromGoogleFunctionCall(googleCall);

MCP (Model Context Protocol)

import { toMCP, fromMCP, toMCPTools } from 'veto-sdk';

const mcpTools = toMCPTools(vetoDefinitions);
const vetoCall = fromMCP(mcpToolCall);

Error Handling

ToolCallDeniedError

Thrown when a tool call is blocked in strict mode.
import { ToolCallDeniedError } from 'veto-sdk';

try {
  await wrappedTool.handler({ amount: 10000 });
} catch (error) {
  if (error instanceof ToolCallDeniedError) {
    console.error(`Tool call denied: ${error.message}`);
    console.error(`Reason: ${error.reason}`);
    console.error(`Tool: ${error.toolName}`);
  }
}

ApprovalTimeoutError

Thrown when approval flow times out.
import { ApprovalTimeoutError } from 'veto-sdk';

try {
  await wrappedTool.handler(args);
} catch (error) {
  if (error instanceof ApprovalTimeoutError) {
    console.error('Approval timed out');
  }
}

Configuration Types

VetoOptions

interface VetoOptions {
  configDir?: string;
  mode?: 'strict' | 'log' | 'shadow';
  logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
  sessionId?: string;
  agentId?: string;
  userId?: string;
  role?: string;
  validators?: Array<Validator | NamedValidator>;
  apiKey?: string;
  endpoint?: string;
  kernelClient?: KernelClient;
  cloudClient?: VetoCloudClient;
  onApprovalRequired?: (context: ValidationContext, approvalId: string) => void | Promise<void>;
}

Validator

Custom validation function.
type Validator = (
  context: ValidationContext
) => ValidationResult | Promise<ValidationResult>;

interface NamedValidator {
  name: string;
  description?: string;
  validate: Validator;
  priority?: number;
  toolFilter?: string[];
}

Example

const noDeleteValidator: NamedValidator = {
  name: 'no-delete',
  description: 'Block all delete operations',
  priority: 10,
  validate: async (context) => {
    if (context.toolName.includes('delete')) {
      return {
        decision: 'deny',
        reason: 'Delete operations are not allowed'
      };
    }
    return { decision: 'allow' };
  }
};

const veto = await Veto.init({
  validators: [noDeleteValidator]
});

Advanced Features

Budget Tracking

const veto = await Veto.init({
  configDir: './veto'
});

// In veto.config.yaml:
// budget:
//   max: 100.00
//   currency: USD
//   window: session
// costs:
//   transfer_funds: 10.00
//   send_email: 0.50

const status = veto.getBudgetStatus();
console.log(`Used: ${status.used}/${status.max}`);

Event Webhooks

// In veto.config.yaml:
// events:
//   webhook:
//     url: https://example.com/veto-events
//     on:
//       - decision
//       - approval_required
//     min_severity: high
//     format: slack

const veto = await Veto.init();
// Events automatically sent to webhook

Output Validation

Validate tool outputs against patterns.
# In veto/rules/output.yaml
output_rules:
  - id: redact-ssn
    name: Redact SSNs from output
    action: redact
    tools:
      - fetch_user_data
    patterns:
      - '\d{3}-\d{2}-\d{4}'

TypeScript Types

The SDK is fully typed with TypeScript. Import types as needed:
import type {
  VetoOptions,
  VetoMode,
  ValidationMode,
  WrappedTools,
  WrappedHandler,
  GuardContext,
  GuardResult,
  ToolDefinition,
  ToolCall,
  ToolResult,
  ValidationContext,
  ValidationResult,
  ValidationDecision,
  LogLevel
} from 'veto-sdk';

Build docs developers (and LLMs) love