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

@cuylabs/agent-core

v0.4.0

Published

Embeddable AI agent infrastructure - streaming, sessions, resilience, capabilities

Readme

@cuylabs/agent-core

Embeddable AI agent infrastructure using Vercel AI SDK. Core building blocks for streaming AI agents with session management, resilience, and model capabilities.

Features

  • Agent Framework — Create AI agents with tool support and streaming responses
  • Session Management — Persistent conversation state with branching support
  • LLM Streaming — Real-time streaming with proper backpressure handling
  • Error Resilience — Automatic retry with exponential backoff
  • Context Management — Token counting and automatic context pruning
  • Tool Framework — Type-safe tool definitions with Zod schemas
  • Middleware — Composable lifecycle hooks for tool interception, prompt injection, logging, and guardrails
  • Skills — Modular knowledge packs with progressive disclosure (L1 summary → L2 content → L3 resources)
  • Approval System — Configurable tool approval via middleware (rules + interactive prompts)
  • Checkpoint System — Undo/restore capabilities for file operations
  • Model Capabilities — Runtime model capability detection
  • MCP Support — Extend agents with Model Context Protocol servers
  • Sub-Agents — Fork agents with inherited config, run tasks in parallel, or let the LLM delegate via invoke_agent
  • Presets — Reusable agent configurations with tool filtering

Installation

npm install @cuylabs/agent-core
# or
pnpm add @cuylabs/agent-core

You'll also need at least one AI SDK provider:

npm install @ai-sdk/openai
# or @ai-sdk/anthropic, @ai-sdk/google

For OpenAI-compatible endpoints (local or hosted), add:

npm install @ai-sdk/openai-compatible

Quick Start

import { createAgent, Tool } from "@cuylabs/agent-core";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";

// Define tools
const greet = Tool.define("greet", {
  description: "Greet a user by name",
  parameters: z.object({
    name: z.string().describe("Name to greet"),
  }),
  execute: async ({ name }) => ({
    title: "Greeting",
    output: `Hello, ${name}!`,
    metadata: {},
  }),
});

// Create agent
const agent = createAgent({
  model: openai("gpt-4o"),
  tools: [greet],
  systemPrompt: "You are a helpful assistant.",
});

// Stream responses
for await (const event of agent.chat("session-1", "Hello!")) {
  switch (event.type) {
    case "text-delta":
      process.stdout.write(event.text);
      break;
    case "tool-start":
      console.log(`Calling tool: ${event.toolName}`);
      break;
    case "tool-result":
      console.log(`Tool result: ${event.result}`);
      break;
    case "complete":
      console.log("\nDone!");
      break;
  }
}

API Reference

Local Models (Ollama Example)

import { createAgent, createModelResolver } from "@cuylabs/agent-core";

const resolveModel = createModelResolver({
  engines: {
    ollama: {
      adapter: "openai-compatible",
      settings: {
        baseUrl: "http://localhost:11434/v1",
      },
    },
  },
});

const agent = createAgent({
  model: resolveModel("ollama/llama3.1"),
  cwd: process.cwd(),
});

Agent

import { createAgent, Agent } from "@cuylabs/agent-core";
import { openai } from "@ai-sdk/openai";

const agent = createAgent({
  model: openai("gpt-4o"),
  cwd: "/path/to/project",
  tools: myTools,
  systemPrompt: "You are a helpful assistant.",
  temperature: 0.7,
  maxSteps: 10,
});

// Streaming chat
for await (const event of agent.chat(sessionId, message)) {
  // Handle events
}

Session Management

import { 
  SessionManager, 
  MemoryStorage, 
  FileStorage 
} from "@cuylabs/agent-core";

// In-memory storage (default)
const memoryStorage = new MemoryStorage();

// File-based persistent storage
const fileStorage = new FileStorage({
  dataDir: "/path/to/data",
});

const sessions = new SessionManager(fileStorage);
await sessions.createSession({ id: "my-session" });

Tool Framework

import { Tool } from "@cuylabs/agent-core";
import { z } from "zod";

const calculator = Tool.define("calculator", {
  description: "Evaluate a math expression",
  parameters: z.object({
    expression: z.string(),
  }),
  execute: async ({ expression }, ctx) => {
    // ctx provides sessionID, cwd, abort signal, host, etc.
    return {
      title: "Calculator",
      output: String(eval(expression)), // Don't actually do this!
      metadata: {},
    };
  },
});

Middleware

Composable lifecycle hooks for tool interception, prompt injection, logging, and guardrails:

import { createAgent, type AgentMiddleware, approvalMiddleware } from "@cuylabs/agent-core";

// Simple logging middleware
const logger: AgentMiddleware = {
  name: "logger",
  async beforeToolCall(tool, args) {
    console.log(`→ ${tool}`, args);
    return { action: "allow" };
  },
  async afterToolCall(tool, _args, result) {
    console.log(`← ${tool}`, result.title);
    return result;
  },
  async onChatStart(sessionId, message) {
    console.log(`Chat started: ${sessionId}`);
  },
  async onChatEnd(sessionId, { usage, error }) {
    console.log(`Chat ended: ${usage?.totalTokens} tokens`);
  },
};

// Guardrail middleware — block dangerous tools
const guardrail: AgentMiddleware = {
  name: "guardrail",
  async beforeToolCall(tool) {
    if (tool === "bash") {
      return { action: "deny", reason: "Shell commands are disabled." };
    }
    return { action: "allow" };
  },
};

const agent = createAgent({
  model: openai("gpt-4o"),
  tools: myTools,
  middleware: [
    logger,
    guardrail,
    approvalMiddleware({
      rules: [{ pattern: "*", tool: "read_file", action: "allow" }],
      onRequest: async (req) => {
        // Prompt user for approval
        return await askUser(req);
      },
    }),
  ],
});

Middleware hooks: beforeToolCall, afterToolCall, promptSections, onEvent, onChatStart, onChatEnd. Sub-agents inherit middleware via fork().

Skills

Modular knowledge packs with three-level progressive disclosure:

import { createAgent, createSkillRegistry, createSkillTools } from "@cuylabs/agent-core";

// Discover skills from SKILL.md files
const registry = await createSkillRegistry(process.cwd(), {
  externalDirs: [".agents", ".claude"],
});

// Create skill tools (skill + skill_resource)
const skillTools = createSkillTools(registry);

// Inject L1 summary into system prompt, give agent skill tools
const agent = createAgent({
  model: openai("gpt-4o"),
  tools: [...myTools, ...skillTools],
  systemPrompt: `You are a coding assistant.\n\n${registry.formatSummary()}`,
});

Skills use the SKILL.md format with YAML frontmatter. See examples/skills/ for samples.

Built-in Sub-Agent Tools

Let the LLM delegate work to specialized sub-agents via tool calls:

import { createAgent, createSubAgentTools, Presets } from "@cuylabs/agent-core";
import type { AgentProfile } from "@cuylabs/agent-core";

const profiles: AgentProfile[] = [
  { name: "explorer", description: "Fast code search", preset: Presets.explore },
  { name: "reviewer", description: "Thorough code review", preset: Presets.review },
];

const parent = createAgent({ model, tools: codeTools });
const subTools = createSubAgentTools(parent, { profiles, async: true });

const agent = createAgent({
  model,
  tools: [...codeTools, ...subTools],
});
// The LLM can now call invoke_agent, wait_agent, and close_agent

Tools: invoke_agent (spawn), wait_agent (collect results), close_agent (cancel). Supports sync and async modes, depth limiting, and concurrency control. See docs/subagents.md.

Error Handling & Retry

import { 
  withRetry, 
  LLMError, 
  isRetryable,
  getRetryDelay 
} from "@cuylabs/agent-core";

const result = await withRetry(
  async () => {
    // Your operation
  },
  {
    maxRetries: 3,
    initialDelay: 1000,
    maxDelay: 30000,
  }
);

Context Management

import { 
  ContextManager,
  estimateTokens,
  pruneContext 
} from "@cuylabs/agent-core";

const ctx = new ContextManager({
  maxInputTokens: 100000,
  pruneThreshold: 0.9,
});

const tokens = estimateTokens("Your text here");

Model Capabilities

import { 
  ModelCapabilityResolver,
  getDefaultResolver 
} from "@cuylabs/agent-core";

const resolver = getDefaultResolver();
const caps = await resolver.resolve("gpt-4o");

console.log(caps.supportsImages);
console.log(caps.supportsToolUse);
console.log(caps.maxOutputTokens);

MCP (Model Context Protocol)

import { 
  createAgent, 
  createMCPManager, 
  stdioServer 
} from "@cuylabs/agent-core";
import { anthropic } from "@ai-sdk/anthropic";

// Create MCP manager with servers
const mcp = createMCPManager({
  filesystem: stdioServer("npx", [
    "-y", "@modelcontextprotocol/server-filesystem", "/tmp"
  ]),
});

// Create agent with MCP tools
const agent = createAgent({
  model: anthropic("claude-sonnet-4-20250514"),
  mcp,
});

// MCP tools are automatically available
const result = await agent.send("session", "List files in /tmp");

// Clean up
await agent.close();

Event Types

The chat() method yields these event types:

| Event Type | Description | |------------|-------------| | text-delta | Streaming text chunk | | text-start / text-end | Text generation boundaries | | tool-start | Tool invocation started | | tool-result | Tool execution completed | | tool-error | Tool execution failed | | step-start / step-finish | LLM step boundaries with usage stats | | reasoning-delta | Model reasoning chunk (if supported) | | status | Agent state changes (thinking, calling-tool, etc.) | | doom-loop | Repeated tool call pattern detected | | context-overflow | Context window exceeded | | message | Complete user/assistant message | | complete | Stream finished with usage stats | | error | Unrecoverable error |

See examples/03-streaming.ts for a complete event handling example.

Concurrency Note

When using runConcurrent() to run multiple tasks in parallel, be aware that all tasks share the same SessionManager instance. For independent conversations, create separate Agent instances or use distinct session IDs.

Examples

See examples/ for 17 runnable examples covering every feature — from basic chat to middleware, skills, and Docker execution. The examples README has setup instructions and run commands.

Documentation

See docs/ for in-depth guides on each subsystem.