npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@open1s/jsbos

v2.3.2

Published

BrainOS — multi-language AI agent framework. Agents, tools, event bus, MCP, skills, memory — for Node.js.

Readme

@open1s/jsbos — v2.3.0

BrainOS JavaScript/Node.js bindings — AI agent framework with ReAct engine

High-performance JavaScript bindings for BrainOS, a Rust-based AI agent framework implementing the ReAct (Reason + Act) paradigm. Built with NAPI-RS for native performance.

Features

  • ReAct Agent — Async agent with tool-calling capabilities, streaming responses, and automatic reasoning
  • Multimodal Content — Support for images, audio, and other binary content via unified Binary type
  • Message Bus — Publish/subscribe message bus for inter-agent communication
  • Lifecycle Hooks — Intercept and modify agent behavior at key points
  • Plugin System — Extend LLM requests/responses and tool execution
  • MCP Client — Connect to Model Context Protocol servers
  • Bash Tool — Execute shell commands with workspace isolation
  • Skills — Register agent capabilities from directory files

Installation

npm install @open1s/jsbos
# or
yarn add @open1s/jsbos

Requirements

  • Node.js >= 12.22.0 (or Node.js >= 14.17.0)
  • Prebuilt binaries available for:
    • macOS (arm64)
    • Linux (x86_64, aarch64)
    • Windows (x86_64)

Quick Start

Using BrainOS (recommended)

import { BrainOS, ToolDef } from '@open1s/jsbos';

async function main() {
  const brain = new BrainOS();
  await brain.start();

  // Define a tool
  const addTool = new ToolDef(
    'add',
    'Add two numbers',
    (args) => args.a + args.b,
    { type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } }, required: ['a', 'b'] }
  );

  // Create and configure an agent
  const agent = brain
    .agent('assistant')
    .register(addTool)
    .start();

  // Run the agent
  const response = await agent.ask('What is 15 + 23?');
  console.log(response);

  await brain.stop();
}

main().catch(console.error);

Using Agent directly (low-level)

import { Agent, Bus } from '@open1s/jsbos';

async function main() {
  const bus = await Bus.create();

  const agent = await Agent.create({
    name: 'assistant',
    model: 'gpt-4',
    baseUrl: 'https://api.openai.com/v1',
    apiKey: process.env.OPENAI_API_KEY,
    systemPrompt: 'You are a helpful assistant.',
    temperature: 0.7,
    timeoutSecs: 120,
  }, bus);

  await agent.addTool(
    'calculator',
    'Evaluate a mathematical expression',
    JSON.stringify({ expression: { type: 'string', description: 'Math expression' } }),
    JSON.stringify({ type: 'object', properties: { expression: { type: 'string' } }, required: ['expression'] }),
    (err, args) => JSON.stringify({ result: eval(args.expression) })
  );

  const response = await agent.runSimple('What is 15 * 23?');
  console.log(response);
}

main().catch(console.error);

API Reference

BrainOS (High-level API)

The recommended way to use jsbos — manages bus lifecycle, config loading, and tool registry.

new BrainOS() — Create a BrainOS instance

const brain = new BrainOS();
await brain.start();  // Loads config, starts bus, registers global tools

brain.agent(name, options) — Create an agent builder

const agent = brain
  .agent('assistant', { model: 'gpt-4', systemPrompt: 'Be helpful.' })
  .register(myTool)           // Register a ToolDef
  .hook(HookEvent.BeforeLlmCall, (err, ctx) => 'continue')
  .plugin('my-plugin', { onLlmRequest: (req) => req })
  .skillsFromDir('./skills')
  .start();                   // Returns an AgentWrapper

agent.ask(prompt) — Ask a question

const response = await agent.ask('What is 2+2?');

agent.react(task) — Run with ReAct reasoning

const response = await agent.react('Find files modified in the last hour');

agent.stream(task, onToken) — Stream responses

await agent.stream('Write a story', (token) => {
  if (token.type === 'Text') process.stdout.write(token.text);
  if (token.type === 'Done') console.log('\n[Done]');
});

agent.streamCollect(task) — Collect all streaming tokens

const tokens = await agent.streamCollect('List 3 colors');
const text = tokens.filter(t => t.type === 'Text').map(t => t.text).join('');

agent.runSimple(prompt) — Simple task execution

const response = await agent.runSimple('What is 100 * 100?');

agent.stop() — Stop the agent

agent.stop();

agent.metrics() — Get performance metrics

const m = agent.metrics();
console.log(m.llmCallCount, m.totalInputTokens, m.totalOutputTokens);

agent.session — Session management

const session = agent.session;
const json = session.export();
await session.saveFull('./session.json');
await session.restoreFull('./session.json');
session.compact(2, 500);  // keep 2 messages, max 500 chars summary
session.clear();

ToolDef

Define tools with a clean declarative API.

import { ToolDef } from '@open1s/jsbos';

const addTool = new ToolDef(
  'add',                                    // name
  'Add two numbers',                        // description
  (args) => args.a + args.b,                // handler
  { type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } }, required: ['a', 'b'] }  // schema
);

Multimodal Content

BrainOS supports images, audio, and other binary content through Content, ContentPart, and Binary classes.

Creating Content

import { Content, ContentPart, Binary, BinarySource } from '@open1s/jsbos';

// Text only
const textContent = Content.text('What is Python?');

// Single image (URL)
const imageContent = Content.image('https://example.com/photo.jpg');

// Audio from base64 data
const audioContent = Content.audio(base64Data, 'mp3');

// Audio from URL
const audioUrlContent = Content.audioUrl('https://example.com/audio.mp3', 'mp3');

// Multi-part content (text + image + audio)
const multiContent = Content.parts([
    ContentPart.text('Describe this image and audio'),
    ContentPart.image('https://example.com/photo.jpg'),
    ContentPart.audio(base64Data, 'mp3'),
]);

Using Content with Agent

// Text
const result = await agent.ask('What is Python?');

// Text with image
const content = Content.parts([
    ContentPart.text('What is in this image?'),
    ContentPart.image('https://example.com/photo.jpg'),
]);
const result = await agent.ask(content);

// Text with audio
const audioContent = Content.parts([
    ContentPart.text('Transcribe this audio'),
    ContentPart.audio(base64Data, 'wav'),
]);
const result = await agent.ask(audioContent);

Content API

| Method | Description | |--------|-------------| | Content.text(text) | Simple text content | | Content.image(url) | Single image (URL) | | Content.audio(data, format) | Single audio (base64) | | Content.audioUrl(url, format) | Single audio (URL) | | Content.parts([...]) | Multi-part content |

ContentPart API

| Method | Description | |--------|-------------| | ContentPart.text(text) | Create text part | | ContentPart.image(url) | Create image part (URL) | | ContentPart.audio(data, format) | Create audio part (base64) | | ContentPart.audioUrl(url, format) | Create audio part (URL) | | ContentPart.binary(type, data) | Create binary part |

Binary / BinarySource

The Binary class represents binary data with content_type and source:

const binary = new Binary('image/jpeg', BinarySource.url('https://example.com/photo.jpg'));

| Method | Description | |--------|-------------| | binary.contentType() | Get content type (e.g., "image/jpeg") | | binary.isImage() | Check if image type | | binary.isAudio() | Check if audio type | | BinarySource.url(data) | Create URL source | | BinarySource.base64(data) | Create base64 source |

Agent (Low-level API)

The core AI agent class with tool-calling and ReAct reasoning capabilities.

Agent.create(config) — Create a new agent

const agent = await Agent.create({
  name: 'my-agent',           // Agent name
  model: 'gpt-4',             // LLM model identifier
  baseUrl: 'https://api.openai.com/v1',
  apiKey: process.env.OPENAI_API_KEY,
  systemPrompt: 'You are a helpful assistant.',
  temperature: 0.7,           // Sampling temperature (0-2)
  maxTokens: 4096,            // Max tokens in response
  timeoutSecs: 120,           // Request timeout
  maxSteps: 10,               // Max ReAct steps
  // Rate limiting
  rateLimitCapacity: 40,
  rateLimitWindowSecs: 60,
  rateLimitMaxRetries: 3,
  // Circuit breaker
  circuitBreakerMaxFailures: 5,
  circuitBreakerCooldownSecs: 30,
}, bus);  // Optional: bus for RPC communication

agent.runSimple(task) — Run a simple task

Execute a task with automatic tool calling. Returns the final response string.

const response = await agent.runSimple('What is 100 * 100?');
console.log(response); // "100 * 100 = 10000"

agent.react(task) — Run with ReAct reasoning

Execute a task using explicit ReAct (Reason + Act) reasoning loop.

const response = await agent.react('Find files modified in the last hour');

agent.stream(task, callback) — Stream responses

Process tasks with streaming token support.

await agent.stream('Write a story', (err, token) => {
  if (err) {
    console.error('Error:', token.error);
    return;
  }

  switch (token.type) {
    case 'Text':
      process.stdout.write(token.text);
      break;
    case 'ReasoningContent':
      console.error('[Reasoning]', token.text);
      break;
    case 'ToolCall':
      console.log('[Tool]', token.name, token.args);
      break;
    case 'Done':
      console.log('\n[Complete]');
      break;
  }
});

agent.addTool(name, description, parameters, schema, callback) — Register a tool

Register a JavaScript function as an agent tool.

await agent.addTool(
  'weather',
  'Get weather for a city',
  JSON.stringify({
    city: { type: 'string', description: 'City name' }
  }),
  JSON.stringify({
    type: 'object',
    properties: {
      city: { type: 'string', description: 'City name' }
    },
    required: ['city']
  }),
  (err, args) => {
    // args = { city: 'Tokyo' }
    return JSON.stringify({ temp: 22, condition: 'sunny' });
  }
);

agent.addBashTool(name, workspaceRoot?) — Add bash execution

Add a tool that executes shell commands with optional workspace isolation.

await agent.addBashTool('bash', '/path/to/workspace');
// Agent can now run: bash { command: "ls -la", cwd: "/path/to/workspace" }

agent.registerSkillsFromDir(dirPath) — Register skills

Load agent skills from a directory (see skills format in main BrainOS crate).

await agent.registerSkillsFromDir('./skills');

agent.addMcpServer(namespace, command, args) — Add MCP server

Connect to a local MCP server process.

await agent.addMcpServer(
  'filesystem',           // Namespace for tools
  'npx',                  // Command
  ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/dir']
);

agent.addMcpServerHttp(namespace, url) — Connect to HTTP MCP server

Connect to an MCP server over HTTP/SSE.

await agent.addMcpServerHttp('mcp-server', 'https://mcp.example.com/sse');

agent.listMcpTools(), listMcpResources(), listMcpPrompts()

List available MCP tools, resources, and prompts.

const tools = await agent.listMcpTools();
const resources = await agent.listMcpResources('filesystem');
const prompts = await agent.listMcpPrompts();

agent.registerHook(event, callback) — Register lifecycle hooks

Intercept agent events and optionally modify behavior.

agent.registerHook('BeforeToolCall', (err, ctx) => {
  console.log('About to call:', ctx.data.toolName);
  return 'continue'; // or 'abort' to block
});

Hook Events:

  • BeforeToolCall — Before a tool is executed
  • AfterToolCall — After a tool completes
  • BeforeLlmCall — Before LLM request
  • AfterLlmCall — After LLM response
  • OnMessage — On each message in conversation
  • OnComplete — When agent finishes
  • OnError — On error

agent.registerPlugin(...) — Register a plugin

Add a plugin to intercept LLM requests/responses and tool calls.

agent.registerPlugin(
  'my-plugin',
  (err, req) => { /* modify LLM request */ return req; },
  (err, resp) => { /* modify LLM response */ return resp; },
  (err, call) => { /* intercept tool call */ return call; },
  (err, result) => { /* modify tool result */ return result; }
);

Message Management

// Add a message to the conversation
await agent.addMessage({ role: 'user', content: 'Hello' });

// Get all messages
const messages = agent.getMessages();

// Save/restore conversation state
agent.saveMessageLog('./conversation.json');
agent.restoreMessageLog('./conversation.json');

// Session context (arbitrary key-value store)
agent.setSessionContext({ key: 'value' });
const context = agent.sessionContext();
agent.clearSessionContext();

// Save/restore full session
agent.saveSession('./session.json');
agent.restoreSession('./session.json');

// Compact-message log for long conversations
agent.compactMessageLog();

AgentWrapper (from BrainOS)

Bus (Message Bus)

Distributed message bus for inter-agent and process communication.

Bus.create(config?) — Create a message bus

const bus = await Bus.create({
  mode: 'peer',              // 'peer', 'client', or 'server'
  connect: ['addr1', 'addr2'], // Addresses to connect to
  listen: ['addr1'],          // Addresses to listen on
  peer: 'my-peer-id'          // Peer identifier
});

bus.publishText(topic, payload) / bus.publishJson(topic, data)

Publish a message to a topic.

await bus.publishText('events', 'Hello subscribers!');
await bus.publishJson('data', { key: 'value' });

bus.createPublisher(topic) — Create a publisher

const publisher = await bus.createPublisher('my-topic');
await publisher.publishText('message 1');
await publisher.publishJson({ event: 'data' });

bus.createSubscriber(topic) — Create a subscriber

const subscriber = await bus.createSubscriber('my-topic');

// Blocking receive
const msg = await subscriber.recv();
const msg = await subscriber.recvWithTimeoutMs(5000);

// Or run a handler
await subscriber.run((err, msg) => {
  console.log('Received:', msg);
});

// Stop the subscriber
await subscriber.stop();

bus.createQuery(topic) — Request/response queries

const query = await bus.createQuery('compute');

// On the responding side:
const queryable = await bus.createQueryable('compute');
await queryable.setHandler(async (err, input) => {
  return JSON.stringify({ result: compute(input) });
});
await queryable.start();

// Make a query:
const response = await query.queryText('calculate 2+2');
// or with timeout:
const response = await query.queryTextTimeoutMs('calculate 2+2', 5000);

bus.createCaller(name) / bus.createCallable(uri) — RPC

Remote procedure call support.

// Caller
const caller = await bus.createCaller('service-name');
const result = await caller.callText('request data');

// Callable (service)
const callable = await bus.createCallable('my-service');
await callable.setHandler(async (err, input) => {
  return await processRequest(input);
});
await callable.start();

HookRegistry

Standalone hook registry for external use.

const registry = new HookRegistry();

await registry.register('BeforeToolCall', (err, ctx) => {
  console.log('Tool call:', ctx.agentId, ctx.data);
  return 'continue';
});

McpClient

Standalone MCP client (not requiring an agent).

import { McpClient } from '@open1s/jsbos';

// From command
const client = await McpClient.spawn('npx', ['-y', '@modelcontextprotocol/server-filesystem', '/tmp']);
await client.initialize();

// Or HTTP
const client = McpClient.connectHttp('http://127.0.0.1:8000/mcp');
await client.initialize();

// Or HTTPS
const client = McpClient.connectHttp('https://mcp.example.com/mcp');
await client.initialize();

// Use MCP
const tools = await client.listTools();
const result = await client.callTool('tool-name', JSON.stringify({ arg: 'value' }));
const prompts = await client.listPrompts();
const resources = await client.listResources();
const resource = await client.readResource('resource-uri');

ConfigLoader

Load configuration from files.

const loader = new ConfigLoader();
loader.discover();           // Auto-discover config files
loader.addFile('./config.json');
loader.addDirectory('./configs');
loader.addInline({ key: 'value' });

const config = JSON.parse(loader.loadSync());

Logging

import { initTracing, logTestMessage } from '@open1s/jsbos';

// Initialize tracing (for debugging)
initTracing();
logTestMessage('Debug message');

Configuration

Create a config file at ~/.bos/conf/config.toml:

# OpenAI-compatible endpoint
[global_model]
api_key = "your-api-key"
base_url = "https://api.openai.com/v1"
model = "gpt-4"

# NVIDIA NIM
[llm.nvidia]
api_key = "nv-..."
base_url = "https://integrate.api.nvidia.com/v1"
model = "nvidia/llama-3.1-nemotron-70b-instruct"

# Google AI (Gemini, etc.)
[llm.google]
api_key = "google-api-key"
base_url = "https://generativelanguage.googleapis.com/v1"
model = "gemini-pro"

# OpenRouter
[llm.openrouter]
api_key = "or-..."
base_url = "https://openrouter.ai/api/v1"
model = "anthropic/claude-3-haiku"

[bus]
mode = "peer"
listen = ["127.0.0.1:7890"]

Or set environment variables:

  • OPENAI_API_KEY — API key
  • LLM_BASE_URL — Base URL (default: NVIDIA API)
  • LLM_MODEL — Model name

Examples

See the examples directory for complete examples:

| Example | Description | |---------|-------------| | brainos_demo.js | High-level BrainOS API | | demo_multimodal.js | Multimodal (text, image, audio) content | | demo_audio.js | Audio content with LLM | | demo_content_api.js | Content API (text, images, audio) | | agent_demo.js | Agent with tools | | agent_mcp_demo.js | Agent with MCP servers | | agent_stream_demo.js | Streaming responses | | agent_metrics_demo.js | Performance metrics | | agent_skill_demo.js | Agent skills from directory | | agent_resilience_demo.js | Rate limiting + circuit breaker | | session_demo.js | Session save/restore/compact | | bus_demo.js | Pub/sub messaging | | caller_demo.js | RPC pattern | | query_demo.js | Request/response queries | | mcp_demo.js | Standalone MCP client | | mcp_http_demo.js | HTTP MCP connections | | demo-hooks.js | Lifecycle hooks | | demo-plugins.js | Plugin system | | config_demo.js | Configuration loading | | elegant-api-examples.js | Tools, plugins, hooks, streaming, session, skills |

Run an example:

node examples/agent_demo.js

Development

# Install dependencies
yarn

# Build native addon
yarn build

# Build for release
yarn build:release

# Run tests
yarn test

# Format code
yarn format

Architecture

┌─────────────────────────────────────────────────────────────┐
│                        JavaScript/Node.js                    │
├─────────────────────────────────────────────────────────────┤
│  @open1s/jsbos (NAPI-RS bindings)                           │
│  ┌──────────┐ ┌──────────┐ ┌──────┐ ┌───────┐ ┌──────────┐ │
│  │ BrainOS  │ │ToolDef   │ │ Bus  │ │ Hooks │ │McpClient │ │
│  └────┬─────┘ └────┬─────┘ └──┬───┘ └───┬───┘ └────┬─────┘ │
│       │            │           │         │            │       │
│  ┌────┴────────────┴───────────┴─────────┴────────────┴────┐ │
│  │                    Agent                                │ │
│  └────────────────────┬────────────────────────────────────┘ │
└───────────────────────┼─────────────────────────────────────┘
                        ▼
┌─────────────────────────────────────────────────────────────┐
│                    BrainOS (Rust Core)                       │
│  agent/ │ bus/ │ config/ │ logging/ │ react/ │ qserde/      │
└─────────────────────────────────────────────────────────────┘

License

MIT