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

@langchain/typesafe

v0.0.2

Published

TypeSafe System One integration for LangChain.js (Jev classifier).

Readme

@langchain/typesafe

This package contains the LangChain.js integration for TypeSafe System One models.

TypeSafe's jev model answers typed questions about unstructured input — no string generation, no parsing, no schema wrangling. It returns calibrated probabilities in 70–500ms, and every question in a single request is evaluated in parallel, so asking ten questions costs barely more than asking one.

Installation

npm install @langchain/typesafe @langchain/core

This package passes @langchain/core as a peer dependency. Make sure your project resolves a single instance of it:

{
  "overrides": { "@langchain/core": "^1.0.0" },
  "resolutions": { "@langchain/core": "^1.0.0" },
  "pnpm": { "overrides": { "@langchain/core": "^1.0.0" } }
}

Usage

Set TYPESAFE_API_KEY in your environment, then:

import { TypeSafeClassifier } from "@langchain/typesafe";

const classifier = new TypeSafeClassifier({
  questions: {
    department: {
      type: "choice",
      criteria: {
        billing: "Payment and payout issues",
        technical: "Bugs and outages",
        sales: null,
      },
      instructions: "Which team should handle this?",
    },
    urgent: { type: "noul", instructions: "Does this convey urgency?" },
    frustration: {
      type: "score",
      criteria: ["calm", "frustrated", "angry"],
      instructions: "How frustrated is the writer?",
    },
  },
});

const result = await classifier.invoke({
  message: "Help! My payouts have been failing for 3 days.",
  account_tier: "enterprise",
});

result.answers.department; // { type: "choice", choice: "billing", confidence: 0.99, probabilities: {...} }
result.answers.urgent; // { type: "noul", noul: 0.97 }
result.answers.frustration; // { type: "score", score: 1.3, legend: { 0: "calm", ... }, ... }

result.model is the versioned model that actually answered (e.g. jev-1.13.0), not the alias you sent — jev-latest in, jev-1.13.0 out.

Three read-only, non-enumerable helpers partition answers by variant, keyed by question id — handy when you only care about one kind of question:

result.choices.department; // same object as result.answers.department
result.nouls.urgent;
result.scores.frustration;

Because they're non-enumerable, they never duplicate answers in JSON.stringify(result) or a LangSmith trace.

Question types

| Type | Ask | Get back | | -------- | ------------------------------------------- | -------------------------------------------------------------------------------------------- | | choice | pick one of N labels you define | the winning label, the full distribution, and a confidence | | score | position on an ordered rubric (low to high) | a probability-weighted number that may land between levels, plus a legend and distribution | | noul | a single yes/no proposition | a bare probability from 0 to 1 |

A Noul answer carries no confidence and no probabilities. For a binary question the probability is the confidence: 0.97 means "almost certainly yes", and 0.5 means genuine uncertainty. Threshold it when your code needs a hard decision.

score and choice may omit instructions if criteria alone is clear. A noul needs at least one of the two.

Messages as input

LangChain messages are the common unit of context, so they are accepted anywhere in the input and converted automatically:

await classifier.invoke([new HumanMessage("..."), new AIMessage("...")]);
await classifier.invoke({ conversation: messages, account: { tier: "pro" } });

Tracing

TypeSafeClassifier is a Runnable, so calls appear in LangSmith traces with their inputs, outputs and configuration, nested inside whatever agent or chain invoked them. The API key is redacted before it reaches the tracer. Note that LangSmith does not attribute token cost to non-LLM runs, so usage appears in the traced output rather than as a costed metric.

Errors

import { TypeSafeRateLimitError } from "@langchain/typesafe";

try {
  await classifier.invoke(input);
} catch (error) {
  if (TypeSafeRateLimitError.isInstance(error)) {
    console.log(error.retryAfterMs, error.requestId);
  }
}

Use .isInstance() rather than instanceof — it stays correct when more than one copy of the library ends up in a dependency tree.

Errors carry status, requestId, body and headers as properties, but never render the response body into their message, because TypeSafe error bodies echo the request — including the content you asked it to classify.

Retries are handled by LangChain's AsyncCaller; configure them with maxRetries and maxConcurrency on the constructor.

@langchain/typesafe/middleware

Two createMiddleware-based factories for use with LangChain agents.

langchain is an optional peer dependency — the base package does not need it, so install it alongside if you use this entrypoint:

npm install @langchain/typesafe langchain

modelRouterMiddleware

Classifies the latest human message ONCE per agent run with a TypeSafe Choice, then routes every model call in that run to the selected model:

import { modelRouterMiddleware } from "@langchain/typesafe/middleware";
import { createAgent } from "langchain";

const agent = createAgent({
  model: "openai:gpt-5-mini",
  middleware: [
    modelRouterMiddleware({
      choices: {
        fast: {
          model: "openai:gpt-5-mini",
          criteria: "Simple, well-scoped tasks.",
        },
        powerful: {
          model: "openai:gpt-5",
          criteria: "Complex tasks requiring deeper reasoning.",
        },
      },
      instructions: "Choose the least costly model suited to the task.",
    }),
  ],
});

autoModeMiddleware

Blocks a tool call before it runs when a TypeSafe Noul scores it above a risk threshold. It blocks rather than asking, and composes with humanInTheLoopMiddleware rather than replacing it:

import { autoModeMiddleware } from "@langchain/typesafe/middleware";
import { createAgent } from "langchain";

const agent = createAgent({
  model: "openai:gpt-5",
  tools: [runSqlTool, sendEmailTool],
  middleware: [
    autoModeMiddleware({
      tools: ["run_sql", "send_email"],
    }),
  ],
});

Both middlewares build their own TypeSafeClassifier internally; pass classifierOptions (everything TypeSafeClassifier accepts except questions) to configure transport and model settings.

Development

pnpm install
pnpm build --filter @langchain/typesafe
pnpm test

Integration tests hit the live API and are excluded from pnpm test. To run them, put your key in libs/providers/langchain-typesafe/.env (this path, not the repo root — dotenv resolves relative to the package directory):

TYPESAFE_API_KEY=your-key

then:

pnpm test:int

They skip rather than fail when no key is present.

License

MIT