Structure of an eval
Evals live underevals/, with file names ending in .eval.ts, and default-export defineEval(...):
- The file path decides the ID: the ID of
evals/billing/refund.eval.tsisbilling/refund. Only.eval.tsand.eval.tsxfiles are discovered. descriptionappears in results. Write it as one sentence about what this eval verifies.tagsare for selecting by tag, for exampleniceeval exp local --tag billing. The Experiment’sevalsfunction can read them too.test(t)is the eval body.thas every method for sending messages, asserting, and working with the Sandbox.
judge, timeoutMs, sandbox, and metadata, see the defineEval reference.
Single-turn: send one message and check the result
t.succeeded(): this turn completed normally, without failing or stopping in a waiting state.t.calledTool(...): it calledget_weather, the city in the arguments is Brooklyn, and it called it exactly once. Tool calls are only visible when the Adapter reports the matching events; see Write send.t.check(value, match): checks one specific value, here the reply text.
await t.check(...).orStop() to stop on failure.
Add .label("...") to a check, and results show your description instead of a piece of code, which is easier to read:
t.send() returns this turn’s Turn. Save it when you need to check one turn on its own:
Multi-turn: check that context carries over
send calls on the same t form one conversation. draft.succeeded() only checks the first turn; t.calledTool checks whether the tool was called anywhere in the eval. When you need two unrelated conversations, for example to simulate two users, open a new session with t.newSession().
Multi-turn conversation requires the Adapter to carry the previous turn’s context to the application; see Write send.
Give open-ended answers to the Judge
Questions like “is the answer grounded” or “is the tone right for elementary school students” cannot be written as a regex. Hand them to the Judge model to score:.gate(0.7) means anything below 0.7 fails. When a deterministic rule can check something, such as which tool was called or whether a file changed, prefer the deterministic rule; save the Judge for truly open-ended quality. To configure which model the Judge uses, see Configure and Verify the Judge.
Generate many evals from one dataset
When dozens of evals share the same logic and differ only in input, you do not need dozens of files. Export an array from one file:sql/0000 and sql/0001. To read a dataset from YAML or JSON and give each row a stable ID, see Data-Driven Tests.
Prepare a workspace for a Coding Agent
When evaluating a Coding Agent, the eval is still an ordinary.eval.ts. You just put a project into the Sandbox first, then let the Agent change it:
Report progress and issues during a run
When preparation is slow, uset.progress to show what is happening in the terminal. When something is worth recording but does not affect the conclusion, record a diagnostic with t.diagnostic:
progress is only shown during the run and is not saved. diagnostic is saved with this Attempt and visible in the results afterwards, but it does not change pass or fail. Write business conclusions as assertions. When preparation fails and the run cannot continue, throw an exception directly, and this run is recorded as errored.
Prepare and clean up external resources
Some evals create temporary resources outside the Sandbox, for example a temporary repository on a shared Git service. Usesetup to prepare and teardown to clean up; each runs once per Attempt:
- Most evals do not need
teardown. Files written into the Sandbox and installed dependencies disappear when the Sandbox is destroyed. Only resources outside the Sandbox need manual cleanup. - Once
setuphas started,teardownalways runs, even ifsetupthrows, so guard against resources that were never created. - When
teardownthrows or exceeds 30 seconds, it only records ateardown-faileddiagnostic and does not change the conclusion this Attempt already reached. To make a check affect the conclusion, put it insetuportest. - When
attemptsis greater than 1, multiple Attempts of the same eval run concurrently. Store handles in aWeakMapkeyed bysandbox, one per Attempt, so they do not overwrite each other.
Next steps
- When a task has partial completion and you want to score by how many steps were done: read Pass/Fail and Scored Evals.
- To write clear criteria that do not misjudge: read NiceEval Taste.
- For every matcher: see the expect reference.