All files / src/code-interpreter index.ts

100% Statements 74/74
93.75% Branches 15/16
100% Functions 8/8
100% Lines 74/74

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                                                                              1x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x   17x   17x 14x 14x 14x   14x 14x 14x 4x 8x 14x 14x 14x 14x 14x 14x 2x 2x 2x 2x 2x 2x 2x 14x   17x 17x 8x 8x   17x 6x 6x   17x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 17x 17x  
/**
 * AgentKits — Code Interpreter Module
 *
 * Safe JavaScript code execution sandbox for LLM tool use.
 *
 * Usage:
 *   import { createCodeInterpreter } from 'agentkits/code-interpreter';
 *   const interpreter = createCodeInterpreter();
 *   const result = await interpreter.execute('return 2 + 2');
 */
 
import { setTimeout as sleep } from 'node:timers/promises';
 
// ── Types ──────────────────────────────────────────────────────────
 
export interface CodeInterpreterConfig {
  timeout?: number;
  sandbox?: Record<string, unknown>;
  allowRequire?: boolean;
}
 
export interface ExecutionResult {
  success: boolean;
  output: string;
  error?: string;
  duration: number;
}
 
export interface CodeInterpreterClient {
  /** Execute JavaScript code in sandbox */
  execute(code: string, options?: { timeout?: number }): Promise<ExecutionResult>;
  /** Execute and return structured result */
  eval(expression: string): Promise<ExecutionResult>;
  /** Get as function-calling tool definition */
  readonly toolDefinition: { type: 'function'; function: { name: string; description: string; parameters: Record<string, unknown> } };
}
 
// ── Factory ────────────────────────────────────────────────────────
 
export function createCodeInterpreter(config: CodeInterpreterConfig = {}): CodeInterpreterClient {
  const defaultTimeout = config.timeout ?? 10000;
  const baseSandbox = {
    console: {
      log: (...args: unknown[]) => logs.push(args.map(String).join(' ')),
      error: (...args: unknown[]) => logs.push('[ERROR] ' + args.map(String).join(' ')),
      warn: (...args: unknown[]) => logs.push('[WARN] ' + args.map(String).join(' ')),
    },
    JSON,
    Math,
    Date,
    Array,
    Object,
    String,
    Number,
    Boolean,
    RegExp,
    Map,
    Set,
    parseInt,
    parseFloat,
    isNaN,
    isFinite,
    ...config.sandbox,
  };
 
  let logs: string[] = [];
 
  async function run(code: string, timeout: number): Promise<ExecutionResult> {
    logs = [];
    const start = Date.now();
    try {
      // Use Function constructor for sandboxed execution
      const fn = new Function('sandbox', `with(sandbox) { ${code} }`);
      const result = fn(baseSandbox);
      const output = logs.length > 0
        ? logs.join('\n') + (result !== undefined ? '\n→ ' + JSON.stringify(result) : '')
        : (result !== undefined ? JSON.stringify(result) : '(no output)');
      return {
        success: true,
        output,
        duration: Date.now() - start,
      };
    } catch (e: unknown) {
      return {
        success: false,
        output: logs.join('\n'),
        error: e instanceof Error ? e.message : String(e),
        duration: Date.now() - start,
      };
    }
  }
 
  return {
    async execute(code, options = {}) {
      return run(code, options.timeout ?? defaultTimeout);
    },
 
    async eval(expression) {
      return run(`return (${expression})`, defaultTimeout);
    },
 
    get toolDefinition() {
      return {
        type: 'function' as const,
        function: {
          name: 'code_interpreter',
          description: 'Execute JavaScript code and return the result. Use for calculations, data processing, etc.',
          parameters: {
            type: 'object',
            properties: {
              code: { type: 'string', description: 'JavaScript code to execute' },
            },
            required: ['code'],
          },
        },
      };
    },
  };
}