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

@textopt/langsmith

v0.1.2

Published

LangSmith experiment reporting for textopt

Readme

@textopt/langsmith

LangSmith experiment reporting for textopt.

createLangSmithReporter writes a run to LangSmith as one experiment per accepted candidate over one fixed dataset. Selecting several of those experiments in LangSmith's comparison view renders the candidate x instance score matrix selection reads: which instances a candidate won, and which it paid for.

It works with any optimizer. The reporter reads the acceptance payload every search emits — the candidate text and its per-instance row over the validation set — rather than one search's event union, and folds whatever else the optimizer put on the event (GEPA's lineage, MIPRO's menu choices, SIMBA's step) into the experiment's metadata.

Install langsmith separately. This package matches its Client structurally and declares no runtime dependency on it.

Usage

import { GepaOptimizer } from "textopt/gepa";
import { createLangSmithReporter } from "@textopt/langsmith";
import { Client } from "langsmith";

const instanceId = ({ datum }: { datum: Ticket }) => datum.id;

const result = await new GepaOptimizer({ trackBestOutputs: true }).optimize({
  seedCandidate,
  trainingSet,
  validationSet,
  testSet,
  adapter,
  reflect,
  maxMetricCalls: 300,
  instanceId,
  reporters: [
    createLangSmithReporter({
      client: new Client(),
      dataset: "ticket-triage",
      experimentPrefix: "gepa-2026-08-19",
      validationSet,
      testSet,
      instanceId,
      toInput: (datum) => ({ ticket: datum.text }),
      toExpected: (datum) => ({ label: datum.label }),
    }),
  ],
});

Experiments are named <experimentPrefix>/cand-<candidateId>, starting with cand-0 for the seed — the baseline every later candidate is read against. Each carries the candidate's text, iteration, parents, source and aggregate score as metadata, so a score that moved sits next to the edit that moved it.

| Option | Default | Effect | | ------------------ | -------------------- | ------------------------------------------------------------------- | | client | required | A LangSmith Client, or anything with the same shape. | | dataset | required | Dataset holding the validation split. Created once, then reused. | | experimentPrefix | required | Names the experiments. Use a value unique to the run. | | validationSet | required | The validation set the run was given, in the same order. | | testSet | none | Uploaded as its own dataset, swept once, for the winner only. | | testDataset | <dataset>-held-out | Names that second dataset. | | instanceId | the row's position | Keys a dataset row across runs. | | toInput | the datum itself | The example's inputs. | | toExpected | none | The example's outputs, when the dataset should carry a reference. | | concurrency | 8 | Rows uploaded at once within one experiment. |

What is deliberately not logged

Minibatch rollouts. They are small random subsets of the training set that differ every iteration, so they cannot be compared across candidates and would bury the experiments that can. They are still traceable: with LANGSMITH_TRACING=1, @textopt/langsmith's sibling @textopt/langchain tags every rollout with its iteration, phase, split and candidate id.

A held-out experiment per candidate. GEPA scores the held-out set only once selection is over, precisely so that nothing can be chosen against it. There is one held-out experiment, for the winner, on its own dataset — and no option to change that, because the first time a candidate is picked because it looked better there, the number stops meaning anything.

Zeros for unmeasured instances. An instance the evaluation policy skipped, or one an infrastructure failure lost, has no row. Written as a zero it reads as a regression that never happened.

Notes

Uploads are queued, not awaited: onEvent runs on the search's hot path, and the reporter's flush is awaited once as the run ends, including when it ends by throwing. A LangSmith that is unreachable degrades to a warning — the run that bought the rollouts finishes either way.

Dataset row ids are derived from the dataset name and instanceId, not assigned by the server, so a repeated or resumed run writes to the rows it already has. If the dataset already exists, its examples are left alone; a validation set that changed shape wants a new dataset name.

Uploading is chatty: one run plus one feedback per measured instance per accepted candidate. Ten candidates over a hundred validation instances is a few thousand calls.