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

koatty_llm

v1.0.0

Published

LLM calling abstraction for Koatty: provider adapters, model routing, reliability, budgets, structured output and tool-call loops.

Readme

koatty_llm

LLM calling abstraction for Koatty: one interface for every vendor, plus the reliability, budget and safety plumbing that production calls need.

Roadmap: docs/koatty-hardening-and-ai-evolution-plan.md → Phase F, item F-2. Deliberately NOT included: agent orchestration DSLs and multi-agent frameworks.

Install

pnpm add koatty_llm

koatty_validation is required; koatty_store (distributed token counting) and koatty_cacheable (response cache) are optional peers — any object with the two documented methods works, so a custom Redis/DB client is fine too.

Use

import { Service } from 'koatty_core';
import { Autowired } from 'koatty_container';
import { createOpenAiCompatibleProvider, createLlmClient } from 'koatty_llm';

const llm = createLlmClient({
  providers: [
    createOpenAiCompatibleProvider({ name: 'openai', baseUrl: 'https://api.openai.com/v1', apiKey: process.env.OPENAI_API_KEY }),
    createOpenAiCompatibleProvider({ name: 'local', baseUrl: 'http://127.0.0.1:11434/v1' }),
  ],
  routes: {
    // logical name -> provider + provider-side model, with ordered failover
    default: { model: 'default', provider: 'openai', providerModel: 'gpt-4o-mini', fallbacks: ['local'] },
    local: { model: 'local', provider: 'local', providerModel: 'llama3.1' },
  },
  reliability: { attempts: 2, backoffMs: 200, timeoutMs: 60_000, breakerThreshold: 5 },
  budget: { maxTokens: 200_000, scope: 'tenant', store: redisStore },
  cache: cacheableService,
});

@Service()
export class SupportAgent {
  async answer(question: string, signal: AbortSignal) {
    // returns an AsyncIterable — pipe it through the existing streamSSE helper
    return llm.stream({
      model: 'default',
      messages: [{ role: 'user', content: question }],
      signal,                      // ctx.signal: aborting cancels the provider call
      budgetScope: 'tenant-42',
    });
  }
}

Capabilities

| Capability | Notes | |---|---| | Provider abstraction | createOpenAiCompatibleProvider (OpenAI, Azure-compatible gateways, most vendors, vLLM/Ollama) and createAnthropicProvider. Both are fetch + SSE, so a proxy/instrumented fetchImpl can be injected. | | Model routing | Logical model name → provider + provider-side model id; fallbacks are tried in order, and only for retryable failures. | | Reliability | Per-attempt timeout, exponential backoff with jitter for 429/5xx only, circuit breaker per provider+model (resetBreakers() for admin use). | | Budget | Pre-flight check plus post-call accounting through BudgetStore (get/set/required atomic incrBy), so several instances share one counter. Exceeding the budget aborts the call — it never silently truncates. | | Cancellation | options.signal is propagated to the provider and re-checked between chunks, so an aborted call (ctx.signal) stops within the provider round-trip. | | Structured output | Pass schema (provider-side JSON schema) and dto (class-validator DTO); the parsed JSON is validated with koatty_validation, and validationRetries re-asks once with a correction message. | | Tool calling | withTools({ tools, registry, invoke }) runs the tool-call loop in-process: the model asks for a tool → it is invoked through your invoker (a koatty_mcp host satisfies it) → the result is fed back, with a hard maxRounds cap. | | Caching | Exact-match cache for non-streaming complete() calls (cache: false to bypass, cacheKey as an additional discriminator; each client and DTO has its own namespace). Semantic caching is intentionally not in v1. | | Cost | estimateCost() from pricePer1kPrompt / pricePer1kCompletion on the route. |

Every result carries model, provider, usage, finishReason, cached and (optionally) cost — feed those into your trace/metrics layer.

Errors

LlmError subclasses tell the caller what to do:

| Error | When | Retryable | |---|---|---| | LlmAbortError | caller aborted (ctx.signal) | no | | LlmTimeoutError | per-attempt timeout | yes | | LlmBudgetError | scope budget exhausted (scope, used, max) | no | | LlmValidationError | structured output is not JSON or fails the DTO (issues, raw) | no | | LlmUnavailableError | every route/attempt failed (attempts, plus the last error code) | per last error | | LlmError | provider 4xx/5xx first failure | 429/5xx only |

Verify

npx jest test/regression/F-02 --coverage=false   # 19 cases: cancellation ≤1s,
                                                 # failover/retry/breaker, budget,
                                                 # structured output, tool loop,
                                                 # cache, both adapters
npx tsc -p tsconfig.json --noEmit

License

BSD-3-Clause

Review migration (2026-09-30)

When budget is configured, store and atomic incrBy are required. The default per-attempt completion reservation is 1024 tokens (budget.defaultMaxTokens), capped by the remaining scope allowance. An immediate failure before any chunk releases its reservation. Interrupted output without usage retains the bounded reservation. Estimates do not truncate a stream; authoritative usage and provider maxTokens enforce accounting. Settlement failures are logged as budget_settlement_failed and do not replace completed results; reconcile the counter before reusing an affected scope.

streamWithTools(options) is the streaming counterpart of withTools; both support detached invocation, validate every tool name before exposing/executing it, pass cancellation, and report invocation failures as tool results. Cache entries include the effective schema and DTO identity, invalid entries refresh, and same-named providers in different clients do not share entries.