Skip to content

Agent Runner

Run LLM tool-use loops with Anthropic or OpenAI, routed through Nella's validation pipeline with full cost tracking.

The Agent Runner lets you run complete LLM tool-use loops where every tool call is routed through Nella’s validation pipeline. It supports Anthropic and OpenAI models with built-in token tracking and cost estimation.

How It Works

  1. You provide a prompt and model configuration
  2. The runner sends the prompt to the LLM along with Nella’s MCP tool definitions
  3. When the LLM requests a tool call, the runner executes it through McpToolHandler
  4. Tool results are fed back to the LLM as messages
  5. The loop continues until the LLM finishes, hits the turn limit, or is stopped

Every tool call goes through Nella’s full validation pipeline — constraints, risk scanning, refusal checks — ensuring safe execution even in autonomous loops.

Quick Start

import { AgentRunner, McpToolHandler } from '@getnella/mcp';

const handler = new McpToolHandler({ workspacePath: '.' });
const runner = new AgentRunner(handler);

const result = await runner.run({
  provider: 'anthropic',
  model: 'claude-sonnet-4-20250514',
  apiKey: process.env.ANTHROPIC_API_KEY,
  prompt: 'Add input validation to the login form',
  maxTurns: 10,
  maxTokens: 4096,
});

console.log(`Status: ${result.status}`);
console.log(`Turns: ${result.turns.length}`);
console.log(`Cost: $${result.totalCost.toFixed(4)}`);

Configuration

ParameterTypeRequiredDescription
providerstringYes"anthropic" or "openai"
modelstringYesModel ID (e.g., claude-sonnet-4-20250514, gpt-4o)
apiKeystringYesProvider API key
promptstringYesThe task prompt
maxTurnsnumberNoMaximum loop iterations (default: 10)
maxTokensnumberNoMax tokens per LLM call

Supported Models & Pricing

ModelInput (per 1M tokens)Output (per 1M tokens)
claude-opus-4-20250514$15.00$75.00
claude-sonnet-4-20250514$3.00$15.00
claude-3-5-sonnet-20241022$3.00$15.00
gpt-4-turbo$10.00$30.00
gpt-4o$2.50$10.00
gpt-4o-mini$0.15$0.60

Result Structure

{
  turns: AgentTurn[];          // Each turn contains:
  // {
  //   assistantContent: string;
  //   toolCalls: ToolCallInfo[];
  //   toolResults: ToolResultInfo[];
  //   tokenUsage: { inputTokens, outputTokens, totalTokens };
  //   cost: number;
  //   durationMs: number;
  // }

  totalTokenUsage: {
    inputTokens: number;
    outputTokens: number;
    totalTokens: number;
  };
  totalCost: number;
  totalDurationMs: number;
  status: "completed" | "max_turns" | "stopped" | "error";
  error?: string;
}

Events

Subscribe to runner events for real-time monitoring:

runner.onEvent((event) => {
  switch (event.type) {
    case 'turn:start':
      console.log(`Turn ${event.turn} starting...`);
      break;
    case 'turn:tool_call':
      console.log(`Calling ${event.toolName}...`);
      break;
    case 'turn:end':
      console.log(`Turn complete. Cost: $${event.cost}`);
      break;
    case 'done':
      console.log(`Finished: ${event.status}`);
      break;
  }
});
EventDescription
statusRunner status change
turn:startNew turn beginning
turn:thinkingLLM is generating
turn:tool_callTool call requested
turn:tool_resultTool call completed
turn:endTurn finished
doneAll turns complete
errorError occurred

Stopping a Run

You can stop a running agent at any time:

const runner = new AgentRunner(handler);

// Start the run
const resultPromise = runner.run(config);

// Stop after 30 seconds
setTimeout(() => runner.stop(), 30000);

const result = await resultPromise;
// result.status === "stopped"

Provider Adapters

Anthropic

Calls https://api.anthropic.com/v1/messages with anthropic-version: 2023-06-01. Automatically converts between Nella’s tool format and Anthropic’s content block format (text + tool_use + tool_result).

OpenAI

Calls https://api.openai.com/v1/chat/completions. Converts tool calls from OpenAI’s function calling format with JSON-stringified arguments. Maps finish reasons (stopend_turn, tool_callstool_use).