TypeScript SDK
Full API reference for the Veto TypeScript SDK (v1.12.0).
Installation
npm install veto-sdkprotect(tools, options?)
Recommended entrypoint for new integrations.
import { protect } from 'veto-sdk';
const safeTools = await protect(tools);Single-tool overload:
const safeTool = await protect(tool);Common options:
const safeTools = await protect(tools, { pack: 'financial' });
const safeToolsCloud = await protect(tools, { apiKey: 'veto_...' });
const safeToolsLog = await protect(tools, { mode: 'log' });
const safeToolsShadow = await protect(tools, { mode: 'shadow' });Use Veto.init() directly when you need full lifecycle or initialization control.
Veto.init(options?)
Initialize Veto. Loads configuration from ./veto by default.
import { Veto } from 'veto-sdk';
// Local mode (default — no API key needed)
const vetoLocal = await Veto.init();
// Cloud mode
const vetoCloud = await Veto.init({ apiKey: "veto_..." });
// Self-hosted mode
const vetoSelfHosted = await Veto.init({ endpoint: "https://veto.internal.corp.com" });Options
| Option | Type | Default | Description |
|---|---|---|---|
configDir | string | "./veto" | Path to config directory |
mode | "strict" | "log" | "shadow" | "strict" | Operating mode |
apiKey | string | — | API key — triggers cloud mode |
endpoint | string | — | Server URL — triggers self-hosted mode |
logLevel | string | "info" | Log level |
sessionId | string | — | Session ID for tracking |
agentId | string | — | Agent ID for tracking |
validators | Validator[] | — | Additional validators |
cloudClient | VetoCloudClient | — | Injected cloud client |
onApprovalRequired | (context, approvalId) => void | — | Hook fired when a tool call needs human approval |
Mode auto-detection: endpoint > apiKey > explicit config > VETO_API_KEY env > local fallback. See SDK Modes for full precedence rules.
Operating mode precedence: explicit mode option > config mode > VETO_MODE env > strict.
veto.wrap<T>(tools: T[]): T[]
Wraps an array of tools with validation. The returned tools have identical types — fully compatible with your AI framework.
const wrappedForOpenAI = veto.wrap(openAITools);
const wrappedForAnthropic = veto.wrap(anthropicTools);
const wrappedForVercel = veto.wrap(vercelTools);
const wrappedForMCP = veto.wrap(mcpTools);Works with OpenAI function calling, Anthropic tool use, Vercel AI SDK, LangChain, MCP tools, and custom tool objects.
MCP tool definitions (using inputSchema instead of parameters) are auto-detected and converted transparently. See MCP Integration.
veto.wrapTool<T>(tool: T): T
Wraps a single tool instance.
const safeTool = veto.wrapTool(myTool);veto.guard(toolName, args, context?)
Run Veto validation as a standalone check without wrapping or executing a tool.
import { Veto, type GuardResult } from 'veto-sdk';
const veto = await Veto.init({ mode: 'log' });
const result: GuardResult = await veto.guard(
'wire_transfer',
{ amount: 25000, recipient: 'vendor-123' },
{ sessionId: 'session-42', agentId: 'agent-7' }
);
if (result.decision === 'deny') {
console.error(result.reason);
}GuardResult
type GuardResult = {
decision: 'allow' | 'deny' | 'require_approval';
reason?: string;
ruleId?: string;
severity?: 'critical' | 'high' | 'medium' | 'low' | 'info';
approvalId?: string;
shadow?: boolean;
shadowDecision?: string;
};Guard behavior (important)
- Uses the same internal
ValidationEngine.validate()pipeline as wrapped tool calls. - Records every guard check in
HistoryTracker(getHistoryStats()andexportDecisions()include guard calls). - Never throws
ToolCallDeniedError; deny outcomes are returned inGuardResult. - In log mode and shadow mode,
guard()still returns the real policy verdict (deny/require_approval) instead of converting toallow. - In shadow mode,
guard()includesshadow: trueandshadowDecisionfor non-allow outcomes. context.sessionId/context.agentIdoverride instance-level tracking values for that call only.require_approvalis returned directly for local approval rules and cloud approval flow checks.approvalIdis populated when available (for example, cloud responses withapproval_id).ruleIdandseverityare populated from validation metadata when present.
veto.getHistoryStats()
Returns statistics about validation decisions.
const stats = veto.getHistoryStats();
// { totalCalls: 5, allowedCalls: 4, deniedCalls: 1, ... }veto.clearHistory()
Resets the history statistics.
veto.clearHistory();Error handling
When a tool call is blocked in strict mode, Veto throws a ToolCallDeniedError:
import { ToolCallDeniedError } from 'veto-sdk';
try {
await wrappedTool.invoke(args);
} catch (error) {
if (error instanceof ToolCallDeniedError) {
console.log(error.toolName); // "transfer_funds"
console.log(error.reason); // "Amount 5000 exceeds limit of 1000"
console.log(error.callId); // "tc_abc123"
}
}See the Error Handling Guide for strategies on retry, graceful degradation, and framework-specific patterns (OpenAI, Anthropic, LangChain).
When a budget limit is exceeded, Veto throws a BudgetExceededError:
import { BudgetExceededError } from 'veto-sdk';
try {
await wrappedTool.invoke(args);
} catch (error) {
if (error instanceof BudgetExceededError) {
console.log(error.spent); // 48.50
console.log(error.limit); // 50
console.log(error.remaining); // 1.50
console.log(error.toolName); // "purchase"
console.log(error.toolCost); // 25
}
}When an approval poll times out, Veto throws an ApprovalTimeoutError:
import { ApprovalTimeoutError } from 'veto-sdk';
try {
await wrappedTool.invoke(args);
} catch (error) {
if (error instanceof ApprovalTimeoutError) {
console.log(error.approvalId); // "apr_abc123"
console.log(error.timeoutMs); // 300000
}
}Cloud validation and approvals
When using cloud or self-hosted mode, the SDK routes tool calls through the Veto server. The server can return three decisions: allow, deny, or require_approval.
When a tool call requires approval, the SDK:
- Fires the
onApprovalRequiredhook (so your app can show approval UI) - Polls
GET /v1/approvals/:iduntil a human approves or denies - Returns the final decision to the agent
const veto = await Veto.init({
apiKey: "veto_...",
onApprovalRequired: (context, approvalId) => {
console.log(`Tool "${context.toolName}" needs approval: ${approvalId}`);
},
});Configuration
Configure approval polling in veto.config.yaml:
validation:
mode: "cloud"
cloud:
apiKey: "veto_abc123..."
baseUrl: "https://api.runveto.com"
approval:
pollInterval: 2000 # ms between polls (default: 2000)
timeout: 300000 # max ms to wait (default: 300000 = 5 min)Approval preference cache
Cache per-tool preferences to auto-resolve approvals without server polling:
veto.setApprovalPreference('read_file', 'approve_all');
veto.setApprovalPreference('delete_database', 'deny_all');
veto.getApprovalPreference('read_file'); // "approve_all"
veto.clearApprovalPreferences('read_file');
veto.clearApprovalPreferences(); // Clear allClient-side deterministic validation
When using cloud mode, the SDK evaluates deterministic constraints locally — no network round-trip needed. Policies are fetched from the cloud and cached with a stale-while-revalidate strategy.
This is automatic. When the SDK has a cached policy for a tool and that policy uses deterministic mode without session constraints or rate limits, validation runs entirely in the SDK.
Agent calls tool
│
▼
Check PolicyCache ─── cache miss ─── POST /v1/validate (server)
│
cache hit (deterministic, no session/rate constraints)
│
▼
Run local validation
│
├── allow ─── Tool executes
│
└── deny ─── ToolCallDeniedError
│
POST /v1/decisions (fire-and-forget)Supported constraint types
| Constraint | Applies to | Description |
|---|---|---|
required | all | Argument must be present |
notNull | all | Argument cannot be null |
minimum | numbers | Lower bound (inclusive) |
maximum | numbers | Upper bound (inclusive) |
greaterThan | numbers | Lower bound (exclusive) |
lessThan | numbers | Upper bound (exclusive) |
minLength | strings | Minimum string length |
maxLength | strings | Maximum string length |
enum | strings | Allowed exact values |
regex | strings | Pattern match (max 256 chars, ReDoS-safe) |
minItems | arrays | Minimum array length |
maxItems | arrays | Maximum array length |
Policy cache
Policies are cached with two time windows:
| Window | Default | Behavior |
|---|---|---|
| Fresh | 60s | Returns cached policy immediately |
| Max age | 5min | Returns stale policy while refreshing in background |
After max age, the cache entry expires and the next validation falls through to the server.
VetoCloudClient
Standalone client for direct cloud API interaction. Used internally by Veto, but also available for advanced use cases.
import { VetoCloudClient } from 'veto-sdk';
const client = new VetoCloudClient({
config: {
apiKey: 'veto_abc123...',
baseUrl: 'https://api.runveto.com',
timeout: 30000,
retries: 2,
retryDelay: 1000,
},
logger,
});client.validate(toolName, args, context?)
Validate a tool call against cloud policies.
const result = await client.validate('send_email', {
to: 'user@example.com',
subject: 'Hello',
});
// { decision: "allow" | "deny" | "require_approval", reason?, approval_id? }client.pollApproval(approvalId, options?)
Poll an approval record until resolved or timed out.
const approval = await client.pollApproval('apr_abc123', {
pollInterval: 2000,
timeout: 300000,
});
// { id, toolName, status: "approved" | "denied" | "expired", resolvedBy? }client.fetchPolicy(toolName)
Fetch a tool's policy from the server.
const policy = await client.fetchPolicy('send_email');
// { toolName, mode, constraints, sessionConstraints?, rateLimits?, version }client.logDecision(request)
Log a client-side validation decision to the server. Fire-and-forget.
client.logDecision({
tool_name: 'send_email',
arguments: { to: 'user@example.com' },
decision: 'allow',
mode: 'deterministic',
latency_ms: 2,
source: 'client',
});client.registerTools(tools)
Register tool signatures with the cloud for policy generation.
await client.registerTools([{
name: 'send_email',
description: 'Send an email',
parameters: [
{ name: 'to', type: 'string', required: true },
{ name: 'subject', type: 'string', required: true },
{ name: 'body', type: 'string', required: true },
],
}]);veto.exportDecisions(options?)
Export the local decision history as JSON or CSV. Added in v1.6.0.
const json = veto.exportDecisions(); // JSON by default
const csv = veto.exportDecisions({ format: 'csv' });Options
| Option | Type | Default | Description |
|---|---|---|---|
format | "json" | "csv" | "json" | Output format |
Each record includes normalized audit fields: timestamp, tool_name, arguments, policy_version, rule_id, decision, reason.
Framework integrations
The SDK provides deep integrations with popular AI frameworks. Each integration intercepts tool calls at the framework level — no changes to your agent code.
| Framework | Import | Guide |
|---|---|---|
| LangChain | veto-sdk/integrations/langchain | LangChain Integration |
| Vercel AI SDK | veto-sdk/integrations/vercel-ai | Vercel AI SDK Integration |
| browser-use | veto-sdk/integrations/browser-use | Browser-Use Integration |
| MCP | veto-sdk/providers | MCP Integration |
Provider adapters
The SDK includes adapters that convert tool definitions between formats:
import { toAnthropic, toOpenAI } from 'veto-sdk/providers/adapters';
const anthropicTools = toAnthropic(openAITools);
const openAITools = toOpenAI(anthropicTools);MCP tools are converted automatically by veto.wrap(). For manual use:
import { fromMCP, isMCPTool } from 'veto-sdk/providers';
if (isMCPTool(tool)) {
const normalized = fromMCP(tool);
}Exports
| Import | What it provides |
|---|---|
veto-sdk | Core Veto class, ToolCallDeniedError, BudgetExceededError, BudgetStatus, VetoCloudClient, ApprovalTimeoutError |
veto-sdk/providers/* | Provider adapters (toOpenAI, fromOpenAI, toAnthropic, fromAnthropic, fromMCP, isMCPTool) |
veto-sdk/rules | Rule parsing and matching utilities |
veto-sdk/kernel | Local model evaluation via Ollama |
veto-sdk/custom | Direct LLM provider integration |
veto-sdk/compiler | Rule compiler utilities |
veto-sdk/benchmark | Performance benchmarking |
veto-sdk/integrations/langchain | LangChain middleware, ToolNode wrapper, callback handler |
veto-sdk/integrations/vercel-ai | Vercel AI SDK middleware with streaming support |
veto-sdk/integrations/browser-use | Browser-use controller wrapper |