Package Exports
- agents-js
- agents-js/tools
Readme
agents-js
A powerful and flexible JavaScript library for building intelligent AI agents with OpenAI's GPT models. Features include automatic multi-agent orchestration, pre-built tools, lifecycle callbacks, session management, token tracking, and human-in-the-loop confirmations.
✨ Features
- 🤖 Automatic Multi-Agent Orchestration - Seamless agent transfers with built-in
transferToAgent - 🛠️ Pre-built Tools - Web search, scraping, calculator, datetime, and more
- 🔄 Lifecycle Callbacks - Hook into agent execution flow
- 💾 Session Management - Persist conversation state
- 💰 Token Tracking - Monitor usage and costs
- ✋ Human-in-the-Loop - Confirm dangerous operations
- 📝 TypeScript Support - Full type definitions included
- 🌊 Streaming - Real-time response streaming
- 🔑 Centralized API Key Management - Automatic fallback between services
Installation
npm install agents-jsQuick Start
require("dotenv").config();
const OpenAI = require("openai");
const { Agent, AgentController } = require("agents-js");
const { serperSearch } = require("agents-js/tools");
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL, // Optional: for local LLM endpoints
});
const controller = new AgentController(client, {
apiKeys: {
serper: process.env.SERPER_API_KEY,
firecrawl: process.env.FIRECRAWL_API_KEY,
},
});
const agent = new Agent({
name: "SearchAssistant",
model: "gpt-4o-mini",
instructions: "You are a helpful assistant with web search capabilities.",
functions: [serperSearch],
});
const messages = [{ role: "user", content: "What's new in AI?" }];
const response = await controller.run(agent, messages);
console.log(response.messages[response.messages.length - 1].content);
console.log(`Cost: $${response.cost.toFixed(4)}`);Pre-built Tools
Web Tools
const {
serperSearch,
firecrawlScrape,
firecrawlCrawl,
} = require("agents-js/tools");
// serperSearch automatically falls back to Firecrawl if Serper key is missing
serperSearch({ query: "AI agents 2025" });
firecrawlSearch({ query: "latest news" });
firecrawlScrape({ url: "https://example.com" });Math Tools
const {
calculate,
add,
subtract,
multiply,
divide,
} = require("agents-js/tools");
calculate({ expression: "25 * 48 + 100" });
add({ a: 5, b: 10 });DateTime Tools
const { getCurrentTime, getTimestamp, formatDate } = require("agents-js/tools");
getCurrentTime({ timezone: "America/New_York" });
getTimestamp();
formatDate({ timestamp: 1234567890000, format: "iso" });Web Tools
serperSearch- Web search via Serper.dev (with Firecrawl fallback)firecrawlSearch- Web search via Firecrawl.dev search APIfirecrawlScrape- Web scraping via Firecrawl.devfirecrawlCrawl- Website crawling
Advanced Features
API Key Management
Configure API keys for external tools in one place:
const controller = new AgentController(client, {
apiKeys: {
serper: "your-serper-key",
firecrawl: "your-firecrawl-key",
},
});
controller.setApiKey("serper", "new-key");
const key = controller.getApiKey("serper");API Key Management:
- AgentController configured keys:
controller.setApiKey("serper", "key") - Environment variables:
SERPER_API_KEY,FIRECRAWL_API_KEY
Automatic Fallback: serperSearch automatically falls back to Firecrawl if the Serper API key is missing or if the Serper API call fails. This ensures reliable web search functionality even if one service is unavailable.
Tool Usage: Tools automatically use configured API keys - no need to pass apiKey parameters.
Lifecycle Callbacks
Hook into the agent execution flow:
const agent = new Agent({
name: "Assistant",
instructions: "You are helpful.",
functions: [myTool],
beforeModel: async ({ messages, contextVariables }) => {
console.log("About to call model");
},
afterModel: async ({ response }) => {
console.log("Model responded");
},
beforeTool: async (toolName, args, context) => {
console.log(`Executing ${toolName}`);
return true;
},
afterTool: async (toolName, args, result, context) => {
console.log(`${toolName} completed`);
},
});Session Management
Persist conversation state across turns:
const { Session } = require("agents-js");
const session = new Session();
await session.set("user_name", "Alice");
await session.set("conversation_history", messages);
const name = await session.get("user_name");
const history = await session.get("conversation_history");Tool Confirmation (Human-in-the-Loop)
Require user confirmation for dangerous operations:
const { ToolConfirmation } = require("agents-js");
function deleteFile({ filename }) {
return new Result({ value: `Deleted ${filename}` });
}
const confirmationHandler = async (toolName, args, message) => {
console.log(message);
return true;
};
const controller = new AgentController(client, { confirmationHandler });
const agent = new Agent({
functions: [
new ToolConfirmation({
tool: deleteFile,
message: "⚠️ Confirm file deletion?",
}),
],
});Token Usage Tracking
Monitor costs and token usage:
const response = await controller.run(agent, messages);
console.log(`Input tokens: ${response.tokenUsage.totalInputTokens}`);
console.log(`Output tokens: ${response.tokenUsage.totalOutputTokens}`);
console.log(`Total cost: $${response.cost.toFixed(4)}`);
controller.resetTokenUsage();Automatic Multi-Agent Systems
Create specialized agents that automatically transfer to each other:
const searchAgent = new Agent({
name: "SearchSpecialist",
instructions: "You specialize in web search.",
functions: [serperSearch],
description: "Expert at finding online information",
});
const mathAgent = new Agent({
name: "MathSpecialist",
instructions: "You specialize in calculations.",
functions: [calculate],
description: "Expert at mathematical operations",
});
const coordinator = new Agent({
name: "Coordinator",
instructions: `Route requests to the appropriate specialist:
- For search questions → transfer to "SearchSpecialist"
- For math questions → transfer to "MathSpecialist"`,
functions: [], // transferToAgent is automatically added
subAgents: [searchAgent, mathAgent],
});
const response = await controller.run(coordinator, messages);
console.log("Active agent:", response.agent.name);Key Benefits:
- No need to manually create
transferToAgentfunctions - Automatic agent discovery and registration
- Built-in error handling for invalid agent names
- Seamless context transfer between agents
Streaming Responses
Stream responses in real-time:
const stream = await controller.run(agent, messages, {}, null, true);
for await (const chunk of stream) {
if (chunk.delim === "start") {
console.log("Starting stream...");
} else if (chunk.delim === "end") {
console.log("\nStream ended.");
} else if (chunk.content) {
process.stdout.write(chunk.content);
} else if (chunk.response) {
console.log("\nFinal response:", chunk.response);
}
}Context Variables
Pass dynamic context to your agents:
const contextVariables = {
userId: "123",
userName: "Alice",
preferences: { theme: "dark" },
};
const response = await controller.run(agent, messages, contextVariables);Functions can access context variables:
function personalizedGreeting({ context_variables }) {
/**
* @description Greet user with their name
*/
const name = context_variables.userName || "there";
return new Result({ value: `Hello, ${name}!` });
}Custom Tools
Create custom tools with JSDoc annotations:
const { Result } = require("agents-js");
function fetchWeather({ city }) {
/**
* @param {string} city - City name to get weather for
* @description Get current weather for a city
*/
const temp = Math.floor(Math.random() * 30) + 10;
return new Result({
value: `The temperature in ${city} is ${temp}°C`,
});
}
const agent = new Agent({
functions: [fetchWeather],
});API Reference
Agent
new Agent({
name: string,
model: string,
instructions: string | function,
functions: Array<Function | ToolConfirmation>,
toolChoice: string | null,
parallelToolCalls: boolean,
beforeModel: function,
afterModel: function,
beforeTool: function,
afterTool: function,
subAgents: Array<Agent>,
description: string,
})AgentController
new AgentController(client, {
confirmationHandler: async (toolName, args, message) => boolean,
apiKeys: {
serper: "key",
firecrawl: "key",
},
});
controller.run(
agent,
messages,
contextVariables,
modelOverride,
stream,
debug,
maxTurns,
executeTools
);
controller.setApiKey(service, key);
controller.getApiKey(service);
controller.getTokenUsage();
controller.resetTokenUsage();Result
new Result({
value: string,
agent: Agent | null,
contextVariables: object,
});Response
{
messages: Array<Message>,
agent: Agent,
contextVariables: object,
tokenUsage: object,
cost: number,
}Usage Examples
Basic Agent with Web Search
const agent = new Agent({
name: "ResearchAssistant",
model: "gpt-4o-mini",
instructions: "You are a research assistant with web search capabilities.",
functions: [serperSearch],
});
const response = await controller.run(agent, [
{ role: "user", content: "What are the latest developments in AI?" }
]);Multi-Agent System with Automatic Transfers
const weatherAgent = new Agent({
name: "WeatherSpecialist",
instructions: "You specialize in weather information.",
functions: [serperSearch],
});
const timeAgent = new Agent({
name: "TimeSpecialist",
instructions: "You specialize in time and timezone information.",
functions: [getCurrentTime],
});
const coordinator = new Agent({
name: "Assistant",
instructions: "Route weather questions to WeatherSpecialist, time questions to TimeSpecialist.",
functions: [], // transferToAgent automatically added
subAgents: [weatherAgent, timeAgent],
});
// Agents automatically transfer based on user queries
const response = await controller.run(coordinator, [
{ role: "user", content: "What's the weather in New York?" }
]);Session Management
const session = new Session();
await session.set("user_preferences", { theme: "dark", language: "en" });
const response = await controller.run(agent, messages, {
session: session,
user_preferences: await session.get("user_preferences")
});Environment Variables
Create a .env file in your project root:
# OpenAI Configuration (or compatible endpoint)
OPENAI_API_KEY=your-api-key
OPENAI_BASE_URL=http://localhost:3002/v1 # Optional: for local LLM endpoints
# External Tool API Keys (optional)
SERPER_API_KEY=your-serper-key
FIRECRAWL_API_KEY=your-firecrawl-keyUsing Local LLM Endpoints:
agents-js works with any OpenAI-compatible API endpoint. For example, to use a local LLM:
# Example: Local LLM at localhost:3002
OPENAI_API_KEY=your-local-key
OPENAI_BASE_URL=http://localhost:3002/v1
# Example: Ollama
OPENAI_API_KEY=ollama
OPENAI_BASE_URL=http://localhost:11434/v1
# Example: LM Studio
OPENAI_API_KEY=lm-studio
OPENAI_BASE_URL=http://localhost:1234/v1TypeScript
Full TypeScript definitions are included:
import { Agent, AgentController, Result, Response, Session } from "agents-js";
import { serperSearch, calculate } from "agents-js/tools";
const agent: Agent = new Agent({
name: "Assistant",
model: "gpt-4o-mini",
instructions: "You are helpful.",
});Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
License
MIT License - see LICENSE file for details.
Author
Vikrant Guleria
Examples
See the examples directory for practical demonstrations:
- Basic Agent - Custom tools and core functionality
- Multi-Agent System - Automatic agent orchestration
- Advanced Features - Sessions, confirmations, and callbacks
Links
Built with ❤️ for the AI agent community