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
AScorer is a named, self-describing evaluator. Its score function is a
ScorerFn: given a ScorerInput, it returns a Promise<ScoreResult>.
A named scorer.
The argument passed to a
ScorerFn. Built from the task’s input, output, and
metadata at scoring time.What a
ScorerFn returns.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.
types.ts · See also ScorersMap, Components
createScorer
Build a customScorer from a plain config object. The returned scorer is just
its config; the work lives in your score function.
The named scorer, ready to bind to a task.
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 yourinstructions 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.
A scorer whose
score calls judge.generate(...) and parses the reply.llmJudge.js · Tests create-scorer.test.js · See also Built-in scorers
Built-in scorers
Each built-in is a factory that returns aScorer. 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 bysmithers 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:
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 viaEffect.runFork and returns immediately, so scoring never blocks the workflow.
Failures are logged, not thrown.
The keyed bindings to run.
Run/node coordinates plus the data the scorers grade. See
ScorerContext.Database adapter to persist results, or
null to skip persistence.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 toScoreResult (or null
when a scorer is sampled out or fails).
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.
Database adapter to read scorer rows from.
One row per scorer, ordered by scorer name.
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.