Evaluations
Test jobs with deterministic scorers and model-based judges.
Fabric eval suites are TypeScript modules named *.eval.ts. Each suite supplies cases, a runner, one or more scorers, and an optional pass threshold. fh test discovers and runs them locally or in CI.
Install
pnpm add -D @fabric-harness/evals @fabric-harness/nodeEvaluate a job
import { containsTextScorer, defineEvalSuite } from '@fabric-harness/evals';
import { runAgent } from '@fabric-harness/node';
export default defineEvalSuite({
name: 'hello-quality',
cases: [
{ id: 'named-user', input: { name: 'Ada' }, expected: 'Ada' },
{ id: 'default-user', input: { name: 'World' }, expected: 'World' },
],
runner: async ({ case: evalCase }) => {
const run = await runAgent({
agent: 'hello',
payload: evalCase.input,
mock: true,
});
return run.result;
},
scorers: [containsTextScorer()],
passThreshold: 1,
});Run every suite:
fh testRun a subset or produce machine-readable output:
fh test evals --suite hello-quality
fh test --threshold 0.9 --jsonThe command exits nonzero when any suite fails, so it can be used directly as a CI quality gate.
Choose scorers
| Scorer | Use it for |
|---|---|
exactMatchScorer() | Deterministic structured or scalar output. |
containsTextScorer() | Required text in an answer. |
regexMatchScorer() | IDs, formats, and constrained strings. |
jsonShapeMatchScorer() | Required JSON fields and primitive types. |
llmAsJudgeScorer() | Semantic criteria that deterministic assertions cannot express. |
Prefer deterministic scorers first. For an LLM judge, use a separate provider/model, write a narrow rubric, and set passThreshold explicitly. Never pass provider secrets through eval case input.
For long-lived comparisons and stored grading trajectories, see Jetty. For every exported type and scorer, see the eval library reference.