Skip to content

Commit b6e76c2

Browse files
dmontagupetyosi
andauthored
Add evals support (offline + online) under logfire/evals
Co-authored-by: Petyo Ivanov <underlog@gmail.com>
1 parent f605307 commit b6e76c2

86 files changed

Lines changed: 10152 additions & 248 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/evals-port.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'logfire': minor
3+
'@pydantic/logfire-node': minor
4+
---
5+
6+
Add evals support — offline + online evaluations.
7+
8+
A new `logfire/evals` subpath exports `Dataset`, `Case`, `Evaluator`, built-in evaluators (`Equals`, `EqualsExpected`, `Contains`, `IsInstance`, `MaxDuration`, `HasMatchingSpan`, `LLMJudge`), report-level evaluators (`ConfusionMatrixEvaluator`, `PrecisionRecallEvaluator`, `ROCAUCEvaluator`, `KolmogorovSmirnovEvaluator`), and `withOnlineEvaluation` for runtime monitoring.
9+
10+
Emitted OTel spans, log events, and report analyses are wire-compatible with the Python `pydantic-evals` package, so experiments, cases, report-level charts, and live evaluations show up automatically in the Logfire web UI without any additional configuration. Datasets serialize to / deserialize from the same YAML and JSON format Python uses (`Dataset.toFile` / `Dataset.fromFile`, `Dataset.jsonSchema()`), with filesystem helpers supported in Node, Bun, and Deno.
11+
12+
`logfire.configure()` now auto-installs the evals span-tree processor; users on a custom `TracerProvider` can install it manually with `getEvalsSpanProcessor()` from `logfire/evals`.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
node_modules
22
packages/*/*.tgz
3+
coverage
4+
packages/*/coverage
35
.env
46
scratch/
57
**/.turbo

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
24.14.1

AGENTS.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Agent Instructions
2+
3+
This file is the canonical project guide for coding agents. `CLAUDE.md` is kept as a symlink for tools that still look for that name. Keep this file tool-neutral and update it when project commands, package layout, or non-obvious conventions change.
4+
5+
## Project Overview
6+
7+
This repository is the Pydantic Logfire JavaScript SDK monorepo. It provides OpenTelemetry-based tracing and logging packages for Node.js, browsers, Cloudflare Workers, and standalone manual tracing.
8+
9+
## Repository Layout
10+
11+
- `packages/logfire-api` publishes `logfire`, the core manual tracing API.
12+
- `packages/logfire-node` publishes `@pydantic/logfire-node`, which adds Node.js SDK setup and automatic instrumentation.
13+
- `packages/logfire-cf-workers` publishes `@pydantic/logfire-cf-workers`, which adapts Logfire to Cloudflare Workers.
14+
- `packages/logfire-browser` publishes `@pydantic/logfire-browser`, which adapts Logfire to browser tracing.
15+
- `packages/tooling-config` contains shared build and lint configuration.
16+
- `examples/` contains runnable examples for Express, Next.js, Deno, Cloudflare Workers, browser usage, and related integrations.
17+
18+
## Environment
19+
20+
- Use the Node.js version in `.node-version`. The root `package.json` also enforces Node.js 24 through `engines`.
21+
- Use pnpm 10.28.0. The package manager is pinned in `packageManager`.
22+
- Run workspace commands from the repository root unless a package-level command is explicitly needed.
23+
24+
## Useful Commands
25+
26+
Install dependencies:
27+
28+
```bash
29+
pnpm install
30+
```
31+
32+
Build all packages:
33+
34+
```bash
35+
pnpm run build
36+
```
37+
38+
Build packages in watch-style development mode:
39+
40+
```bash
41+
pnpm run dev
42+
```
43+
44+
Run all package tests:
45+
46+
```bash
47+
pnpm run test
48+
```
49+
50+
Run all checks before broad or release-oriented changes:
51+
52+
```bash
53+
pnpm run check
54+
```
55+
56+
Run focused checks for one package:
57+
58+
```bash
59+
pnpm --filter logfire test
60+
pnpm --filter @pydantic/logfire-node test
61+
pnpm --filter @pydantic/logfire-browser typecheck
62+
```
63+
64+
Run a single Vitest test by name from a package filter:
65+
66+
```bash
67+
pnpm --filter logfire test -- -t "test name pattern"
68+
```
69+
70+
Format or verify formatting:
71+
72+
```bash
73+
pnpm run format
74+
pnpm run format-check
75+
```
76+
77+
Add a changeset when a package-visible change needs a release note or version bump:
78+
79+
```bash
80+
pnpm run changeset-add
81+
```
82+
83+
## Architecture Notes
84+
85+
- `logfire` wraps OpenTelemetry tracing APIs with convenience methods such as `span`, `startSpan`, `info`, `debug`, `warn`, and `error`.
86+
- Runtime packages depend on `logfire` and add environment-specific configuration and instrumentation.
87+
- Message templates are formatted by `logfireFormatWithExtras()` in `packages/logfire-api/src/formatter.ts`; template fields become structured attributes.
88+
- Sensitive data scrubbing is handled by `AttributeScrubber` in `packages/logfire-api/src/AttributeScrubber.ts`.
89+
- Trace IDs use ULIDs through `ULIDGenerator`.
90+
- Logfire spans use `logfire.span_type`: `log` for point-in-time events and `span` for duration-based work.
91+
92+
## Development Conventions
93+
94+
- Prefer existing package patterns, helpers, and OpenTelemetry abstractions over introducing new wrappers.
95+
- Keep changes scoped to the package or example relevant to the task.
96+
- Update examples or docs when public behavior, configuration, or package usage changes.
97+
- Add or update tests for behavior changes. If a package has minimal tests or `--passWithNoTests`, still run typecheck/build for that package when relevant.
98+
- Avoid adding production dependencies without a clear need; keep workspace dependency and lockfile changes together.
99+
- Do not put agent-specific or vendor-specific instructions here unless they are explicitly about repository compatibility. Use generic wording that applies to any coding agent.
100+
101+
## Testing Guidance
102+
103+
- Tests use Vitest and usually live alongside source files as `*.test.ts`.
104+
- Prefer exact assertions over fuzzy matching for stable output. Use `toBe` or `toEqual` with deterministic inputs instead of `toContain` or broad regex matching.
105+
- When testing formatted errors or stack output, mock stack strings so assertions stay deterministic.
106+
- For changes under `packages/logfire-api/src/evals`, consider the focused coverage script:
107+
108+
```bash
109+
pnpm --filter logfire run coverage:evals
110+
```
111+
112+
## Package-Specific Notes
113+
114+
- `packages/logfire-node/src/logfireConfig.ts` owns Node SDK configuration and environment variable handling.
115+
- Relevant environment variables include `LOGFIRE_TOKEN`, `LOGFIRE_SERVICE_NAME`, `LOGFIRE_SERVICE_VERSION`, `LOGFIRE_ENVIRONMENT`, `LOGFIRE_CONSOLE`, `LOGFIRE_SEND_TO_LOGFIRE`, and `LOGFIRE_DISTRIBUTED_TRACING`.
116+
- `packages/logfire-api` is the base API package and should not depend on runtime-specific packages.
117+
- Cloudflare Workers code should stay compatible with Worker runtime constraints.
118+
- Browser code should avoid Node-only APIs.
119+
120+
## Examples
121+
122+
Use examples to validate integration behavior when package-level tests do not cover the runtime path. Check the target example's `package.json` before running it, because scripts vary by example.
123+
124+
Typical flow:
125+
126+
```bash
127+
cd examples/express
128+
pnpm install
129+
pnpm run dev
130+
```
131+
132+
## Agent Guidance Maintenance
133+
134+
- Keep this file concise and operational. Prefer links or file paths over copied explanations when the code is self-describing.
135+
- If a subdirectory needs different build, test, or safety rules, add a nested `AGENTS.md` in that directory instead of growing this root file.
136+
- Instructions closest to the edited file should be treated as more specific than this root file.
137+
- Preserve the `CLAUDE.md` symlink unless the repository drops compatibility with tools that read it.

CLAUDE.md

Lines changed: 0 additions & 186 deletions
This file was deleted.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AGENTS.md

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,42 @@ Optionally, you can use the Logfire API package for creating manual spans.
259259
Install the `logfire` NPM package and call the respective methods
260260
from your code.
261261

262+
## Evaluations
263+
264+
The `logfire/evals` subpath provides offline datasets and online evaluation
265+
wrappers that emit Logfire-compatible OpenTelemetry spans and log events. Add
266+
`logfire` as a direct dependency in projects that import this subpath.
267+
268+
```ts
269+
import { Case, Dataset, Equals, EqualsExpected, withOnlineEvaluation } from 'logfire/evals'
270+
271+
const dataset = new Dataset<{ text: string }, string>({
272+
cases: [new Case({ expectedOutput: 'HELLO', inputs: { text: 'hello' }, name: 'hello' })],
273+
evaluators: [new EqualsExpected()],
274+
name: 'uppercase',
275+
})
276+
277+
await dataset.evaluate(({ text }) => text.toUpperCase())
278+
279+
const monitored = withOnlineEvaluation(async (text: string) => text.toUpperCase(), {
280+
evaluators: [new Equals({ value: 'HELLO' })],
281+
target: 'uppercase',
282+
})
283+
await monitored('hello')
284+
```
285+
286+
Dataset file helpers are available in Node, Bun, and Deno. Browser and
287+
Cloudflare Worker usage is limited to in-memory datasets and online evaluation;
288+
browser offline runs should keep `maxConcurrency: 1` because there is no
289+
`AsyncLocalStorage` equivalent.
290+
291+
Dataset YAML/JSON uses the Python `pydantic-evals` field names for portable
292+
files, for example `predicted_from`, `expected_from`, and snake_case
293+
`SpanQuery` keys. Online evaluator `context.inputs` is built from JavaScript
294+
function parameter names when they can be inspected; pass
295+
`extractArgs: ['name', ...]` when bundled or minified code needs stable input
296+
names, or `extractArgs: false` to keep positional input values.
297+
262298
### Configuring the instrumentation
263299

264300
The `logfire.configure` function accepts a set of configuration options that

0 commit comments

Comments
 (0)