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

nyaasu

v0.1.0

Published

A clean, modular AI agent framework with zero runtime dependencies

Readme

Nyaasu

A clean, modular AI agent framework with zero runtime dependencies.

Nyaasu provides a harness-first architecture for building AI agents and orchestrating them through finite state machine workflows. It handles the execution loop, tool calls, memory, structured output, and safety controls — while staying entirely provider-agnostic.

Features

  • Zero runtime dependencies — only Node.js built-ins (node:sqlite, node:crypto)
  • Harness-first execution — agents never call LLMs directly; everything flows through a controlled loop
  • Provider-agnostic — implement the LLM interface for any model provider
  • Type-safe workflows — FSM orchestration with generic state and compile-time guarantees
  • Result types — predictable error handling via Result<T, E> instead of exceptions
  • Config cascade — system → workflow → agent configuration inheritance
  • Built-in memory — SQLite + FTS5 persistent memory per agent
  • Structured output — JSON schema validation with automatic retry
  • Safety controls — budget guards, input/output guardrails, abort propagation
  • Execution patterns — sub-agents, reflection loops, iterative execution
  • Strict validation — definition-time integrity checks with actionable error messages
  • Test utilities — mock providers and isolated test runners shipped with the package

Requirements

  • Node.js >= 22.5.0 (required for node:sqlite)
  • TypeScript 5.x (strict mode, ESM-only)

Installation

npm install nyaasu

Quick Start

Define an Agent

import { createAgent } from "nyaasu";
import type { Tool } from "nyaasu";

const searchTool: Tool = {
  name: "web_search",
  description: "Search the web for information",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string" },
    },
    required: ["query"],
  },
  execute: async (input) => {
    const { query } = input as { query: string };
    return { output: `Results for: ${query}` };
  },
};

const researcher = createAgent({
  id: "researcher",
  role: { system: "You are a research assistant. Use tools to find information." },
  tools: [searchTool],
  skills: [],
});

Run an Agent (Testing)

import { testAgent } from "nyaasu/testing";

const result = await testAgent(researcher, {
  input: "Find information about TypeScript 5.x features",
  provider: [
    {
      text: "",
      toolCalls: [{ id: "1", name: "web_search", input: { query: "TypeScript 5.x features" } }],
      stopReason: "tool_use",
      usage: { inputTokens: 100, outputTokens: 50 },
    },
    {
      text: "TypeScript 5.x includes decorators, const type parameters, and more.",
      toolCalls: [],
      stopReason: "end",
      usage: { inputTokens: 200, outputTokens: 100 },
    },
  ],
});

console.log(result.output); // "TypeScript 5.x includes..."

Build a Workflow

import { createWorkflow } from "nyaasu";

interface PipelineState {
  topic: string;
  research: string | null;
  summary: string | null;
}

const pipeline = createWorkflow<PipelineState>({
  id: "research-pipeline",
  initialState: { topic: "AI agents", research: null, summary: null },
  nodes: [
    {
      id: "research",
      start: true,
      agent: { definition: researcher },
      run: async (ctx) => {
        const result = await ctx.runAgent(ctx.state.topic);
        return {
          status: "done",
          output: result.output,
          stateUpdates: { research: result.output as string },
        };
      },
    },
    {
      id: "summarize",
      end: true,
      run: async (ctx) => {
        return {
          status: "done",
          stateUpdates: { summary: `Summary of: ${ctx.state.research}` },
        };
      },
    },
  ],
  transitions: [{ from: "research", to: "summarize" }],
});

Structured Output

const analyzer = createAgent({
  id: "analyzer",
  role: { system: "Analyze sentiment. Return structured JSON." },
  tools: [],
  skills: [],
  outputSchema: {
    schema: {
      type: "object",
      properties: {
        sentiment: { type: "string", enum: ["positive", "negative", "neutral"] },
        confidence: { type: "number" },
      },
      required: ["sentiment", "confidence"],
    },
    maxRetries: 2,
  },
});

Architecture

┌─────────────────────────────────────────────────────┐
│  Workflow Layer (FSM Orchestrator)                   │
│  createWorkflow() → nodes + transitions             │
├─────────────────────────────────────────────────────┤
│  Agent Layer                                        │
│  createAgent() → definition + access control        │
├─────────────────────────────────────────────────────┤
│  Harness Layer (Execution Engine)                   │
│  runLoop() → LLM invoke → tools → repeat           │
│  ┌──────────┐  ┌──────────┐  ┌───────────────┐    │
│  │ Patterns │  │ Control  │  │ Structured    │    │
│  │ sub-agent│  │ budget   │  │ Output        │    │
│  │ reflect  │  │ guardrail│  │ validation    │    │
│  │ loop-iter│  │ abort    │  │ + retry       │    │
│  └──────────┘  └──────────┘  └───────────────┘    │
├─────────────────────────────────────────────────────┤
│  Infrastructure                                     │
│  Provider (LLM interface) │ Config │ Memory │ Types │
└─────────────────────────────────────────────────────┘

Subpath Exports

Import only what you need:

import { createAgent, runLoop } from "nyaasu";           // Core API
import { runLoop } from "nyaasu/harness";                 // Harness only
import { createSqliteStore } from "nyaasu/memory";        // Memory system
import { createWorkflow } from "nyaasu/workflow";          // Workflow engine
import { createMockProvider, testAgent } from "nyaasu/testing"; // Test utilities

Provider Interface

Nyaasu is provider-agnostic. Implement the LLM interface to connect any model:

import type { LLM, LLMResponse, StreamChunk } from "nyaasu";

const myProvider: LLM = {
  async invoke(messages, options) {
    // Call your LLM API here
    return {
      text: "response",
      toolCalls: [],
      stopReason: "end",
      usage: { inputTokens: 0, outputTokens: 0 },
    };
  },
  async *stream(messages, options) {
    yield { type: "text", text: "response" };
    yield {
      type: "done",
      response: {
        text: "response",
        toolCalls: [],
        stopReason: "end",
        usage: { inputTokens: 0, outputTokens: 0 },
      },
    };
  },
};

Memory System

Each agent gets its own persistent SQLite memory store with full-text search:

import { createSqliteStore, createMemoryTools } from "nyaasu/memory";

const store = createSqliteStore({
  agentId: "my-agent",
  path: ".nyaasu/memory/my-agent.db",
});

// Memory tools are automatically injected when memory.enabled = true
const tools = createMemoryTools({ store, agentId: "my-agent" });
// Provides: memory_store, memory_search, memory_list, memory_delete

Config Cascade

Configuration merges across three levels with field-level override:

import { defineConfig } from "nyaasu";

const systemConfig = defineConfig({
  provider: { model: "gpt-4o", temperature: 0.7, maxTokens: 4096 },
  budget: { maxTokens: 100_000, maxIterations: 50, timeout: 120_000 },
  context: { strategy: "full" },
});

// Workflow config overrides system → agent config overrides workflow

Safety & Controls

Budget Guard

Enforces token, iteration, and time limits per agent run:

const agent = createAgent({
  id: "bounded",
  role: { system: "..." },
  tools: [],
  skills: [],
  config: {
    budget: { maxTokens: 10_000, maxIterations: 5, timeout: 30_000 },
  },
});

Guardrails

Validate input/output with optional retry:

import type { Guardrail } from "nyaasu";
import { ok, err } from "nyaasu";

const noSecrets: Guardrail = {
  name: "no-secrets",
  validate: (content) =>
    content.includes("SECRET") ? err("Output contains secrets") : ok(undefined),
  retryable: true,
  maxRetries: 2,
};

Abort / Cancellation

Full abort signal propagation from workflow down to provider calls:

const controller = new AbortController();
const result = await workflow.run({ signal: controller.signal });

// Cancel at any time
controller.abort();

Testing

Nyaasu ships test utilities for deterministic agent testing:

import { createMockProvider, testAgent, testWorkflow } from "nyaasu/testing";

// Mock provider returns scripted responses in order
const mock = createMockProvider([
  { text: "Hello!", toolCalls: [], stopReason: "end", usage: { inputTokens: 10, outputTokens: 5 } },
]);

// Isolated agent test
const result = await testAgent(myAgent, {
  input: "Hi",
  provider: mock,
});

// Full workflow E2E test
const wfResult = await testWorkflow(myWorkflow, {
  providers: { researcher: mock },
});

Project Templates

Agent-First (single agent)

my-agent/
├── src/
│   ├── agent.ts          # createAgent() definition
│   ├── tools/            # Agent tools
│   └── main.ts           # Entry point
├── nyaasu.config.ts      # System config
└── package.json

Workflow-First (multi-step orchestration)

my-project/
├── src/
│   ├── nodes/            # Workflow nodes (one folder each)
│   ├── agents/           # Reusable agent definitions
│   ├── workflows/        # Workflow definitions
│   ├── tools/            # Shared tools
│   └── main.ts
├── nyaasu.config.ts
└── package.json

Design Principles

  1. Zero runtime deps — only Node.js built-ins
  2. Harness-first — controlled execution loop for all agent interactions
  3. Result over exceptions — predictable error handling
  4. Strict validation — fail fast at definition time with clear messages
  5. Config cascade — sensible defaults with layer-by-layer override
  6. Provider-agnostic — adapters are external packages
  7. YAGNI — ship what's needed, defer what's not

Scripts

pnpm build       # Build with tsup
pnpm test        # Run tests (vitest)
pnpm test:watch  # Watch mode
pnpm lint        # Check with biome
pnpm lint:fix    # Auto-fix lint issues
pnpm typecheck   # Type check with tsc

License

MIT