DEV Community

ZNY
ZNY

Posted on

Building AI Agents in Node.js: Complete Guide to Autonomous Task Execution

AI agents are one of the most transformative applications of large language models. An AI agent can reason, decide, and take actions — writing code, calling APIs, reading files — without constant human guidance. Here's how to build them in Node.js.

What Is an AI Agent?

An AI agent has three components:

  1. Planning — The LLM decides what actions to take
  2. Memory — Stores conversation history and context
  3. Tools — Functions the agent can call (web search, file I/O, API calls)

The agent loops: observe → plan → act → repeat until the task is complete.

The Core Agent Loop

`javascript
class SimpleAgent {
constructor(apiKey, tools = []) {
this.client = new ClaudeAPI(apiKey);
this.tools = tools;
this.messages = [];
}

async think(task) {
this.messages.push({ role: 'user', content: task });

// Build system prompt with tool descriptions
const systemPrompt = this.buildSystemPrompt();
const fullMessages = [systemPrompt, ...this.messages];

const response = await this.client.complete(fullMessages);
this.messages.push({ role: 'assistant', content: response });

return response;
}

buildSystemPrompt() {
const toolDescriptions = this.tools.map(t =>
${t.name}: ${t.description}
).join('\n');

return {
role: 'system',
content: `You are an AI agent. You have access to these tools:
${toolDescriptions}

When you need to use a tool, respond with:

{
"tool": "tool_name",
"input": { ... }
}

When you complete the task, respond with:
your answer
};
}
}

Defining Tools

Tools are functions the agent can call. Here's how to define them:

javascript
const tools = [
{
name: 'web_search',
description: 'Search the web for information',
execute: async (query) => {
const response = await fetch(https://api.example.com/search?q=${encodeURIComponent(query)});
return response.json();
}
},
{
name: 'read_file',
description: 'Read contents of a file',
execute: async (filepath) => {
return fs.readFileSync(filepath, 'utf8');
}
},
{
name: 'write_file',
description: 'Write content to a file',
execute: async ({ filepath, content }) => {
fs.writeFileSync(filepath, content);
return Written ${content.length} characters to ${filepath};
}
},
{
name: 'run_command',
description: 'Execute a shell command',
execute: async (command) => {
const { stdout, stderr } = await exec(command);
return stdout + stderr;
}
}
];

Parsing Tool Calls

When the model outputs a tool call, parse and execute it:

`javascript
async function executeToolCall(response) {
const match = response.match(/\s({[\s\S]?})\s*<\/Action>/);
if (!match) return null;

const { tool, input } = JSON.parse(match[1]);
const selectedTool = tools.find(t => t.name === tool);

if (!selectedTool) {
return { error: Unknown tool: ${tool} };
}

try {
const result = await selectedTool.execute(input);
return { tool, result };
} catch (error) {
return { tool, error: error.message };
}
}
`

Putting It Together: A Code Review Agent

Here's a practical example — an agent that reviews code:

`javascript
class CodeReviewAgent extends SimpleAgent {
constructor(apiKey) {
const reviewTools = [
{
name: 'read_file',
description: 'Read a source code file',
execute: async (filepath) => fs.readFileSync(filepath, 'utf8')
},
{
name: 'list_files',
description: 'List files in a directory',
execute: async (dir) => {
return fs.readdirSync(dir).join('\n');
}
}
];
super(apiKey, reviewTools);
}

async reviewProject(projectPath) {
const files = await this.executeTool({ name: 'list_files', input: projectPath });
const fileList = files.result.split('\n').filter(f => f.endsWith('.js'));

const reviews = [];
for (const file of fileList) {
const content = await this.executeTool({
name: 'read_file',
input: ${projectPath}/${file}
});
const review = await this.think(
Review this code for bugs, security issues, and best practices:\n\n${content}
);
reviews.push({ file, review });
}

return reviews;
}
}
`

Adding Memory Persistence

For longer tasks, persist memory to disk:

`javascript
class PersistentAgent extends SimpleAgent {
constructor(apiKey, tools, memoryPath = './agent-memory.json') {
super(apiKey, tools);
this.memoryPath = memoryPath;
this.loadMemory();
}

loadMemory() {
if (fs.existsSync(this.memoryPath)) {
this.messages = JSON.parse(fs.readFileSync(this.memoryPath, 'utf8'));
}
}

saveMemory() {
fs.writeFileSync(this.memoryPath, JSON.stringify(this.messages));
}

async think(task) {
const response = await super.think(task);
this.saveMemory();
return response;
}
}
`

Safety Considerations

AI agents executing code can be dangerous. Always:

  1. Sandbox commands — Run in isolated containers
  2. Limit file access — Only allow specific directories
  3. Timeout long operations — Prevent infinite loops
  4. Review before execute — Log all actions for human review

Getting Started

The easiest way to power an AI agent is with ofox.ai — their OpenAI-compatible API gives you Claude's reasoning capabilities at competitive pricing. Set up an API key and start building agents in minutes.

👉 Get started with ofox.ai

This article contains affiliate links.

Tags: ai-agents,nodejs,artificial-intelligence,programming,developer
Canonical URL: https://dev.to/zny10289

Top comments (0)