CodeRun Agents SDK Overview
CodeRun Agents SDK (coderun-agent) is a standalone, lightweight, multi-provider AI Agent framework in plain JavaScript (ESM). It enables developers to build tool-augmented autonomous AI agents with real-time streaming, multi-agent delegation, and Human-in-the-Loop (HIL) safety approval workflows.
function name() {}). Zero TypeScript compilation needed. Works natively in Node.js, Web Browsers, Electron, and server environments.
Quickstart
Install coderun-agent via npm:
npm install coderun-agent
Initialize and execute your agent in 5 lines of code:
import { createAgent } from 'coderun-agent';
var agent = createAgent({
name: 'CodeAssistant',
instructions: 'You are a helpful software engineering assistant.',
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
apikey: 'ollama',
model: 'qwen2.5-coder:7b'
});
agent.run('Write a function to reverse a string.').then(function(result) {
console.log(result.content);
});
Agents & createAgent
An agent is configured using a single configuration object passed to createAgent(config). An agent instance exposes methods to execute prompts, track token usage, manage lifecycle state, and connect optional MCP servers.
Agent Methods Reference
agent.run(prompt, runOptions): Executes a prompt turn loop. Returns a Promise resolving to a structuredresultobject.agent.run(prompt, { history }): Passes caller-owned continuation history for one run.- The agent does not retain history between runs, preventing accidental context leakage.
result.history: Returns the complete transcript produced during that run.agent.getUsage(): Returns cumulative token usage metrics (prompt_tokens,completion_tokens,total_tokens).agent.resetContext(): Resets usage and the agent's local lifecycle state.agent.connectMcp(config): Connects to an MCP server and discovers its tools.agent.closeMcp(): Closes connected MCP sessions and local MCP server processes.
Plug-and-Play MCP Servers
Install the optional MCP client package when you want to use existing MCP servers:
npm install @modelcontextprotocol/client
Connect open-source filesystem, GitHub, or other MCP servers through stdio:
var agent = createAgent({
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
apikey: 'ollama',
model: 'minimax-m3:cloud'
});
await agent.connectMcp({
name: 'filesystem',
transport: 'stdio',
command: 'npx',
args: [ '-y', '@modelcontextprotocol/server-filesystem', process.cwd() ]
});
var result = await agent.run('List the project files with the MCP filesystem tool.');
await agent.closeMcp();
For a remote server, use transport: 'streamable-http', provide its url, and add authentication headers when required:
await agent.connectMcp({
name: 'remote-github',
transport: 'streamable-http',
url: 'https://example.com/mcp',
headers: { Authorization: 'Bearer YOUR_TOKEN' }
});
MCP tools are discovered automatically, converted to the agent's tool format, validated, permission-checked, executed through the normal agent loop, and returned to the model. The MCP client is loaded lazily only when connectMcp() is called.
Tools & Schemas (tool)
Define custom tools using the tool helper function. Tools accept standard JSON schema objects or Zod schemas (z.object(...)).
import { tool } from 'coderun-agent';
function executeWeather(args) {
var city = args ? args.city : 'Tokyo';
return Promise.resolve('Weather in ' + city + ' is sunny 25°C.');
}
var getWeatherTool = tool({
name: 'get_weather',
description: 'Get current weather for a city',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: 'City name e.g. Tokyo' }
},
required: ['city']
},
execute: executeWeather
});
Tool Suite Integration (coderun-tools, coderun-browser, coderun-desktop)
coderun-agent seamlessly connects with the complete CodeRun Tool Suite. You can pass tools from all three packages together in a single agent:
import { createAgent } from 'coderun-agent';
import coderunTools from 'coderun-tools';
import coderunBrowser from 'coderun-browser';
import coderunDesktop from 'coderun-desktop';
// Combine definitions from all three libraries
var allTools = [].concat(
coderunTools.getDefinitions(),
coderunBrowser.getDefinitions(),
coderunDesktop.getDefinitions()
);
var agent = createAgent({
name: 'FullAutomationAgent',
instructions: 'You are an autonomous agent with workspace file access, web browser automation, and OS desktop controls.',
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
model: 'qwen2.5-coder:7b',
tools: allTools
});
agent.run('Check workspace files, open example.com in browser, and capture desktop screenshot.');
🛡️ Guardrails Pipeline (Input, Tool & Output Safety)
Guardrails allow you to define programmable safety checkpoints at each stage of the agent execution lifecycle. Pass arrays of inspection functions in inputGuardrails, toolGuardrails, and outputGuardrails:
import { createAgent } from 'coderun-agent';
// 1. Input Guardrail: Block prompt injection or destructive requests
function checkPromptSafety(prompt, context) {
var lower = prompt.toLowerCase();
if (lower.indexOf('ignore all instructions') >= 0 || lower.indexOf('drop database') >= 0) {
return { pass: false, error: 'Security tripwire: Unsafe prompt detected.' };
}
return { pass: true };
}
// 2. Tool Guardrail: Prevent directory escape outside workspace
function checkWorkspaceBoundary(toolName, args, context) {
if (args && args.path && typeof args.path === 'string') {
if (args.path.indexOf('..') >= 0 || args.path.startsWith('/etc') || args.path.startsWith('C:\\Windows')) {
return { pass: false, error: 'Path traversal forbidden outside workspace.' };
}
}
return { pass: true };
}
// 3. Output Guardrail: Enforce response format rules
function checkOutputFormat(content, context) {
if (content.indexOf('SUMMARY:') === -1) {
return { pass: false, error: 'Response must include a "SUMMARY:" section.' };
}
return { pass: true };
}
var agent = createAgent({
name: 'GuardedAgent',
provider: 'openai-compatible',
baseurl: 'https://opencode.ai/zen/v1',
apikey: 'sk-your-key',
model: 'deepseek-v4-flash-free',
inputGuardrails: [checkPromptSafety],
toolGuardrails: [checkWorkspaceBoundary],
outputGuardrails: [checkOutputFormat]
});
📐 Structured Output Enforcement (outputSchema)
Pass an outputSchema (a Zod schema or standard JSON schema) to guarantee valid, typed JSON output. If the model emits invalid JSON or schema violations, the engine automatically prompts the model to self-correct within the loop:
import { createAgent } from 'coderun-agent';
import { z } from 'zod';
var LeadExtractionSchema = z.object({
fullName: z.string().describe('Full name of contact'),
email: z.string().describe('Email address'),
score: z.number().describe('Lead score from 1-100')
});
var agent = createAgent({
provider: 'openai-compatible',
baseurl: 'https://generativelanguage.googleapis.com/v1beta/openai/',
apikey: 'YOUR_GEMINI_API_KEY',
model: 'gemini-flash-latest',
outputSchema: LeadExtractionSchema
});
var result = await agent.run('Extract contact info: John Doe, reachable at john@example.com, high purchase intent (95).');
// Access parsed structured object directly:
console.log(result.structuredOutput);
// Output: { fullName: "John Doe", email: "john@example.com", score: 95 }
Human-in-the-Loop (HIL) Security & Permission Control Guide
Protect your file system, terminal environment, and desktop OS from unauthorized actions using HIL Permission Controls (needsApproval + permissionHandler).
needsApproval is configured (as a boolean, an array of tool names, or inside a tool definition), passing a permissionHandler function is strictly mandatory. If missing, createAgent throws an explicit validation error: Error: permissionHandler function is required when needsApproval is configured.
1. Three Approval Configuration Modes
- Mode 1: Array of Specific Tool Names
needsApproval: ['delete_file', 'execute_command', 'desktop_click']
Gates only the specific sensitive tools specified in the array. All other tools run automatically. - Mode 2: Global Boolean Flag
needsApproval: true
Gates ALL tools passed to the agent. Every single tool call requires user confirmation before execution. - Mode 3: Per-Tool Definition Flag
tool({ name: 'delete_file', needsApproval: true, execute: ... })
Flags specific custom tools as requiring approval directly inside their declaration.
2. Execution Lifecycle & resolve(true) / resolve(false)
When an agent encounters a tool call that requires approval:
- The agent pauses the LLM execution turn loop.
- It transitions state to
'waiting'and emitsonEvent({ type: 'state_changed', state: 'waiting', tool: toolName, args: args, id: toolId }). - It invokes your custom
permissionHandler(toolName, args, toolId)callback. - User Approves (
resolve(true)): The agent unfreezes, executes the action on disk/terminal/desktop, and returns the tool output to the LLM. - User Denies (
resolve(false)): The agent unfreezes, blocks execution, and feeds"Permission denied by user. Do NOT retry calling this tool."back to the LLM so it can pick a safe alternative.
3. Node.js Terminal CLI Approval Example
import readline from 'readline';
import { createAgent } from 'coderun-agent';
import coderunTools from 'coderun-tools';
// Terminal CLI Permission Handler
function cliPermissionHandler(toolName, args, toolId) {
return new Promise(function(resolve) {
console.log('\n⚠️ [SECURITY APPROVAL REQUIRED]');
console.log(' Tool requested:', toolName);
console.log(' Arguments:', JSON.stringify(args, null, 2));
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Allow tool execution? (y/N): ', function(answer) {
rl.close();
if (answer.trim().toLowerCase() === 'y') {
console.log('🟢 Permission GRANTED by user.');
resolve(true); // 👈 ALLOW execution!
} else {
console.log('🔴 Permission DENIED by user.');
resolve(false); // 👈 BLOCK execution!
}
});
});
}
var agent = createAgent({
name: 'SecureCLIAgent',
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
model: 'qwen2.5-coder:7b',
tools: coderunTools.getDefinitions(),
// Gate dangerous tools:
needsApproval: ['delete_file', 'delete_folder', 'execute_command'],
permissionHandler: cliPermissionHandler
});
4. Web UI / HTML Modal Approval Example
// Web UI / React Modal Permission Handler
function webUiPermissionHandler(toolName, args, toolId) {
return new Promise(function(resolve) {
// 1. Show HTML Modal / Dialog in React or DOM:
showApprovalModal({
title: 'Tool Permission Request',
message: 'Agent wants to run ' + toolName,
details: args,
onApprove: function() {
hideModal();
resolve(true); // 🟢 User clicked ALLOW!
},
onDeny: function() {
hideModal();
resolve(false); // 🔴 User clicked DENY!
}
});
});
}
var agent = createAgent({
name: 'WebUIAgent',
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
model: 'qwen2.5-coder:7b',
tools: coderunTools.getDefinitions(),
needsApproval: true, // Gate all tools
permissionHandler: webUiPermissionHandler
});
Streaming & Reasoning Tokens
Enable stream: true to receive real-time reasoning/thinking tokens, response text, and tool execution events:
function handleAgentEvent(evt) {
if (evt.type === 'thinking' && evt.chunk) {
process.stdout.write(evt.chunk); // 💭 Live reasoning tokens (DeepSeek / Qwen / Claude)
} else if (evt.type === 'stream' && evt.chunk) {
process.stdout.write(evt.chunk); // 💬 Live content tokens
} else if (evt.type === 'tool_call') {
console.log('🛠️ Tool Called:', evt.tool, evt.args);
} else if (evt.type === 'tool_result') {
console.log('✅ Tool Result:', evt.tool);
}
}
var agent = createAgent({
name: 'StreamAgent',
provider: 'openai-compatible',
baseurl: 'https://opencode.ai/zen/v1',
apikey: 'YOUR_API_KEY',
model: 'deepseek-v4-flash-free',
tools: [ getWeatherTool ],
stream: true
});
agent.run('What is the weather in Tokyo?', { onEvent: handleAgentEvent });
Agents as Tools (Subagents)
Pass any agent instance directly inside tools: [ subAgent ] to create hierarchical multi-agent delegation chains:
var researcher = createAgent({
name: 'Researcher',
instructions: 'You research topics and summarize findings.',
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
apikey: 'ollama',
model: 'qwen2.5-coder:7b'
});
var manager = createAgent({
name: 'Manager',
instructions: 'Delegate research tasks to the Researcher agent.',
provider: 'openai-compatible',
baseurl: 'http://localhost:11434/v1',
apikey: 'ollama',
model: 'qwen2.5-coder:7b',
tools: [ researcher ] // 👈 Automatically available as delegate_to_researcher tool!
});
Model Providers
coderun-agent connects to any LLM endpoint via standard provider drivers:
| Provider Name | BaseURL Format | Example Model |
|---|---|---|
openai-compatible |
http://localhost:11434/v1 |
qwen2.5-coder:7b (Ollama) |
openai-compatible |
https://generativelanguage.googleapis.com/v1beta/openai/ |
gemini-flash-latest (Google Gemini) |
openai-compatible |
https://opencode.ai/zen/v1 |
deepseek-v4-flash-free (OpenCode) |
openai-compatible |
https://api.openai.com/v1 |
gpt-4o (OpenAI) |
anthropic |
Direct SDK Connection | claude-3-5-sonnet-20241022 |
Options Reference Table
| Field | Required | Description |
|---|---|---|
name |
No | Defaults to function/agent name (e.g. "Agent"). |
instructions |
No | System prompt/instructions shown to the LLM. |
provider |
Yes | "openai-compatible" or "anthropic". |
baseurl |
OpenAI-compatible only | HTTP endpoint URL. Anthropic uses its native SDK endpoint by default. |
apikey |
No | API key or bearer token. Optional when the provider SDK environment variable (OPENAI_API_KEY, ANTHROPIC_API_KEY) is set. |
model |
No | Model string identifier (default: "qwen2.5-coder:7b"). |
tools |
No | Array of tools (custom tools, coderun-tools, or subagents). |
inputGuardrails |
No | Array of check functions: [function(prompt, context) { ... }]. Blocks unsafe prompts before LLM call. |
toolGuardrails |
No | Array of check functions: [function(toolName, args, context) { ... }]. Blocks invalid or unsafe tool parameters. |
outputGuardrails |
No | Array of check functions: [function(content, context) { ... }]. Validates final output against compliance rules. |
outputSchema |
No | Zod schema or JSON schema. Enforces valid structured JSON output with automatic LLM self-correction. |
needsApproval |
No | Approval policy: true or array of tool names ['delete_file']. |
permissionHandler |
Conditional | Mandatory function when needsApproval is set: function(toolName, args, id) returning true or false. |
stream |
No | Boolean indicating if streaming is enabled (default: true). |
workspace |
No | Workspace directory path (defaults to process.cwd()). |
timeoutMs |
No | Abort the provider request and cooperative tool work after the specified number of milliseconds. Timeout results use status: 'timeout'. |
maxIterations |
No | Maximum agent-loop turns (default: 50). Termination returns status: 'max_iterations_reached'. |
maxRetries |
No | Provider request retry count on transient failures (default: 3). |
temperature |
No | Sampling temperature passed to the provider. |
maxTokens / max_tokens |
No | Max generated tokens per request. Anthropic default: 4096; OpenAI-compatible defaults to the provider's server default when omitted. |
parallelTools |
No | Execute multiple tool calls concurrently in one iteration (default: false). |
toolChoice / tool_choice |
No | Control tool selection: 'auto', 'none', 'required', or a specific tool object. |
responseFormat / response_format |
No | Provider response format object (e.g. { type: 'json_object' }). |
streamOptions / stream_options |
No | Streaming extras; set false to omit stream_options for endpoints that reject them. |
maxHistoryMessages / maxHistory |
No | Keep only the most recent N history messages (turn-aware pruning). Disabled when omitted. |
maxContextTokens |
No | Approximate token budget for the whole request; oldest complete turns are trimmed to fit. Disabled when omitted. |
maxToolOutputChars |
No | Truncate tool result text stored in history (default: 6000, set 0 to disable). |
onEvent |
No | Global streaming/state event callback: function(evt). |
askPermission |
No | Alias for permissionHandler. |
subagents |
No | Array of agent instances made available as delegation tools. |
signal |
No | Caller-provided AbortSignal for cancelling provider and cooperative tool work. Aborted results use status: 'aborted'. |
Result Object Reference Table
| Field | Type | Description |
|---|---|---|
success |
Boolean | Indicates clean completion of the agent turn loop. Iteration-limit termination returns false. |
content |
String | Final text answer generated by the assistant. |
structuredOutput |
Object | Parsed JSON object returned when outputSchema is provided. |
thinking |
String | Accumulated reasoning/thinking tokens. |
toolCalls |
Array | Array of executed tool objects: [{ id, name, args, output }]. |
usage |
Object | Token consumption: { prompt_tokens, completion_tokens, total_tokens }. |
history |
Array | Complete transcript produced during the current run. It is not automatically reused by a later run. |
status |
String | Result status: 'completed' on success; otherwise 'max_iterations_reached', 'timeout', 'aborted', 'schema_validation_failed', 'guardrail_blocked', or 'error'. |
iterations |
Number | Number of agent-loop turns consumed by this run. |
rawResponse |
Object | Raw provider response (non-streaming). For streaming, contains { streamed, model, chunksCount, finishReason }. |