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

ashr-labs

v0.6.0

Published

TypeScript SDK for the Ashr Labs API — agent testing & evaluation

Readme

Ashr Labs TypeScript SDK

A TypeScript client library for evaluating AI agents against Ashr Labs test datasets.

Documentation

Installation

npm install ashr-labs

Quick Start

import { AshrLabsClient, EvalRunner } from "ashr-labs";

// Only need your API key — baseUrl and tenantId are automatic
const client = new AshrLabsClient("tp_your_api_key_here");

// Fetch a dataset and run your agent against it
const runner = await EvalRunner.fromDataset(client, 42);
const run = await runner.run(myAgent);

// Inspect results
const metrics = run.build().aggregate_metrics as Record<string, unknown>;
console.log(`Passed: ${metrics.tests_passed}/${metrics.total_tests}`);
console.log(`Avg similarity: ${metrics.average_similarity_score}`);

// Submit results
await run.deploy(client, 42);

Your agent just needs two methods:

import type { Agent } from "ashr-labs";

const myAgent: Agent = {
  async respond(message: string) {
    // Call your LLM, return { text: "...", tool_calls: [...] }
    return { text: "response", tool_calls: [] };
  },

  async reset() {
    // Clear conversation history between scenarios
  },
};

See Testing Your Agent for a full end-to-end guide.

Observability — Production Tracing

Trace your agent in production. Captures LLM calls, tool invocations, and events. Never rejects — if the backend is unreachable, errors are logged silently.

// wrap() pattern — auto-end on completion, auto-capture errors
await client.trace("handle-ticket", { userId: "user_42" }).wrap(async (trace) => {
  const gen = trace.generation("classify", { model: "claude-sonnet-4-6",
    input: [{ role: "user", content: "help" }] });
  const result = await callLlm(...);
  gen.end({ output: result, usage: { input_tokens: 50, output_tokens: 12 } });

  await trace.span("tool:search", { input: { q: "..." } }).wrap(async (s) => {
    const data = await search(...);
    s.end({ output: data });
  });
});

// Analytics
const analytics = await client.getObservabilityAnalytics(7);
console.log(`Traces: ${analytics.overview.total_traces}`);
console.log(`Tool calls: ${analytics.overview.total_tool_calls}`);

See API Reference for full Trace/Span/Generation docs.

VM Stream Logs

Attach virtual machine session logs to test results for browser-based or desktop-based agents:

test = run.addTest("checkout_flow");
test.start();
// ... run agent, add tool calls and responses ...

// Kernel browser session (first-class support)
test.setKernelVm("kern_sess_abc123", {
  durationMs: 15000,
  logs: [
    { ts: 0, type: "navigation", data: { url: "https://app.example.com" } },
    { ts: 1200, type: "action", data: { action: "click", selector: "#login" } },
  ],
  replayId: "replay_abc123",
  replayViewUrl: "https://www.kernel.sh/replays/replay_abc123",
  stealth: true,
  viewport: { width: 1920, height: 1080 },
});

// Or use the generic setVmStream() for any provider
test.setVmStream("browserbase", {
  sessionId: "sess_abc123",
  durationMs: 45000,
  logs: [
    { ts: 0, type: "navigation", data: { url: "https://app.example.com" } },
    { ts: 1200, type: "action", data: { action: "click", selector: "#login" } },
  ],
});
test.complete();

Available Methods

All methods that accept tenantId auto-resolve it from your API key if omitted.

Datasets

| Method | Description | |--------|-------------| | getDataset(datasetId, ...) | Get a dataset by ID | | listDatasets(tenantId, limit, offset, ...) | List datasets |

Runs

| Method | Description | |--------|-------------| | createRun(datasetId, result, ...) | Create a new test run | | getRun(runId) | Get a run by ID | | listRuns(datasetId, tenantId, limit, offset) | List runs | | deleteRun(runId) | Delete a run |

EvalRunner

| Method | Description | |--------|-------------| | EvalRunner.fromDataset(client, datasetId) | Create a runner from a dataset | | runner.run(agent, { maxWorkers }) | Run agent against all scenarios, return RunBuilder | | runner.runAndDeploy(agent, client, datasetId, { maxWorkers }) | Run and submit in one call |

RunBuilder

| Method | Description | |--------|-------------| | new RunBuilder() | Create a new run builder | | run.start() | Mark the run as started | | run.addTest(testId) | Add a test and get a TestBuilder | | run.complete(status) | Mark the run as completed | | run.build() | Serialize to a result object | | run.deploy(client, datasetId) | Build and submit via the API |

TestBuilder

| Method | Description | |--------|-------------| | test.start() | Mark the test as started | | test.addUserFile(filePath, description) | Record a user file upload | | test.addUserText(text, description) | Record a user text input | | test.addToolCall(expected, actual, matchStatus) | Record an agent tool call | | test.addAgentResponse(expectedResponse, actualResponse, matchStatus) | Record an agent response | | test.setVmStream(provider, opts) | Attach VM session logs | | test.setKernelVm(sessionId, opts) | Attach Kernel VM session (convenience) | | test.complete(status) | Mark the test as completed |

Requests

| Method | Description | |--------|-------------| | createRequest(requestName, request, ...) | Create a new request | | getRequest(requestId) | Get a request by ID | | listRequests(tenantId, status, limit, offset) | List requests |

Observability

| Method | Description | |--------|-------------| | client.trace(name, opts?) | Start a production trace (returns Trace) | | trace.span(name, opts?) / trace.generation(name, opts?) | Add spans or LLM calls | | trace.wrap(fn) / span.wrap(fn) | Auto-end on completion, auto-capture errors | | await trace.end(opts?) | Flush trace to backend (never rejects) | | listObservabilityTraces(opts?) | List traces | | getObservabilityTrace(traceId) | Get trace with full observation tree | | getObservabilityAnalytics(days?) | Analytics: tokens, latency, errors, tool perf | | getObservabilityErrors(opts?) | Traces with errors | | getObservabilityToolErrors(opts?) | Traces with tool failures |

API Keys & Session

| Method | Description | |--------|-------------| | init() | Validate credentials and get user/tenant info | | listApiKeys(includeInactive) | List API keys for your tenant | | revokeApiKey(apiKeyId) | Revoke an API key | | healthCheck() | Check if the API is reachable |

Error Handling

import { AshrLabsClient, NotFoundError, AuthenticationError } from "ashr-labs";

const client = new AshrLabsClient("tp_...");

try {
  const dataset = await client.getDataset(999);
} catch (e) {
  if (e instanceof AuthenticationError) {
    console.log("Invalid API key");
  } else if (e instanceof NotFoundError) {
    console.log("Dataset not found");
  }
}

Configuration

// All defaults — just pass API key
const client = new AshrLabsClient("tp_...");

// From environment (reads ASHR_LABS_API_KEY)
const client = AshrLabsClient.fromEnv();

// Custom timeout
const client = new AshrLabsClient("tp_...", undefined, 60);

// Custom base URL (for self-hosted)
const client = new AshrLabsClient("tp_...", "https://your-api.example.com");

Requirements

  • Node.js 18+
  • TypeScript 5.4+ (recommended)

License

MIT