Skip to main content
A scorer grades a task’s output and returns a number between 0 and 1. Attach scorers to a Task via its scorers prop; they run after the task completes and never block the workflow. Each result is persisted to the _smithers_scorers table so you can aggregate scores across runs. All scorer values and types are re-exported from the smithers-orchestrator facade, which is canonical. The smithers-orchestrator/scorers subpath exports the same surface.
The component that hosts scorers (Task) can be imported directly or taken from createSmithers; the factory form binds it to the workflow context. See the Components reference for the scorers prop and ScorersMap for its shape.

Concepts

A Scorer is a named, self-describing evaluator. Its score function is a ScorerFn: given a ScorerInput, it returns a Promise<ScoreResult>.
Scorer
object
A named scorer.
ScorerInput
object
The argument passed to a ScorerFn. Built from the task’s input, output, and metadata at scoring time.
ScoreResult
object
What a ScorerFn returns.
A scorer is bound to a task through a ScorerBinding, and a ScorersMap is the keyed set of bindings you pass to the scorers prop. Each binding may carry a SamplingConfig controlling how often the scorer runs.
Source types.ts · See also ScorersMap, Components

createScorer

Build a custom Scorer from a plain config object. The returned scorer is just its config; the work lives in your score function.
config
CreateScorerConfig
required
Scorer
object
The named scorer, ready to bind to a task.
Source createScorer.js · Tests create-scorer.test.js · See also llmJudge

llmJudge

Build an LLM-as-judge scorer that delegates evaluation to an agent. The judge is prompted with your instructions plus the output of promptTemplate, and is expected to reply with JSON { "score": <0-1>, "reason": "<text>" }. The reply is parsed leniently (a bare number works, and braces inside reason do not truncate the match), the score is clamped to 0–1, and an unparseable reply scores 0.
config
LlmJudgeConfig
required
Scorer
object
A scorer whose score calls judge.generate(...) and parses the reply.
Source llmJudge.js · Tests create-scorer.test.js · See also Built-in scorers

Built-in scorers

Each built-in is a factory that returns a Scorer. Judge-based scorers take an AgentLike judge; the deterministic ones do not call an agent. The five delegation-chain scorers read their data from the scored output or context and no-op (score 1, meta.skipped) when it is absent. Their results combine into a run total with delegationRunScore(results, { weights? }) (default weights 0.25 / 0.25 / 0.15 / 0.15 / 0.2), built on the generic weightedScore(results, weights) helper; missing or skipped components drop out and the remaining weights renormalize.
schemaAdherenceScorer and latencyScorer no-op (score 1) when the input lacks an outputSchema or latencyMs. toxicityScorer scores the level of toxicity, so clean text scores near 0.

smithersScorers

smithersScorers is the Drizzle table backing scorer persistence (_smithers_scorers). Every scorer result is inserted here as a ScoreRow; aggregateScores reads from it. Use it for direct queries against your store. Source faithfulnessScorer.js · schema.js · Tests builtins.test.js · See also ScoreRow

Workflow UI compliance

workflowUiComplianceScorer grades a generated workflow UI bundle against the shared-component doctrine; it wraps the pure gradeWorkflowUiSource(uiSource, options), which scans the bundle for hand-rolled status pills/tables/colors, missing createGatewayReactRoot mounting, unsupported imports, and (when the workflow has agent tasks, detected by workflowHasAgentTasks(workflowSource)) a missing live NodeChatStream. The create-ui workflow uses the same grade as its hard compliance gate, so a UI that fails here also fails authoring. Source workflowUiCompliance.js · Tests workflow-ui-compliance.test.js

Eval datasets and assertions

The scorer package also owns the shared eval-case domain used by smithers eval, the eval-suite-run workflow, and score-comparison UIs.
parseEvalDataset(text) accepts a JSON array or JSONL rows, ignores blank and # comment lines in JSONL, derives missing ids, rejects duplicate ids, and validates optional judge assertions. It returns an EvalDatasetParseResult instead of throwing for malformed authored data. evaluateEvalCase(args) performs deterministic grading. An expected object using only status, output, outputContains, and errorContains is an assertion spec. Other objects and arrays use recursive subset matching; scalar values use canonical JSON equality. The result contains every EvalAssertion and a combined passed flag. evaluateEvalCaseAsync(args, runJudge?) composes those deterministic assertions with an optional EvalJudge:
Judge scores are clamped to 0 through 1. Missing runners, invalid judge configuration, provider errors, and malformed verdicts become failed assertions on that case instead of aborting the suite. normalizeEvalJudge validates the authored contract; normalizeExpected, jsonContains, jsonEquals, formatEvalError, isPlainObject, and slugifyEvalToken are the exported low-level helpers for clients that must share the same semantics. evalCaseRunId(suiteId, caseId, evalRunId) builds a readable, bounded, collision-resistant child-run id. evalAssertionScorer() converts the assertions stored on a case task output into the persisted score row read by listScoresForRuns and getScoreDetail. EVAL_CASE_STATUSES defines the allowed engine statuses for status assertions. Source evalCases.js · Tests eval-cases.test.js · See also Evals quickstart, Score comparison RPC

Running scorers

Bound scorers run automatically when a task completes, so you rarely call these directly. They are exported for custom hosts, batch evaluation, and tooling.

runScorersAsync

Fire-and-forget execution for live scoring. Runs every binding concurrently via Effect.runFork and returns immediately, so scoring never blocks the workflow. Failures are logged, not thrown.
scorers
ScorersMap
required
The keyed bindings to run.
ctx
ScorerContext
required
Run/node coordinates plus the data the scorers grade. See ScorerContext.
adapter
SmithersDb | null
required
Database adapter to persist results, or null to skip persistence.
eventBus
EventBus | null
Optional bus that receives ScorerStarted / ScorerFinished / ScorerFailed events.

runScorersBatch

Blocking execution for batch and test evaluation. Runs every binding concurrently and resolves to a map of binding key to ScoreResult (or null when a scorer is sampled out or fails).
Promise<Record<string, ScoreResult | null>>
object
One entry per binding key, in the order the scorers were declared.

aggregateScores

Compute per-scorer statistics across persisted results: count, mean, min, max, p50, and stddev. Filter to a run, node, or scorer.
adapter
SmithersDb
required
Database adapter to read scorer rows from.
opts
AggregateOptions
Promise<AggregateScore[]>
object
One row per scorer, ordered by scorer name.
Scores for a run are also viewable from the CLI:
Source run-scorers.js · aggregate.js · Tests run-scorers.test.js · aggregate.test.js · See also ScorerContext, AggregateScore
To wire scorers into a workflow and read them back, see the Evals quickstart. For the full type surface, see the Types reference. For the scorers prop on Task, see the Components reference.