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

keelwave

v0.1.1

Published

JavaScript and TypeScript SDK for keelwave — observability and alerting for AI agents.

Readme

keelwave — JavaScript / TypeScript SDK

Zero-friction tracing for AI agents on Node.

The keelwave SDK instruments your agent code and streams agent runs, decision steps, tool calls, loop-detection fingerprints, token/cost data, and model traces to a keelwave server. An API key is the only required configuration — point it at your server and wrap your agent.

Status: early / pre-1.0 (MVP). The client, run tracing, decorators, loop detection, and a Vercel AI SDK adapter all work and are covered by integration tests, but the API surface is small and may change before a stable release. Node only (uses node:crypto and AsyncLocalStorage); not built for the browser.


Install

The SDK targets Node 22+ and ships as ESM with bundled type declarations, so it works from plain JavaScript or TypeScript with no extra @types package.

npm install keelwave
# or
pnpm add keelwave
# or
yarn add keelwave

The ai package (Vercel AI SDK) is an optional peer dependency, needed only for the keelwave/vercel-ai model adapter. Core tracing never imports it. Both ai v4 and v5 are supported.

You also need a running keelwave server to receive the data — see github.com/keelwave/keelwave. The SDK defaults to http://localhost:8080.


Quickstart

Construct a client with your API key, then trace an agent run. Inside a run, tool calls are fingerprinted automatically so repeated identical calls are flagged as a loop.

import { Keelwave } from 'keelwave'

const client = new Keelwave({
  apiKey: process.env.KEELWAVE_API_KEY ?? 'kw_...',
  endpoint: 'http://localhost:8080', // defaults to this if omitted
})

// A traced tool. Calls inside an active run are recorded and fingerprinted.
const webSearch = client.observe({ name: 'web_search', stepType: 'tool_call' })(
  async (q: string): Promise<{ results: Array<string> }> => {
    return { results: [`result for: ${q}`] }
  },
)

// Wrap an agent function. Opens a run, records the return value as output,
// and closes the run when the function settles.
const runAgent = client.agent({ name: 'demo-agent' })(async (
  task: string,
): Promise<string> => {
  const { results } = await webSearch(task)
  return `Found: ${results[0]}`
})

const answer = await runAgent('TypeScript observability')
console.log(answer)

Manual runs

If you'd rather not use decorators, open a run directly:

await client.run(
  'demo-agent',
  async (run) => {
    await run.step('plan', 'break the task into steps')
    await run.toolCall('web_search', { q: 'keelwave' }, { results: ['...'] })
    run.setOutput('done')
  },
  { input: 'TypeScript observability' },
)

getCurrentRun() returns the active Run anywhere inside a run (it's tracked via AsyncLocalStorage), so nested helpers can add steps without threading the run through your call stack.


What's captured

Per agent run and its steps, the SDK sends:

  • Agent runs — agent name, input, metadata, start/finish, status (completed / failed), termination reason, duration, and output.
  • Decision steps — an ordered step index, step type, content, and per-step token / cost / metadata.
  • Tool calls — tool name, input, output, success flag, and latency.
  • Loop detection — each tool call is hashed (tool name + sorted input) into a SHA-256 fingerprint; a repeated fingerprint marks the run as looping and records where the loop began.
  • Token & cost — per-step tokens/cost accumulate into run totals.
  • Model traces (ingestAi) — model, provider, input/output/total tokens, cost, latency, status, error message, and an optional agentRunId linking the trace to a run.

Provider adapters

Vercel AI SDK

wrapModel wraps any Vercel AI SDK LanguageModelV1 so every generateText / streamText call emits a model trace (tokens + latency), linked to the active run when there is one. It lives at the keelwave/vercel-ai subpath, so ai stays an optional peer dependency — only install it if you use this adapter (you already have it if you use the Vercel AI SDK).

import { openai } from '@ai-sdk/openai'
import { generateText } from 'ai'
import { Keelwave } from 'keelwave'
import { wrapModel } from 'keelwave/vercel-ai'

const client = new Keelwave({
  apiKey: process.env.KEELWAVE_API_KEY ?? 'kw_...',
})

const model = wrapModel(client, openai('gpt-4o'))

const { text } = await generateText({ model, prompt: 'hello' })
// → keelwave receives a model trace with tokens + latency

Both non-streaming (wrapGenerate) and streaming (wrapStream) calls are instrumented; usage is read from the model's finish data.


Configuration

new Keelwave({ ... }) options:

| Option | Type | Default | Notes | | -------------- | --------- | ----------------------- | ------------------------------------------------ | | apiKey | string | — (required) | keelwave API key (kw_...). | | endpoint | string | http://localhost:8080 | keelwave server base URL. Trailing / trimmed. | | raiseOnError | boolean | false | If false, emit failures warn instead of throw. |

Transport failures surface as typed errors: KeelwaveError, KeelwaveAuthError, KeelwaveValidationError, KeelwaveRateLimited, KeelwaveBufferFull, KeelwaveServerError, KeelwaveTransportError.


Related

  • keelwave server (core): github.com/keelwave/keelwave — the Go API + dashboard that ingests and displays this data. SDK features depend on the server supporting the wire protocol first.

License

MIT. See LICENSE.