tessl install tessl/npm-langsmith@0.4.3TypeScript client SDK for the LangSmith LLM tracing, evaluation, and monitoring platform.
LangSmith provides seamless integration with Jest and Vitest testing frameworks, enabling test-driven evaluation workflows.
The testing integrations extend familiar testing APIs with LangSmith-specific features:
When to use testing integration:
LangSmith provides identical APIs for both Jest and Vitest.
Use if you're already using Jest or prefer its ecosystem.
import { test, expect } from "langsmith/jest";
test(
"greeting generation",
{
input: { name: "Alice" },
expected: { greeting: "Hello, Alice!" }
},
async (input) => {
return { greeting: `Hello, ${input.name}!` };
}
);Use if you're using Vite/Vitest or want faster test execution.
import { test, expect } from "langsmith/vitest";
test(
"summarize text correctly",
{
input: { text: "Long document..." },
expected: { summary: "Summary" }
},
async (input) => {
return await summarizeText(input.text);
}
);Vitest requires reporter configuration:
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
reporters: ["default", "langsmith/vitest/reporter"]
}
});| Feature | Jest | Vitest |
|---|---|---|
| Test API | Identical | Identical |
| Custom Matchers | Yes | Yes |
| Reporter Config | Not required | Required |
| Performance | Good | Faster |
| ES Modules | Requires config | Native |
| TypeScript | Requires ts-jest | Native |
Recommendation:
Both frameworks provide:
// Relative closeness (normalized edit distance)
expect(output).toBeRelativeCloseTo("Expected text", { threshold: 0.8 });
// Absolute closeness (raw edit distance)
expect(output).toBeAbsoluteCloseTo("Expected text", { threshold: 5 });
// Semantic similarity (embeddings-based)
expect(output).toBeSemanticCloseTo("Expected meaning", { threshold: 0.85 });
// Custom evaluators
expect(output).evaluatedBy(customEvaluator);import { test, logFeedback, logOutputs } from "langsmith/jest"; // or vitest
test(
"with feedback",
{ input: { text: "test" } },
async (input) => {
const result = await process(input.text);
logFeedback({
key: "quality",
score: 0.95,
comment: "High quality"
});
logOutputs({ step1: result });
return result;
}
);import { wrapEvaluator } from "langsmith/jest"; // or vitest
const customEvaluator = wrapEvaluator((args) => {
const { input, output, expected } = args;
return {
key: "custom_metric",
score: calculateScore(output, expected),
comment: "Evaluation comment"
};
});
test(
"with custom evaluator",
{
input: "test",
evaluators: [customEvaluator]
},
async (input) => {
const result = await process(input);
expect(result).evaluatedBy(customEvaluator);
return result;
}
);import { test } from "langsmith/jest"; // or vitest
test(
"test name",
{
input: { data: "input" },
expected: { result: "output" }
},
async (input) => {
return { result: processData(input.data) };
}
);test(
"translation quality",
{
input: { text: "Hello", lang: "es" },
expected: "Hola",
datasetName: "translation-tests",
projectName: "translation-eval"
},
async (input) => {
return await translate(input.text, input.lang);
}
);import { describe, test } from "langsmith/jest"; // or vitest
describe("LLM Response Generation", () => {
test(
"should generate greeting",
{
input: { name: "Bob" },
expected: { message: "Hello, Bob!" }
},
async (input) => {
return { message: `Hello, ${input.name}!` };
}
);
test(
"should generate farewell",
{
input: { name: "Bob" },
expected: { message: "Goodbye, Bob!" }
},
async (input) => {
return { message: `Goodbye, ${input.name}!` };
}
);
});