Skip to main content
The AgentScript preset is purpose-built for validating LLM-generated orchestration code. It’s the default preset used by enclave-vm and provides the strictest validation for AI-generated code.

Basic Usage

import { JSAstValidator, createAgentScriptPreset } from '@enclave-vm/ast';

const validator = new JSAstValidator(createAgentScriptPreset());

const result = await validator.validate(`
  const users = await callTool('users:list', { limit: 10 });
  return users.filter(u => u.active);
`);

Configuration Options

const validator = new JSAstValidator(createAgentScriptPreset({
  // Require at least one callTool() invocation (default: false)
  requireCallTool: true,

  // Customize allowed globals
  allowedGlobals: ['callTool', 'getTool', 'Math', 'JSON', 'Array', 'Object'],

  // Allow arrow functions for array methods (default: true)
  allowArrowFunctions: true,

  // Configure allowed loop types
  allowedLoops: {
    allowFor: true,      // for (let i = 0; ...) - default: true
    allowForOf: true,    // for (const x of arr) - default: true
    allowWhile: false,   // while (cond) - default: false
    allowDoWhile: false, // do {} while (cond) - default: false
    allowForIn: false,   // for (key in obj) - default: false
  },

  // Additional identifiers to block
  additionalDisallowedIdentifiers: ['customDangerous'],
}));

Option Reference

OptionTypeDefaultDescription
requireCallToolbooleanfalseRequire at least one callTool() invocation in the code
allowedGlobalsstring[]Standard safe globalsIdentifiers that can be referenced without declaration
allowArrowFunctionsbooleantrueAllow arrow functions for array methods
allowedLoopsobjectfor and for-ofConfigure which loop types are allowed
additionalDisallowedIdentifiersstring[][]Additional identifiers to block
Use requireCallTool: true to ensure AgentScript code actually interacts with tools rather than just performing local computations.

What AgentScript Blocks

CategoryBlocked ConstructsWhy
Code executioneval, Function, AsyncFunction, GeneratorFunctionPrevents dynamic code injection
System accessprocess, require, module, __dirname, __filename, BufferPrevents Node.js API access
Global objectswindow, globalThis, global, self, thisPrevents sandbox escape
TimerssetTimeout, setInterval, setImmediatePrevents timing attacks and async escape
Prototype__proto__, constructor, prototypePrevents prototype pollution
MetaprogrammingProxy, ReflectPrevents interception and reflection
Networkfetch, XMLHttpRequest, WebSocketPrevents network access
StoragelocalStorage, sessionStorage, indexedDBPrevents data persistence
Native codeWebAssembly, Worker, SharedWorkerPrevents native execution
Weak referencesWeakMap, WeakSet, WeakRefPrevents reference manipulation
User functionsfunction foo() {}, const f = function() {}Prevents recursion (arrow functions allowed)
Unbounded loopswhile, do-while, for-inPrevents infinite loops and prototype walking

What AgentScript Allows

// Tool calls
const result = await callTool('users:list', { limit: 10 });

// Variables
const users = result.items;
let count = 0;

// Conditionals
if (users.length > 0) { count = users.length; }

// Bounded loops
for (let i = 0; i < users.length; i++) { /* ... */ }
for (const user of users) { /* ... */ }

// Array methods with arrow functions
const active = users.filter(u => u.active);
const names = users.map(u => u.name);
const total = users.reduce((sum, u) => sum + u.score, 0);

// Safe globals
const max = Math.max(1, 2, 3);
const parsed = JSON.parse('{"a":1}');
const keys = Object.keys(obj);

// Return values
return { count, active, names };

Default Allowed Globals

The AgentScript preset allows these globals by default:
  • callTool - Tool invocation
  • Math - Mathematical operations
  • JSON - JSON parsing/stringifying
  • Array - Array constructor and methods
  • Object - Object methods
  • String - String methods
  • Number - Number methods
  • Boolean - Boolean conversion
  • Date - Date operations (read-only)
  • console - Logging (rate-limited by enclave)
  • undefined, null, NaN, Infinity - Primitives

Customizing Allowed Globals

const validator = new JSAstValidator(createAgentScriptPreset({
  allowedGlobals: [
    // Standard
    'callTool', 'Math', 'JSON', 'Array', 'Object',

    // Custom additions
    'context',      // Your context object
    'formatDate',   // Custom utility
  ],
}));

Precedence Rules

When allowedGlobals and additionalDisallowedIdentifiers are both provided, the following precedence applies:
  1. allowedGlobals removes from the dangerous list — If an identifier like process is normally blocked but you include it in allowedGlobals, it will be removed from the built-in dangerous identifiers blocklist and allowed.
  2. additionalDisallowedIdentifiers always wins — If an identifier appears in both allowedGlobals and additionalDisallowedIdentifiers, it remains blocked. This lets you grant broad access while force-blocking specific identifiers.
const validator = new JSAstValidator(createAgentScriptPreset({
  allowedGlobals: ['callTool', 'process', 'safeApi', 'dangerousApi'],
  additionalDisallowedIdentifiers: ['dangerousApi'],
}));

// 'process' — normally blocked, but allowedGlobals removes it → allowed
// 'safeApi' — custom global, not in any blocklist → allowed
// 'dangerousApi' — in allowedGlobals BUT also in additionalDisallowedIdentifiers → blocked
Be careful when adding normally-blocked identifiers like process or eval to allowedGlobals. Only do so when the sandbox runtime provides safe wrappers for these APIs.

Loop Configuration

Control which loop types are allowed:
const validator = new JSAstValidator(createAgentScriptPreset({
  allowedLoops: {
    allowFor: true,      // for (let i = 0; i < n; i++)
    allowForOf: true,    // for (const item of array)
    allowWhile: false,   // while (condition)
    allowDoWhile: false, // do {} while (condition)
    allowForIn: false,   // for (key in object)
  },
}));
for-in loops are blocked by default because they iterate over prototype properties, which can lead to unexpected behavior and security issues.

Requiring Tool Calls

Ensure scripts actually use tools:
const validator = new JSAstValidator(createAgentScriptPreset({
  requireCallTool: true,
}));

// This passes:
validator.validate('const x = await callTool("test", {}); return x;');

// This fails:
validator.validate('return 1 + 2;'); // No callTool