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

@samrahimi/smol-js-alt

v0.7.4

Published

A TypeScript agentic framework with custom tools plugin system - CodeAgent and ToolUseAgent with YAML orchestration, drop-in custom tools, HTTP transport, and Exa.ai integration

Readme

smol-js

A TypeScript agentic framework inspired by smolagents.

Build AI agents that solve tasks autonomously using the ReAct (Reasoning + Acting) pattern. Agents can write and execute JavaScript code, call tools, delegate to other agents, and orchestrate complex workflows via YAML definitions.

npm version License: MIT

Features

  • Two Agent Types:
    • CodeAgent - Writes JavaScript code to solve tasks
    • ToolUseAgent - Uses native LLM function calling (OpenAI-style)
  • YAML Orchestration: Define complex agent workflows declaratively
  • Sandboxed Execution: JavaScript runs in Node's vm module with state persistence
  • Extensible Tool System: Built-in tools + easy custom tool creation
  • Nested Agents: Manager-worker patterns for hierarchical task delegation
  • Exa.ai Integration: Semantic web search, content extraction, and research automation
  • Dynamic Imports: Import npm packages on-the-fly via jsdelivr CDN
  • OpenAI-Compatible: Works with OpenRouter, OpenAI, Azure, Anthropic, and local servers
  • Streaming: Real-time output streaming from the LLM
  • Memory Management: Context-aware with truncate/compact strategies
  • Color-Coded Logging: Beautiful terminal output with session logging to disk

Installation

npm install @samrahimi/smol-js

Quick Start

Via CLI (YAML Workflows)

The easiest way to get started is using YAML workflows:

# Run directly with npx (no installation needed)
npx @samrahimi/smol-js workflow.yaml --task "Your task here"

# Or install globally and use the CLI
npm install -g @samrahimi/smol-js
smol-js workflow.yaml --task "Research quantum computing"

# Validate a workflow
npx @samrahimi/smol-js validate workflow.yaml

Example workflow (research-agent.yaml):

name: "Research Agent"
description: "An agent that can search the web and write reports"

model:
  modelId: "anthropic/claude-sonnet-4.5"
  baseUrl: "https://openrouter.ai/api/v1"
  maxTokens: 4000

tools:
  search:
    type: exa_search
    config:
      apiKey: "$EXA_API_KEY"

  write:
    type: write_file

agents:
  researcher:
    type: ToolUseAgent
    tools:
      - search
      - write
    maxSteps: 10
    customInstructions: "You are a thorough researcher. Always cite sources."

entrypoint: researcher

Programmatic Usage

import 'dotenv/config';
import { CodeAgent, OpenAIModel } from '@samrahimi/smol-js';

// Create the model (defaults to Claude via OpenRouter)
const model = new OpenAIModel({
  modelId: 'anthropic/claude-sonnet-4.5',
});

// Create the agent
const agent = new CodeAgent({
  model,
  maxSteps: 10,
});

// Run a task
const result = await agent.run('Calculate the first 10 prime numbers');
console.log(result.output); // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Agent Types

CodeAgent

Generates and executes JavaScript code to solve tasks. The agent has access to tools as async functions in its execution environment.

import { CodeAgent, OpenAIModel } from '@samrahimi/smol-js';

const agent = new CodeAgent({
  model,
  tools: [myTool],
  maxSteps: 20,
});

await agent.run('Analyze the file data.csv and create a summary');

How it works:

  1. Agent generates thought + JavaScript code
  2. Code executes in sandboxed VM
  3. Results become observations
  4. Repeats until final_answer() is called

ToolUseAgent

Uses native LLM function calling (OpenAI-style tool calling). Better for LLMs with strong tool-calling capabilities.

import { ToolUseAgent, OpenAIModel } from '@samrahimi/smol-js';

const agent = new ToolUseAgent({
  model,
  tools: [searchTool, readFileTool],
  maxSteps: 15,
  enableParallelToolCalls: true, // Execute independent tools in parallel
});

await agent.run('Search for recent AI papers and summarize the top 3');

Configuration

Environment Variables

# API key for LLM provider
OPENAI_API_KEY=sk-or-v1-your-openrouter-key
# or
OPENROUTER_API_KEY=sk-or-v1-your-key

# For Exa.ai tools
EXA_API_KEY=your-exa-api-key

Model Configuration

const model = new OpenAIModel({
  modelId: 'anthropic/claude-sonnet-4.5', // Model identifier
  apiKey: 'sk-...',                        // API key (or use env var)
  baseUrl: 'https://openrouter.ai/api/v1', // API endpoint
  maxTokens: 4096,                          // Max tokens to generate
  temperature: 0.7,                         // Generation temperature
  timeout: 120000,                          // Request timeout in ms
});

Agent Configuration

const agent = new CodeAgent({
  model,
  tools: [myTool],                          // Custom tools
  maxSteps: 20,                             // Max iterations (default: 20)
  codeExecutionDelay: 5000,                 // Safety delay before execution (default: 5000ms)
  customInstructions: '...',                // Additional system prompt instructions
  verboseLevel: LogLevel.INFO,              // Logging level
  streamOutputs: true,                      // Stream LLM output in real-time
  persistent: false,                        // Retain memory between run() calls
  maxContextLength: 100000,                 // Token limit for context
  memoryStrategy: 'truncate',               // 'truncate' or 'compact'
  additionalAuthorizedImports: ['lodash'], // npm packages (CodeAgent only)
  workingDirectory: '/path/to/dir',        // Working dir for fs operations
});

Built-in Tools

  • FinalAnswerTool: Return the final result (always available)
  • UserInputTool: Prompt for user input
  • ReadFileTool: Read file contents
  • WriteFileTool: Write to files
  • CurlTool: Make HTTP requests
  • ExaSearchTool: Semantic web search via Exa.ai
  • ExaGetContentsTool: Fetch and extract webpage content
  • ExaResearchTool: Multi-step research workflow
  • AgentTool: Wrap agents as tools for nested architectures

Creating Custom Tools

Class-Based Tools

import { Tool } from '@samrahimi/smol-js';
import type { ToolInputs } from '@samrahimi/smol-js';

class WeatherTool extends Tool {
  readonly name = 'get_weather';
  readonly description = 'Get current weather for a city';
  readonly inputs: ToolInputs = {
    city: {
      type: 'string',
      description: 'The city name',
      required: true,
    },
  };
  readonly outputType = 'object';

  async execute(args: Record<string, unknown>): Promise<unknown> {
    const city = args.city as string;
    const response = await fetch(`https://api.weather.com/${city}`);
    return response.json();
  }
}

const agent = new CodeAgent({
  model,
  tools: [new WeatherTool()],
});

Registering Tools for YAML Workflows

import { YAMLLoader, Orchestrator } from '@samrahimi/smol-js';
import { MyCustomTool } from './tools.js';

const loader = new YAMLLoader();

// Register custom tools by type name
loader.registerToolType('my_tool', MyCustomTool);

// Now use in YAML:
// tools:
//   custom:
//     type: my_tool
//     config:
//       apiKey: "$MY_API_KEY"

const workflow = loader.loadFromFile('./workflow.yaml');
const orchestrator = new Orchestrator();
await orchestrator.runWorkflow(workflow, 'Your task here');

YAML Workflow System

Define complex agent architectures declaratively:

name: "Multi-Agent Research System"
description: "Manager-worker pattern with specialized agents"

model:
  modelId: "anthropic/claude-sonnet-4.5"
  baseUrl: "https://openrouter.ai/api/v1"
  apiKey: "$OPENROUTER_API_KEY"

tools:
  search:
    type: exa_search
    config:
      apiKey: "$EXA_API_KEY"

  read:
    type: read_file

  write:
    type: write_file

agents:
  # Worker agent: specialized in research
  researcher:
    type: ToolUseAgent
    tools:
      - search
      - read
    maxSteps: 8
    temperature: 0.3
    customInstructions: "You are a research specialist. Be thorough and cite sources."

  # Worker agent: specialized in writing
  writer:
    type: CodeAgent
    tools:
      - write
    maxSteps: 5
    temperature: 0.7
    customInstructions: "You are a skilled technical writer. Create clear, engaging content."

  # Manager agent: delegates to workers
  manager:
    type: ToolUseAgent
    agents:
      - researcher  # Available as a tool
      - writer      # Available as a tool
    maxSteps: 10
    customInstructions: "You coordinate research and writing tasks. Delegate appropriately."

entrypoint: manager

Run it:

npx @samrahimi/smol-js research-workflow.yaml --task "Write a report on quantum computing"

Nested Agents (Manager-Worker Pattern)

Use agents as tools for hierarchical task delegation:

import { CodeAgent, ToolUseAgent, OpenAIModel, AgentTool } from '@samrahimi/smol-js';

// Create specialized worker agents
const mathAgent = new CodeAgent({
  model,
  maxSteps: 5,
  verboseLevel: LogLevel.OFF, // Quiet - manager handles output
});

const researchAgent = new ToolUseAgent({
  model,
  tools: [searchTool],
  maxSteps: 8,
  verboseLevel: LogLevel.OFF,
});

// Wrap workers as tools
const mathExpert = new AgentTool({
  agent: mathAgent,
  name: 'math_expert',
  description: 'Delegate math and calculation tasks to this agent',
});

const researcher = new AgentTool({
  agent: researchAgent,
  name: 'researcher',
  description: 'Delegate research and information gathering to this agent',
});

// Create manager that uses the workers
const manager = new ToolUseAgent({
  model,
  tools: [mathExpert, researcher],
  maxSteps: 10,
});

await manager.run('Research Tokyo population and calculate water consumption per capita');

Exa.ai Integration

Three tools for web research powered by Exa.ai:

ExaSearchTool

Semantic search with advanced filtering:

import { ExaSearchTool } from '@samrahimi/smol-js';

const searchTool = new ExaSearchTool({
  apiKey: process.env.EXA_API_KEY,
  numResults: 10,
  searchType: 'auto', // 'auto', 'neural', or 'keyword'
});

ExaGetContentsTool

Extract clean webpage content:

import { ExaGetContentsTool } from '@samrahimi/smol-js';

const contentTool = new ExaGetContentsTool({
  apiKey: process.env.EXA_API_KEY,
  textOnly: true,
});

ExaResearchTool

Agentic web research that writes comprehensive reports:

import { ExaResearchTool } from '@samrahimi/smol-js';

const researchTool = new ExaResearchTool({
  apiKey: process.env.EXA_API_KEY,
  model: 'exa-research', // or 'exa-research-fast', 'exa-research-pro'
});

// The Exa Research API is an asynchronous research agent that:
// 1. Plans the research approach
// 2. Executes searches across the web
// 3. Extracts and analyzes facts from sources
// 4. Synthesizes findings into a markdown report with citations
// 5. Returns the complete report (typically 20-90 seconds)

// Usage in agent:
await agent.run('Use exa_research to write a comprehensive report on quantum computing breakthroughs in 2024');

Built-in Capabilities (CodeAgent)

The CodeAgent sandbox includes:

| Category | Available | |----------|-----------| | Output | console.log(), console.error(), print() | | HTTP | fetch(), URL, URLSearchParams | | File System | fs.* (readFileSync, writeFileSync, etc.) | | Path | path.* (join, resolve, dirname, etc.) | | Data | JSON, Buffer, TextEncoder, TextDecoder | | Math | Math.*, parseInt(), parseFloat() | | Types | Object, Array, Map, Set, Date, RegExp, Promise | | Timers | setTimeout(), setInterval() | | Final | final_answer(value) - Return the result |

Dynamic npm Imports

const agent = new CodeAgent({
  model,
  additionalAuthorizedImports: ['lodash', 'dayjs', 'uuid'],
});

// Agent can now write:
// const _ = await importPackage('lodash');
// const result = _.uniq([1, 2, 2, 3]);

Packages are fetched from jsdelivr CDN and cached in ~/.smol-js/packages/.

Examples

See the examples/js/ directory for complete examples:

  • main.ts: Main demo with custom tools and YAML workflows
  • custom-tools.ts: Custom tool implementations (TimestampTool, TextStatsTool, SlugifyTool)
  • agents/: YAML workflow definitions
    • custom_tools.yaml: Workflow using custom tools
    • bloomberg.yaml: Bloomberg research workflow
    • policy.yaml: Policy analysis workflow
    • simple-test.yaml: Simple test workflow

Run an example:

cd examples/js
npm install
npx tsx main.ts

Memory Management

Agents track all execution steps and manage context automatically:

const agent = new CodeAgent({
  model,
  maxContextLength: 100000,    // Token limit
  memoryStrategy: 'truncate',  // or 'compact'
  persistent: false,           // Retain memory between run() calls
});

// Non-persistent (default): Fresh memory each run
await agent.run('Task 1');
await agent.run('Task 2'); // Doesn't remember Task 1

// Persistent: Maintains conversation context
const persistentAgent = new CodeAgent({ model, persistent: true });
await persistentAgent.run('Remember this: X = 42');
await persistentAgent.run('What is X?'); // Remembers X = 42

Memory Strategies:

  • truncate: Removes oldest steps when over token limit
  • compact: Uses LLM to summarize older steps

Session Logging

All sessions are logged to ~/.smol-js/:

  • session-<timestamp>.log - Full session transcript with color codes
  • packages/ - Cached npm packages from dynamic imports

API Reference

Agent Base Class

abstract class Agent {
  constructor(config: AgentConfig)
  run(task: string, reset?: boolean): Promise<RunResult>
  stop(): void
  reset(): void
  addTool(tool: Tool): void
  removeTool(name: string): boolean
  getMemory(): AgentMemory
}

CodeAgent

class CodeAgent extends Agent {
  constructor(config: CodeAgentConfig)
  getExecutor(): LocalExecutor
}

ToolUseAgent

class ToolUseAgent extends Agent {
  constructor(config: ToolUseAgentConfig)
}

interface ToolUseAgentConfig extends AgentConfig {
  enableParallelToolCalls?: boolean; // Execute independent tools in parallel
}

RunResult

interface RunResult {
  output: unknown;        // Final answer
  steps: MemoryStep[];    // Execution history
  tokenUsage: TokenUsage; // Token counts
  duration: number;       // Total time in ms
}

Tool

abstract class Tool {
  abstract readonly name: string;
  abstract readonly description: string;
  abstract readonly inputs: ToolInputs;
  abstract readonly outputType: string;

  abstract execute(args: Record<string, unknown>): Promise<unknown>;

  setup(): Promise<void>;
  call(args: Record<string, unknown>): Promise<unknown>;
  toCodePrompt(): string;          // For CodeAgent
  toOpenAITool(): OpenAITool;      // For ToolUseAgent
}

Orchestrator

class Orchestrator {
  constructor(config?: { verbose?: boolean })

  loadWorkflow(filePath: string): Workflow
  loadWorkflowFromString(yaml: string): Workflow
  runWorkflow(workflow: Workflow, task: string): Promise<void>
  runAgent(agent: Agent, task: string): Promise<void>
  getEventLog(): OrchestrationEvent[]
}

YAMLLoader

class YAMLLoader {
  registerToolType(typeName: string, toolClass: typeof Tool): void
  loadFromFile(filePath: string): Workflow
  loadFromString(yaml: string): Workflow
}

CLI Reference

# Run a workflow
npx @samrahimi/smol-js <workflow.yaml> [options]
npx @samrahimi/smol-js run <workflow.yaml> [options]

# Validate a workflow
npx @samrahimi/smol-js validate <workflow.yaml>

# Options
--task, -t <task>    Task description (prompted if not provided)
--quiet, -q          Reduce output verbosity
--help, -h           Show help message

Security Considerations

  • Sandboxed Execution: Code runs in Node's vm module, isolated from the main process
  • Authorized Imports: Only explicitly allowed npm packages can be imported
  • File System Isolation: fs operations are restricted to configured working directory
  • Execution Delay: Configurable delay before code execution allows user interruption (Ctrl+C)
  • Timeout Protection: Code execution has a configurable timeout (default: 30s)

Comparison with Python smolagents

| Feature | Python smolagents | smol-js | |---------|------------------|---------| | Code execution | Python interpreter | Node.js vm module | | Imports | import statement | await importPackage() | | Tool definition | @tool decorator | Class extending Tool | | Nested agents | ManagedAgent | AgentTool | | Async support | Optional | All tools are async | | HTTP requests | Requires tool | Built-in fetch() | | Remote executors | E2B, Docker, etc. | Local only | | Agent types | CodeAgent, ToolCallingAgent | CodeAgent, ToolUseAgent | | YAML workflows | ❌ | ✅ | | Exa.ai integration | ❌ | ✅ Built-in |

Contributing

Contributions are welcome! Please follow OOP principles and open an issue or PR on GitHub.

# Clone and install
git clone https://github.com/samrahimi/smolagents
cd smolagents/smol-js
npm install

# Build
npm run build

# Run tests
npm test

# Lint
npm run lint
npm run lint:fix

# Type check
npm run typecheck

License

MIT

Credits

This is a TypeScript framework inspired by smolagents by Hugging Face, with additional features including YAML orchestration, ToolUseAgent, and Exa.ai integration.