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

simple-agents-node

v0.5.2

Published

Node.js bindings for SimpleAgents using napi-rs

Readme

simple-agents-napi

Node.js bindings for SimpleAgents using napi-rs.

Build

npm install
npm run build

Testing

  • npm test — unit tests + binding contract tests (no network).
  • npm run test:live — optional integration tests; skipped unless OPENAI_API_KEY or CUSTOM_API_KEY, plus CUSTOM_API_MODEL and PROVIDER are set. From the repo root, make test-node and make check-publish load the root .env (if present) before running test:live.

Usage

const { Client } = require('./index.js');

const provider = process.env.PROVIDER;
const model = process.env.CUSTOM_API_MODEL;
const key = process.env.CUSTOM_API_KEY;
const base = process.env.CUSTOM_API_BASE;

if (!provider || !model || !key) {
  throw new Error('Set PROVIDER, CUSTOM_API_KEY, and CUSTOM_API_MODEL.');
}

if (provider === 'openai') {
  process.env.OPENAI_API_KEY = key;
  if (base) process.env.OPENAI_API_BASE = base;
}
if (provider === 'anthropic') {
  process.env.ANTHROPIC_API_KEY = key;
}
if (provider === 'openrouter') {
  process.env.OPENROUTER_API_KEY = key;
  if (base) process.env.OPENROUTER_API_BASE = base;
}

const client = new Client(provider);

async function main() {
  const response = await client.complete(
    model,
    [
      { role: 'system', content: 'You are concise.' },
      { role: 'user', content: 'Say hi from Node.' },
    ],
    { max_tokens: 64, temperature: 0.7 },
  );

  console.log(response.content);
  console.log(response.usage);
  console.log(response.healed); // present when using healed_json/schema mode

  // Streaming (legacy chunk callback)
  const streamed = await client.stream(
    model,
    'Say hello in two words.',
    (chunk) => {
      if (chunk.content) process.stdout.write(chunk.content);
      if (chunk.finish_reason) console.log('\nfinish:', chunk.finish_reason);
    },
    {},
  );
  console.log('streamed content:', streamed.content);

  // Streaming (typed event callback)
  await client.streamEvents(
    model,
    'Say hello in two words.',
    (event) => {
      if (event.eventType === 'delta' && event.delta?.content) {
        process.stdout.write(event.delta.content);
      }
      if (event.eventType === 'error') {
        console.error('\nstream error:', event.error?.message);
      }
      if (event.eventType === 'done') {
        console.log('\nstream done');
      }
    },
    {},
  );

  // Healed JSON
  const healed = await client.complete(
    'gpt-4',
    'Respond with JSON: {"message": "hello"}',
    { mode: 'healed_json' },
  );
  console.log('parsed JSON value:', healed.healed?.value);

  // Workflow YAML (sync) — messages-first request (see docs/WORKFLOW_API_MIGRATION.md)
  const workflowOutput = client.run({
    workflowPath: 'workflow.yaml',
    messages: [
      { role: 'user', content: 'Classify this email about an invoice from Google.' },
    ],
    healing: false,
    workflowStreaming: false,
    nodeLlmStreaming: true,
    workflowOptions: { includeEvents: true },
  });
  console.log('terminal output:', workflowOutput.terminal_output);

  // Workflow YAML (async + live events)
  const asyncOutput = await client.stream(
    {
      workflowPath: 'workflow.yaml',
      messages: [
        { role: 'user', content: 'Classify this email about an invoice from Google.' },
      ],
      healing: false,
      workflowStreaming: true,
      nodeLlmStreaming: true,
      workflowOptions: { telemetry: { nerdstats: true } },
    },
    (err, eventJson) => {
      if (err) {
        console.error('event error:', err);
        return;
      }
      console.log('event:', eventJson);
    },
  );
  console.log('async terminal output:', asyncOutput.terminal_output);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

Notes

  • Use client.run / client.stream for messages-first workflow requests (WorkflowYamlRunRequest), or client.runWorkflow / client.streamWorkflow when you already have normalized workflow input. Typed workflowOptions use WorkflowRunOptionsNapi (model, telemetry, trace, includeEvents). For stream events, require('simple-agents-node/workflow_event').parseWorkflowEvent(eventJson) parses the JSON string into a typed object.
  • Canonical env contract for examples/tests is: PROVIDER, CUSTOM_API_KEY, CUSTOM_API_BASE (optional), CUSTOM_API_MODEL (also referenced as CUSTOM_API_* in places).
  • For OpenAI provider compatibility, map CUSTOM_API_* to OPENAI_API_* when needed (OPENAI_API_KEY, OPENAI_API_BASE, OPENAI_MODEL).
  • max_tokens, temperature, and top_p are optional. Use mode: "healed_json" for parsed JSON or mode: "schema" with a schema object to coerce/validate.
  • complete resolves with the first choice, usage metadata, and optional healed/coerced metadata.
  • stream invokes a chunk callback and resolves with aggregated content (healing/schema not yet supported for streams).
  • streamEvents is the canonical typed streaming callback API with delta, error, and done events.
  • Set CUSTOM_API_BASE, CUSTOM_API_KEY, CUSTOM_API_MODEL, and PROVIDER to run tests/examples consistently across bindings.

Test Layers

  • npm run test:unit - runtime/export sanity checks
  • npm run test:contract - shared fixture parity contract checks
  • npm run test:live - provider-backed live checks (env-gated)