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

@currentai/dsts

v1.0.1

Published

GEPA (Genetic-Pareto) optimizer for TypeScript - Multi-objective optimization through reflective evolution, with first-class support for AI SDK's generateObject

Readme

DSTS — Dynamic Self‑improving TypeScript

DSTS is a minimal, AI SDK–aligned prompt optimizer for TypeScript. It optimizes prompts for both generateObject (with Zod schemas) and generateText with the latest GEPA optimizer (soft G like “giraffe”). GEPA evolves a prompt along a Pareto frontier across multiple objectives that matter in practice: task performance, latency, and cost.

  • AI Gateway–aligned: pass model ids as strings; generateObject with a Zod schema for a structured object or generateText with a string.
  • Minimal abstractions: one default adapter to call generateObject/generateText and one optimizer.
  • Multi‑objective first: correctness + latency (and cost) tracked per iteration; Pareto front and hyper‑volume (2D) reported.
  • Persistence & budgets: checkpoint/resume, per‑call cost estimation (via tokenlens) and budget caps, seeded minibatching.

Install

npm i @currentai/dsts zod

Quick start

import { z } from "zod";
import { optimize, DefaultAdapterTask } from "@currentai/dsts";

// Define schema (generateObject)
const Item = z.object({ title: z.string(), url: z.string().url() });

// Training data: use schema ⇒ generateObject; provide expectedOutput and/or a scorer
const trainset: DefaultAdapterTask<z.infer<typeof Item>>[] = [
  {
    input: "link to TS docs",
    expectedOutput: {
      title: "TypeScript",
      url: "https://www.typescriptlang.org",
    },
    schema: Item,
  },
];
const valset = trainset;

const result = await optimize({
  seedCandidate: { system: "Extract a title and a valid URL from the text." },
  trainset,
  // Explicit held-out set used for Pareto selection
  valset,
  taskLM: {
    model: "openai/gpt-5-nano",
    // Any extra fields are passed through to AI SDK calls
    temperature: 0.2,
    providerOptions: { openai: { service_tier: "default" } },
  },
  reflectionLM: {
    model: "openai/gpt-5.2",
    providerOptions: { openai: { reasoningEffort: "high" } },
  },
  // Simple way to steer reflection without templates
  reflectionHint: "Prioritize exact field correctness; avoid hallucinating properties.",
  maxIterations: 5,
  maxMetricCalls: 200,
  maxBudgetUSD: 50,
  reflectionMinibatchSize: 3,
  candidateSelectionStrategy: "pareto",
  componentSelector: "round_robin",
  logger: {
    log: (lvl, msg, data) => {
      if (lvl === "info") console.log(`[${lvl}] ${msg}`, data || "");
    },
  },
  persistence: {
    dir: "runs/quickstart",
    checkpointEveryIterations: 1,
    resume: true,
  },
});

console.log("Best system prompt:", result.bestCandidate.system);

Seed prompts matter

dsts currently works best as a prompt refiner, not a prompt inventor.

For heavy structured tasks, the seed prompt should already encode the stable protocol of the task:

  • output shape and schema expectations,
  • allowed labels or field values,
  • evidence or citation format,
  • claim granularity,
  • edge-case handling rules.

If the seed prompt is weak, early GEPA iterations tend to spend budget rediscovering schema constraints instead of improving domain behavior. In practice, the best workflow is:

  1. Hand-write a seed prompt that is already structurally competent.
  2. Make sure it can satisfy the basic schema and rubric.
  3. Use GEPA to optimize domain judgments, tradeoffs, and prioritization.

Examples

Each example:

  • Loads .env locally (AI Gateway by default),
  • Prints total iterations, metric calls, cost (USD), and duration (ms),
  • Enables persistence to runs/....

Run:

npm run example              # email extraction
npm run example:message-spam # spam classification
npm run example:optimize-anything
npm run example:optimize-anything-legacy

Task-specific or private experiments can live under local-examples/, which is gitignored.

Optimize Anything (Advanced)

optimize() remains the stable, AI SDK-native prompt optimization path. For generalized optimization (including non-text state and seedless bootstrapping), use optimizeAnything().

import { optimizeAnything } from "@currentai/dsts";

const result = await optimizeAnything<{ system: string }, Task>({
  initialState: {
    system: "Extract {title, assignee?, priority} as strict JSON.",
  },
  trainset,
  evaluator: async (batch, state, captureTraces) => {
    const evalResult = await adapter.evaluate(batch, state, captureTraces);
    return {
      instanceScores: evalResult.scores,
      metrics: evalResult.metrics,
      trajectories: evalResult.trajectories,
      objectives: {
        correctness: avg(evalResult.scores),
        latency: avg(evalResult.metrics?.map((m) => m.latency_ms ?? 0) ?? []),
      },
      metricCalls: batch.length,
    };
  },
  mutator: async (state, context) => {
    // mutate prompt text using failed examples in context.evaluation
    return { ...state, system: state.system + "\nBe stricter with priority mapping." };
  },
  objectives: { latency: { direction: "minimize" } },
  scalarObjective: "correctness",
  maxIterations: 5,
  maxMetricCalls: 100,
});

console.log("Best prompt:", result.bestState.system);

Legacy Adapter Bridge

To reuse an existing GEPAAdapter with optimizeAnything, use fromLegacyAdapter:

import { fromLegacyAdapter, optimizeAnything } from "@currentai/dsts";
// const adapter = new MyGEPAAdapter(...)
// const { evaluator, mutator } = fromLegacyAdapter(adapter)

How it works

  • Default adapter decides generateObject vs generateText based on schema presence in each task; collects per‑instance scores, latency_ms, and cost_usd (via tokenlens when usage is available).
  • GEPA optimizer maintains a candidate archive, runs minibatch reflection, and accepts improving children. It computes per‑candidate metrics:
    • correctness = average(score[])
    • latency = −avg(latency_ms) (stored negative so higher is better)
    • cost is tracked cumulatively and enforced via maxBudgetUSD.
  • Pareto front and 2D hyper‑volume (when exactly two objectives) are logged per iteration and at the end.

AI SDK passthrough

Pass the object variant for taskLM to forward extra options directly into AI SDK calls (both generateObject and generateText). All unknown fields are spread through to the adapter and then to the SDK:

optimize({
  // ...
  taskLM: {
    model: "openai/gpt-5-nano",
    temperature: 0.2,
    providerOptions: { openai: { service_tier: "default" } },
    // tools, stopWhen, toolChoice, maxToolRoundtrips, experimentalTelemetry, etc. are also supported
  },
})

Steering reflection (no templates)

Use reflectionHint to insert a short guidance string at the top of the reflection prompt. Keep it concise:

optimize({
  // ...
  reflectionHint: "Prioritize exact field correctness; avoid hallucinating properties.",
})

Key files:

Design choices

  • No custom LLM classes: pass model ids as strings (Gateway format, e.g., openai/gpt-5-nano). The adapter uses AI SDK directly.
  • Minimal knobs: set budgets (maxMetricCalls, maxBudgetUSD), minibatch size, and selectors. Concurrency defaults to 10.
  • Multi‑objective by default: we optimise for correctness and latency together; add cost as an explicit objective later if desired.

Environment

  • AI Gateway by default. Set AI_GATEWAY_API_KEY in .env or export it in your shell.
  • If you prefer provider‑direct, swap to @ai-sdk/openai models and pass model objects; the adapter will forward them.

Roadmap

  • Extend hyper‑volume and objectives (e.g., cost as a third dimension) with explicit reference points.
  • Reflection concurrency (optional) and parent/child evaluation parallelism.