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

@agntz/core

v0.5.1

Published

TypeScript SDK for defining and running AI agents with first-class MCP support and pluggable storage

Downloads

1,429

Readme

@agntz/core

npm version License: MIT Node.js TypeScript

TypeScript SDK for defining and running AI agents. Agents are portable, JSON-serializable configurations — not code. Plug in any storage backend, any model provider, any tools.

This is the core package of the agntz monorepo.

Install

npm install @agntz/core @agntz/stores
# or
pnpm add @agntz/core @agntz/stores
# or
yarn add @agntz/core @agntz/stores

Then install at least one model provider (all optional peer dependencies):

npm install @ai-sdk/openai    # for OpenAI models
npm install @ai-sdk/anthropic  # for Anthropic models
npm install @ai-sdk/google     # for Google models

Set your API key:

export OPENAI_API_KEY=sk-...
# or ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, etc.

Quick Start

import { createRunner, defineAgent } from "@agntz/core";
import { MemoryStore } from "@agntz/stores/memory";

const runner = createRunner({ store: new MemoryStore() });

runner.registerAgent(defineAgent({
  id: "greeter",
  name: "Greeter",
  systemPrompt: "You are a friendly greeter. Keep responses under 2 sentences.",
  model: { provider: "openai", name: "gpt-5.6-terra" },
}));

const result = await runner.invoke("greeter", "Hello!");
console.log(result.output);
// → "Hey there! Welcome — great to have you here."

Manifest and hosted-operation contract

@agntz/core/manifest parses and validates the portable YAML contract used by the embedded SDK and hosted/self-hosted workers. The published schema is available from @agntz/core/schema and at https://agntz.co/schemas/agent-manifest.schema.json.

Manifest inputSchema, outputSchema, and callback-tool inputSchema fields accept canonical object-root JSON Schema Draft 2020-12, including nested objects, arrays, unions, local $ref, enums, and numeric/string constraints. The older flat property-map syntax remains readable for compatibility.

The manifest union contains six kinds: llm, transcription, image, tool, sequential, and parallel. @agntz/core supplies the parser and execution boundary for hosted model operations; a worker host supplies transcription and image adapters plus managed artifact storage.

Model declarations share portable controls such as maxTokens, topP, topK, penalties, stop sequences, seed, and retries. Put non-portable controls under a provider namespace:

model:
  provider: mistral
  name: mistral-small-2603
  temperature: 0.2
  maxTokens: 4096
  providerOptions:
    mistral:
      safePrompt: true

Hosted applications normally consume this surface through @agntz/client. See the provider-replacement guide for rich content, normalized results, artifacts, retention, and signed callback tools.

Usage

Defining Agents

Agents are plain data objects — JSON-serializable, portable, and versionable:

import { defineAgent } from "@agntz/core";

const agent = defineAgent({
  id: "writer",
  name: "Writer",
  description: "Writes concise, engaging copy",
  version: "1.0.0",
  systemPrompt: "You write concise, engaging copy.",
  model: { provider: "openai", name: "gpt-5.6-sol" },
  tags: ["content", "writing"],
});

Tools

Define typed tools with Zod schemas and register them with the runner:

import { createRunner, defineAgent, defineTool } from "@agntz/core";
import { z } from "zod";

const lookupOrder = defineTool({
  name: "lookup_order",
  description: "Look up an order by ID",
  input: z.object({ orderId: z.string() }),
  async execute(input) {
    return { status: "shipped", eta: "Tomorrow" };
  },
});

const runner = createRunner({ tools: [lookupOrder] });

runner.registerAgent(defineAgent({
  id: "support",
  name: "Support Agent",
  systemPrompt: "Help customers with their orders. Use tools to look up order info.",
  model: { provider: "openai", name: "gpt-5.6-sol" },
  tools: [{ type: "inline", name: "lookup_order" }],
}));

const result = await runner.invoke("support", "Where's my order #12345?");
console.log(result.toolCalls);
// → [{ name: "lookup_order", input: { orderId: "12345" }, output: { status: "shipped", ... } }]

Sessions (Conversational Memory)

// First message
await runner.invoke("support", "Hi, I need help", { sessionId: "sess_abc" });

// Second message — agent remembers the conversation
await runner.invoke("support", "My order is #12345", { sessionId: "sess_abc" });

Streaming

const stream = runner.stream("writer", "Write a short story about a robot");

for await (const event of stream) {
  if (event.type === "text-delta") {
    process.stdout.write(event.text);
  } else if (event.type === "tool-call-start") {
    console.log(`\nCalling tool: ${event.toolCall.name}`);
  } else if (event.type === "done") {
    console.log(`\nTokens used: ${event.result.usage.totalTokens}`);
  }
}

Stream events:

| Event | Description | |---|---| | text-delta | Incremental text chunk from the model | | tool-call-start | Tool execution is starting | | tool-call-end | Tool execution completed (with result) | | step-complete | One iteration of the tool loop finished | | done | Final result with full InvokeResult |

Agent Chains (Agent-as-Tool)

Agents can invoke other agents as tools:

runner.registerAgent(defineAgent({
  id: "researcher",
  name: "Researcher",
  systemPrompt: "Research topics and return concise findings.",
  model: { provider: "openai", name: "gpt-5.6-sol" },
}));

runner.registerAgent(defineAgent({
  id: "writer",
  name: "Writer",
  systemPrompt: "Write articles. Delegate research to the researcher.",
  model: { provider: "anthropic", name: "claude-sonnet-5" },
  tools: [{ type: "agent", agentId: "researcher" }],
}));

// Writer invokes researcher as a tool during execution
const result = await runner.invoke("writer", "Write about MCP");

Shared Context

Context lets agents share state without tight coupling:

Note: this section uses legacy contextIds scratchpad buckets. Runtime resource access uses context namespace grants instead.

// Researcher writes findings to context
await runner.invoke("researcher", "Find info about MCP", {
  contextIds: ["project-alpha"],
});

// Writer reads the same context
await runner.invoke("writer", "Write an article using the research", {
  contextIds: ["project-alpha"],
});

Runtime Tool Context

Pass runtime data to tools without going through the LLM:

const updateProfile = defineTool({
  name: "update_profile",
  description: "Update the user's profile",
  input: z.object({ field: z.string(), value: z.string() }),
  async execute(input, ctx) {
    // ctx.user comes from toolContext — injected at runtime
    await db.users.update(ctx.user.id, { [input.field]: input.value });
    return { success: true };
  },
});

await runner.invoke("chat", message, {
  toolContext: { user: { id: "u_123", name: "Aaron" } },
});

Structured Output

runner.registerAgent(defineAgent({
  id: "analyzer",
  name: "Sentiment Analyzer",
  systemPrompt: "Analyze the sentiment of input text.",
  model: { provider: "openai", name: "gpt-5.6-sol" },
  outputSchema: {
    type: "object",
    properties: {
      sentiment: { type: "string", enum: ["positive", "negative", "neutral"] },
      confidence: { type: "number" },
    },
    required: ["sentiment", "confidence"],
  },
}));

const { output } = await runner.invoke("analyzer", "I love this!");
const parsed = JSON.parse(output);
// → { sentiment: "positive", confidence: 0.95 }

MCP Integration

Use tools from any MCP-compatible server:

const runner = createRunner({
  mcp: {
    servers: {
      github: { url: "http://localhost:3001/mcp" },
      filesystem: { command: "npx", args: ["-y", "@anthropic/mcp-fs"] },
    },
  },
});

runner.registerAgent(defineAgent({
  id: "code-reviewer",
  name: "Code Reviewer",
  systemPrompt: "Review code from GitHub PRs...",
  model: { provider: "anthropic", name: "claude-sonnet-5" },
  tools: [{ type: "mcp", server: "github", tools: ["get_file_contents"] }],
}));

Expose your agents as an MCP server:

import { createMCPServer } from "@agntz/core";
const server = createMCPServer(runner);

Evals

Evals are first-class records outside AgentDefinition: datasets, eval definitions, async eval runs, latest scores, snapshots, and history. The embedded SDK and hosted clients expose those records through their client resources; the core runner stays focused on execution.

Storage

The default store is in-memory. For persistence, install a database adapter:

import { createRunner } from "@agntz/core";
import { SqliteStore } from "@agntz/stores/sqlite";

const runner = createRunner({
  store: new SqliteStore("./data.db"),
});

Database adapters:

| Package | Use Case | |---|---| | @agntz/stores | Persistent storage for embedded, single-server, and multi-server production |

You can also split stores by concern:

const runner = createRunner({
  agentStore: myPostgresStore,
  sessionStore: myRedisStore,
  logStore: myElasticsearchStore,
});

Custom Stores

Implement the store interfaces from @agntz/contracts:

interface AgentStore {
  getAgent(id: string): Promise<AgentDefinition | null>;
  listAgents(): Promise<AgentSummary[]>;
  putAgent(agent: AgentDefinition): Promise<void>;
  deleteAgent(id: string): Promise<void>;
}

interface SessionStore {
  getMessages(sessionId: string): Promise<Message[]>;
  append(sessionId: string, messages: Message[]): Promise<void>;
  deleteSession(sessionId: string): Promise<void>;
  listSessions(agentId?: string): Promise<SessionSummary[]>;
}

// Also: RunStore, TraceStore, EvalStore, SecretStore, ProviderStore,
// ConnectionStore, ContextStore, LogStore, and resource provider ports.
// Or implement UnifiedStore for all-in-one runtime persistence.

API Reference

createRunner(config?: RunnerConfig): Runner

Creates the central orchestrator. All options are optional:

const runner = createRunner({
  store: myStore,                       // Storage backend
  tools: [myTool1, myTool2],            // Inline tools
  mcp: { servers: { ... } },            // MCP server config
  session: {                              // Session trimming
    maxMessages: 50,
    strategy: "sliding",                  // "sliding" | "summary" | "none"
  },
  context: {                              // Context injection
    maxEntries: 20,
    maxTokens: 4000,
    strategy: "latest",                   // "latest" | "summary" | "all"
  },
  defaults: {                             // Default model config
    model: { provider: "openai", name: "gpt-5.6-terra" },
    maxTokens: 4096,
  },
  retry: {                                // Retry with backoff
    maxRetries: 3,
    initialDelayMs: 1000,
    backoffMultiplier: 2,
  },
  maxRecursionDepth: 3,                   // Agent-as-tool chain limit
  telemetry: { ... },                     // OpenTelemetry (opt-in)
});

defineAgent(config): AgentDefinition

Creates a validated agent definition:

const agent = defineAgent({
  id: "my-agent",
  name: "My Agent",
  systemPrompt: "...",
  model: { provider: "openai", name: "gpt-5.6-sol" },
  // ... all fields from AgentDefinition
});

defineTool(config): ToolDefinition

Creates a typed tool with Zod input validation:

const tool = defineTool({
  name: "my_tool",
  description: "What this tool does",
  input: z.object({ ... }),
  async execute(input, ctx) { ... },
});

Runner Methods

| Method | Description | |---|---| | runner.invoke(agentId, input, options?) | Invoke an agent and get the result | | runner.stream(agentId, input, options?) | Stream an agent invocation | | runner.registerAgent(agent) | Register an agent definition | | runner.shutdown() | Clean up MCP connections and flush stores |

Key Types

| Type | Description | |---|---| | AgentDefinition | Full agent configuration object | | ToolDefinition | Tool with name, description, schema, and execute function | | ToolReference | Reference to a tool: inline, mcp, or agent | | InvokeOptions | Options for invoke(): sessionId, context namespace grants, toolContext, etc. | | InvokeResult | Result: output, toolCalls, usage, duration, model | | InvokeStream | Async iterable of StreamEvent with .result promise | | RunnerConfig | Full configuration for createRunner() | | UnifiedStore | Combined runtime store contract re-exported from @agntz/contracts | | ModelProvider | Interface for custom model providers |

Error Types

Most runtime errors extend AgntzError with a stable code field:

| Error | Code | Description | |---|---|---| | AgentNotFoundError | AGENT_NOT_FOUND | Agent ID doesn't exist | | ToolNotFoundError | TOOL_NOT_FOUND | Tool name not registered | | ToolExecutionError | TOOL_EXECUTION_ERROR | Tool threw during execution | | ModelError | MODEL_ERROR | Model provider returned an error | | ProviderNotFoundError | PROVIDER_NOT_FOUND | No provider SDK installed | | InvocationCancelledError | INVOCATION_CANCELLED | AbortSignal triggered | | MaxStepsExceededError | MAX_STEPS_EXCEEDED | Tool loop hit step limit | | MaxRecursionDepthError | MAX_RECURSION_DEPTH | Agent chain too deep | | RetryExhaustedError | RETRY_EXHAUSTED | All retries failed | | ValidationError | VALIDATION_ERROR | Invalid input |

Templates

Starter agent configurations for common patterns:

import { templates } from "@agntz/core/templates";
import { defineAgent } from "@agntz/core";

runner.registerAgent(defineAgent({
  ...templates.chatbot,
  id: "my-bot",
}));

Available templates: chatbot, codeReviewer, summarizer, dataExtractor, creativeWriter, customerSupport, fitnessCoach, researcher

CLI

# Generate a YAML manifest
npx @agntz/sdk create "Answer support questions in a concise tone" -o ./agents/support.yaml

# Run it locally
npx @agntz/sdk run ./agents/support.yaml --input "Hello!"

# Validate a file or directory, including cross-file refs
npx @agntz/sdk validate ./agents

# Show all current commands
npx @agntz/sdk --help

The current CLI is distributed through @agntz/sdk; the executable name is agntz when installed globally. It supports create, edit, validate, run, publish, hosted auth, runs, traces, and eval commands. Use the SDK directly for local tools, resource providers, and app-specific runtime wiring.

Model Providers

agntz uses the Vercel AI SDK internally — calls go directly to providers with your API keys. No middleman.

defineAgent({
  model: { provider: "openai", name: "gpt-5.6-sol" },      // OPENAI_API_KEY
  model: { provider: "anthropic", name: "claude-sonnet-5" }, // ANTHROPIC_API_KEY
  model: { provider: "google", name: "gemini-3.6-flash" }, // GOOGLE_GENERATIVE_AI_API_KEY
  model: { provider: "openrouter", name: "anthropic/claude-sonnet-5" }, // OPENROUTER_API_KEY
});

Supported providers: openai, anthropic, google, openrouter, mistral, xai, groq, deepseek, perplexity, cohere, azure.

OpenRouter is a meta-provider that proxies to hundreds of models (Anthropic, Google, Meta, DeepSeek, open-source) with a single API key — use provider: "openrouter" and reference any model by its OpenRouter slug (e.g. anthropic/claude-sonnet-5, deepseek/deepseek-v4-pro). Per-request cost is reported by OpenRouter and surfaced on TokenUsage.cost.

Or bring your own model provider:

const runner = createRunner({
  modelProvider: myCustomProvider, // implements ModelProvider interface
});

OpenTelemetry

Opt-in observability:

import { trace } from "@opentelemetry/api";

const runner = createRunner({
  telemetry: {
    tracer: trace.getTracer("my-app"),
    recordIO: false,
    baseAttributes: { "service.name": "my-app" },
  },
});

Span hierarchy: agent.invokeagent.model.call / agent.tool.execute

Zero overhead when telemetry is not configured.

Related Packages

| Package | Description | |---|---| | @agntz/sdk | Embedded SDK, local client, and CLI | | @agntz/client | Hosted/self-hosted HTTP client | | @agntz/contracts | Shared types, store/resource ports, and leaf utilities | | @agntz/db | Shared SQLite/Postgres connection and migration plumbing | | @agntz/stores | Store contracts plus in-memory, SQLite, and Postgres adapters | | @agntz/worker | Hono HTTP worker for executing agents | | @agntz/app | Next.js web UI — multi-tenant, Clerk auth |

Contributing

See the main CONTRIBUTING.md for guidelines.

License

MIT © Aaron Bidworthy