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

weysabi

v0.15.1

Published

AI orchestration for fullstack devs — provider failover, structured output, RAG, and streaming. One library, zero markup.

Readme

weysabi

AI orchestration for fullstack devs. Provider failover, structured output, streaming, RAG, guardrails, and prompt management — one dependency, zero markup.

import { createWeysabi } from "weysabi";
import { z } from "zod";

const weysabi = createWeysabi({
  groq: { apiKey: process.env.GROQ_API_KEY },
  openai: { apiKey: process.env.OPENAI_API_KEY },
});

const res = await weysabi.complete({
  model: "groq/llama-4-scout",
  messages: [{ role: "user", content: "Extract the invoice total." }],
  fallbacks: ["openai/gpt-4o-mini"],
  response: { schema: z.object({ total: z.number() }) },
  rag: ["invoices/*.pdf"],
  guardrails: ["pii"],
});

console.log(res.parsed.total, res.latencyMs, res.requestId);

Why Weysabi?

  • Your keys, your providers. No gateway, no token markup, no middleman.
  • One dependency. Not LangChain + provider SDKs + vector DB. Just weysabi.
  • Built-in everything. Structured output, RAG, guardrails, prompts, streaming, caching — all ship in the box.
  • Works offline-first. SQLite for conversations and RAG. No cloud dependency.
  • No lock-in. Stop paying, the library still works. Your data stays with you.

Features

| Feature | Status | | --------------------------------------------------------------------------------------------------------------- | ------ | | Provider abstraction (OpenAI, Groq, Anthropic, Google, Mistral, DeepSeek, OpenRouter, Together, Nvidia, Ollama) | ✅ | | Custom / OpenAI-compatible endpoints | ✅ | | Custom provider handlers (register your own) | ✅ | | Provider failover (primary → fallbacks) | ✅ | | Circuit breaker + retry + backoff | ✅ | | Streaming (SSE, async iterable) | ✅ | | Structured output (Zod schemas with auto-retry) | ✅ | | Tool calling (auto-execute + chaining) | ✅ | | Prompt templates with {variable} substitution | ✅ | | Prompt registry (register, render, run) | ✅ | | RAG engine (ingest, embed, HNSW search, persist) | ✅ | | Multi-project RAG manager | ✅ | | Guardrails (PII redaction, injection detection, content safety, token limits) | ✅ | | Conversation memory (SQLite/Postgres, auto-truncation) | ✅ | | ChatSDK (prepare + call + record in one) | ✅ | | Framework adapters (Hono, Next.js, Express, Fastify, Elysia) | ✅ | | Caching (InMemory with LRU, Redis, BYO) | ✅ | | Plugin system (lifecycle hooks) | ✅ | | OpenTelemetry integration | ✅ | | Vercel AI SDK adapter | ✅ | | Cost estimation (per-response estimatedCostUsd) | ✅ | | requestId tracking (auto-generated, all logs) | ✅ | | Error status codes (programmatic retry vs. fatal) | ✅ | | WebSocket client (real-time streaming) | ✅ | | CLI (weysabi init, create, complete, stream, config, prompt) | ✅ | | Control plane — projects, conversations, runs, API keys | 🔜 | | Weysabi Cloud — hosted control plane, evals, monitoring | 🔜 |

Install

bun add weysabi

Requires Bun ≥ 1.3.

Providers

Configure any provider with an API key. All providers share the same interface.

const weysabi = createWeysabi({
  openai: { apiKey: process.env.OPENAI_API_KEY },
  anthropic: { apiKey: process.env.ANTHROPIC_API_KEY },
  google: { apiKey: process.env.GOOGLE_API_KEY },
  groq: { apiKey: process.env.GROQ_API_KEY },
  deepseek: { apiKey: process.env.DEEPSEEK_API_KEY },
  mistral: { apiKey: process.env.MISTRAL_API_KEY },
  nvidia: { apiKey: process.env.NVIDIA_API_KEY },
  openrouter: { apiKey: process.env.OPENROUTER_API_KEY },
  together: { apiKey: process.env.TOGETHER_API_KEY },
  ollama: { baseUrl: "http://localhost:11434" },
  // Custom OpenAI-compatible endpoint
  myproxy: { apiKey: "sk-...", baseUrl: "https://my-proxy.com/v1" },
});

Reference models with provider/model-id notation:

weysabi.complete({ model: "groq/llama-4-scout", ... });
weysabi.complete({ model: "openai/gpt-4o", ... });
weysabi.complete({ model: "anthropic/claude-3-5-sonnet-20241022", ... });

Custom Provider Handlers

For providers with non-OpenAI-compatible APIs, register a custom handler:

import { registerProvider } from "weysabi";
import type { ProviderHandler } from "weysabi";

const myHandler: ProviderHandler = {
  buildUrl(baseUrl, modelId, stream) {
    /* ... */
  },
  buildHeaders(apiKey) {
    /* ... */
  },
  buildBody(modelId, messages, opts) {
    /* ... */
  },
  parseResponse(data) {
    /* ... */
  },
  parseStreamChunk(data) {
    /* ... */
  },
};

registerProvider("my-custom-provider", myHandler);

const weysabi = createWeysabi({
  "my-custom-provider": { apiKey: process.env.MY_KEY },
});

Provider Failover

Automatic fallback when a provider fails. Circuit breaker prevents hammering a failing endpoint.

const res = await weysabi.complete({
  model: "groq/llama-4-scout",
  fallbacks: ["openai/gpt-4o-mini", "anthropic/claude-3-5-haiku-20241022"],
  messages: [{ role: "user", content: "Hello" }],
});
// Groq fails → OpenAI fallback → response delivered

Structured Output

Pass a Zod schema. Weysabi validates the response and retries on parse failure.

import { z } from "zod";

const CalendarSchema = z.object({
  events: z.array(
    z.object({
      title: z.string(),
      date: z.string(),
      attendees: z.array(z.string()),
    })
  ),
});

const res = await weysabi.complete({
  model: "groq/llama-4-scout",
  messages: [{ role: "user", content: "Schedule a meeting for next Tuesday." }],
  schema: CalendarSchema,
});

console.log(res.parsed.events);
// Typed as { title: string; date: string; attendees: string[] }[]

On parse failure, throws SchemaValidationError with .raw (raw response) and .issues (Zod errors). Each error carries a statusCode property for programmatic handling.

Streaming

Works with all providers and includes failover — if the primary provider fails mid-stream, the library transparently retries the full request against fallbacks.

const stream = weysabi.stream({
  model: "groq/llama-4-scout",
  messages: [{ role: "user", content: "Write a poem." }],
});

for await (const chunk of stream) {
  if (chunk.content) process.stdout.write(chunk.content);
  if (chunk.usage) console.log("\nTokens:", chunk.usage.totalTokens);
}

Framework Adapters

// Hono, Next.js, Elysia — any Web Fetch framework
import { toResponse } from "weysabi/hono";
// import { toResponse } from "weysabi/next";
// import { toResponse } from "weysabi/elysia";

app.post("/chat", async (c) => {
  const stream = weysabi.stream({ ... });
  return toResponse(stream); // SSE response
});

// Express
import { pipe } from "weysabi/express";
app.post("/chat", async (req, res) => {
  const stream = weysabi.stream({ ... });
  await pipe(stream, res);
});

// Fastify
import { pipe } from "weysabi/fastify";
app.post("/chat", async (req, reply) => {
  const stream = weysabi.stream({ ... });
  await pipe(stream, reply);
});

Batch Requests

Send multiple completions concurrently with a configurable concurrency limit.

const results = await weysabi.batch(
  [
    { model: "groq/llama-4-scout", messages: [{ role: "user", content: "Q1" }] },
    { model: "groq/llama-4-scout", messages: [{ role: "user", content: "Q2" }] },
    { model: "groq/llama-4-scout", messages: [{ role: "user", content: "Q3" }] },
  ],
  { concurrency: 5 }
);

for (const result of results) {
  if (result.ok) {
    console.log(result.data.content);
  } else {
    console.error("Failed:", result.error);
  }
}

Results are returned in request order. Errors are isolated per request.

Prompt Templates

Define, register, and run templates with {variable} substitution.

weysabi.prompts.register({
  id: "classify",
  model: "groq/llama-4-scout",
  messages: [
    {
      role: "system",
      content: "You are a support ticket classifier.",
    },
    {
      role: "user",
      content: `Classify this ticket: {ticket_text}

Categories: billing, technical, account, feature_request

Respond with just the category.`,
    },
  ],
});

// Render + complete in one call
const result = await weysabi.prompts.run("classify", {
  ticket_text: "I was overcharged for my subscription",
});

// Or render separately for inspection
const messages = weysabi.prompts.render("classify", {
  ticket_text: "Login is broken",
});

RAG (Retrieval-Augmented Generation)

Built-in vector search without an external vector database. Ingest documents, auto-chunk, embed, and search.

import { RagEngine } from "weysabi/rag";

const rag = new RagEngine({
  dbPath: ".weysabi/knowledge.db",
  embeddingModel: "openai/text-embedding-3-small",
});

rag.setProviders(
  { provider: "openai", apiKey: process.env.OPENAI_API_KEY },
  { openai: { apiKey: process.env.OPENAI_API_KEY } }
);

// Ingest files
await rag.load("docs/manual.pdf", "docs/faq.md");

// Query
const results = await rag.query("How do I reset my password?");
console.log(results[0].content);

Multi-project management:

import { RagManager } from "weysabi/rag";

const manager = new RagManager({
  basePath: ".weysabi/rag",
  providers: { embeddingProvider: { provider: "openai", apiKey: "..." } },
});

const docs = manager.project("docs-v2");
await docs.load("guides/");

const hits = await docs.query("pricing");

Guardrails

PII redaction, prompt injection detection, content moderation, and output token limits.

const res = await weysabi.complete({
  model: "groq/llama-4-scout",
  messages: [{ role: "user", content: "My email is [email protected]" }],
  guardrails: ["pii"], // Redact emails, phones, SSNs
  // guardrails: ["injection"],            // Detect prompt injection
  // guardrails: ["content"],             // Moderate toxic content
  // guardrails: [{ type: "limits", maxOutputTokens: 100 }],
});

Guardrails can also be used standalone:

import { guardrail } from "weysabi/guardrails";

const result = await guardrail("pii", "My SSN is 123-45-6789");
console.log(result.redacted); // "My SSN is [REDACTED]"

Custom Guardrails

weysabi.guardrail("my-check", {
  scope: "output",
  validate: (text) => text.length < 1000,
  onViolation: (match) => console.log("Blocked:", match),
});

Conversation Memory

Persistent chat history with automatic context management. SQLite by default, Postgres for production.

import { ConversationMemory } from "weysabi/chat";

const memory = new ConversationMemory({
  dbPath: ".weysabi/chat.db",
  maxHistoryTokens: 16384,
});

// Prepare context — no API call
const ctx = memory.prepare("user-abc", {
  message: "Hi, my name is Bob",
  system: "You are a helpful assistant",
});

// Call your provider SDK natively
const response = await anthropic.messages.create({
  model: "claude-3-5-sonnet-20241022",
  system: ctx.system,
  messages: ctx.messages,
});

// Record the turn
memory.record("user-abc", {
  userMessage: { content: "Hi, my name is Bob" },
  assistantMessage: { content: response.content[0].text },
});

// Next turn — history is loaded automatically
const ctx2 = memory.prepare("user-abc", {
  message: "What's my name?",
});
// ctx2.messages includes full history

Postgres for production:

import postgres from "postgres";
import { ConversationMemory, PgSessionStore } from "weysabi/chat";

const sql = postgres("postgres://user:pass@host:5432/db");
const memory = new ConversationMemory({
  store: new PgSessionStore(sql),
});

Tool Calling

Define tools with Zod schemas. The library handles execution and chaining.

const res = await weysabi.complete({
  model: "groq/llama-4-scout",
  messages: [{ role: "user", content: "What's the weather in London?" }],
  tools: [
    {
      name: "get_weather",
      description: "Get current weather",
      schema: z.object({ city: z.string() }),
      execute: async ({ city }) => fetchWeather(city),
    },
  ],
});

Caching

import { InMemoryCache } from "weysabi/cache";

const weysabi = createWeysabi(providers, {
  cache: new InMemoryCache(60_000), // 60s TTL
});

InMemoryCache supports max-size LRU eviction — pass a second argument to prevent unbounded growth:

const cache = new InMemoryCache(60_000, 1000); // 1000 entries max

requestId Tracking

Every request gets a unique requestId, auto-generated via crypto.getRandomValues(). Pass your own for correlation:

const res = await weysabi.complete({
  model: "groq/llama-4-scout",
  messages: [{ role: "user", content: "Hello" }],
  requestId: "my-correlation-id",
});

console.log(res.requestId); // "my-correlation-id"

The requestId flows through all structured log entries, making debugging across services straightforward.

Error Handling

Every error class carries a statusCode for programmatic retry vs. fatal distinction:

| Error | statusCode | Meaning | | ---------------------------- | ---------- | ---------------------- | | SchemaValidationError | 422 | Invalid user input | | ProviderNotConfiguredError | 400 | Provider not in config | | PromptNotFoundError | 404 | Template missing | | MissingPromptInputError | 400 | Missing variable | | MaxToolCallsExceededError | 400 | Tool loop limit | | CircuitBreakerOpenError | 503 | Provider recovering | | AllModelsFailedError | 502 | All providers failed | | ProviderRequestError | varies | Upstream HTTP code | | WeysabiError (base) | 500 | Unknown error |

try {
  const res = await weysabi.complete({ ... });
} catch (err) {
  if (err instanceof WeysabiError) {
    if (err.statusCode < 500) {
      console.log("Client error, fix the request:", err.message);
    } else {
      console.log("Server error, can retry:", err.statusCode);
    }
  }
}

Plugins

Lifecycle hooks for telemetry, logging, or custom behavior.

weysabi.use({
  name: "logger",
  onCompleteRequest(req) {
    console.log("Request:", req.model);
    return req;
  },
  onCompleteResponse(res, req) {
    console.log("Response:", res.latencyMs, "ms");
    return res;
  },
  onError(err, { request }) {
    console.error("Failed:", err.message);
  },
});

OpenTelemetry

import { createOtelPlugin } from "weysabi/otel";

weysabi.use(createOtelPlugin({ tracer: trace.getTracer("my-app") }));

Vercel AI SDK

import { createWeysabiProvider } from "weysabi/ai-sdk";

const provider = createWeysabiProvider(weysabi);
const result = await generateText({
  model: provider.languageModel("groq/llama-4-scout"),
  prompt: "Hello",
});

Control Plane Client

Built-in HTTP + WebSocket client for the Weysabi server control plane — projects, conversations, runs, prompts, documents, and API keys.

import { createWeysabiClient, createWebSocketClient } from "weysabi";

// HTTP client
const client = createWeysabiClient({
  baseUrl: "http://localhost:3000",
  apiKey: "sk-admin",
});

const project = client.project("project-1");
const runs = await project.runs.list({ status: "success" });

// WebSocket streaming
const ws = createWebSocketClient({
  baseUrl: "http://localhost:3000",
  apiKey: "sk-admin",
});

const events = ws.stream("POST", "/v1/projects/p/conversations/c/messages/stream", {
  content: "Hello",
  model: "groq/llama-4-scout",
});

CLI

# Scaffold a new project
bunx create-weysabi-app my-app

# Interactive project setup
bun weysabi init

# Test provider connectivity
bun weysabi config validate

# Quick completions
bun weysabi complete "Hello" -m groq/llama-4-scout
bun weysabi stream "Tell me a story" -m openai/gpt-4o-mini

# Manage prompts
bun weysabi prompt list
bun weysabi prompt add classify -f prompts/classify.txt

HTTP Server

Deploy as an OpenAI-compatible API with auth, rate limits, quotas, usage tracking, and admin monitoring.

bun weysabi server --port 3000

Or embed in your app:

import { createServer } from "weysabi-server";

const server = await createServer(weysabi, {
  apiKey: "sk-my-key",
  adminApiKey: "sk-admin-secret",
});

See weysabi-server for full documentation.

Sub-path Exports

import { createWeysabi } from "weysabi";
import { WeysabiError } from "weysabi/errors";
import { toResponse } from "weysabi/sse";
import { pipe } from "weysabi/express";
import { InMemoryCache } from "weysabi/cache";
import { createOtelPlugin } from "weysabi/otel";
import { createWeysabiProvider } from "weysabi/ai-sdk";
import { RagEngine, RagManager } from "weysabi/rag";
import { ConversationMemory } from "weysabi/chat";
import { PromptRegistry } from "weysabi/prompts";
import { registerProvider } from "weysabi";
import type { ProviderHandler } from "weysabi";
import { WebSocketClient, createWebSocketClient } from "weysabi/client";

License

MIT