Vally 0.5.0
Released on 2026-05-21.
Breaking
- CLI: The
--evalcommand line switch forlinthas been removed, in favor oflint --eval-specorlint -e. (#277) - Program-grader now uses the workspace folder as its default working directory (#274)
- CLI: Removed the inline
promptpositional argument fromvally eval. Use--eval-spec,--suite, or--tagto drive evaluations.
Features
EvalRunOptions.onDiagnosticcallback for structured runtime warnings (falls back toconsole.warnwhen not set).- New built-in
mockexecutor for testing graders without a live agent. Returns a pass-through trajectory (stimulus prompt as output) or loads fixture responses from<workDir>/.mock-executor/<stimulus.name>.json. Registered alongsidecopilot-sdkin the global executor registry. - Program and run-command graders: added
envconfig field for passing custom environment variables to grader subprocesses. Reserved variables (EVALUATE_WORKSPACE,EVALUATE_GRADER_INPUT) cannot be overridden by program grader config. - Allow
programandrun-commandgraders to run from a configured subdirectory under the preserved workspace, accepting either slash style (#278) - Multi-judge
panelgrader — runs the same rubric across N judge models in parallel and combines their verdicts with a configurable aggregation strategy (majority/mean/median/min). Failure isolation keeps surviving judges scoring when one judge fails; per-judge breakdowns appear indetails; the raw spread of judge scores (max − min) is surfaced viametadata.disagreement. (#189)- The panel grader intentionally does not expose a per-invocation
panel_concurrencyknob — judges fan out together viaPromise.allSettled. LLM rate-limit / throughput control belongs at a global layer (e.g. on theLlmClientor runner) so it applies uniformly across every LLM-using grader rather than only within a single panel call. Tracked in #363. maxis intentionally not included in the aggregation strategies — it was only there for symmetry withminand has no concrete use case (“any single judge can pass the panel” is rarely what you actually want). Can be added back if a real workload calls for it.- The panel grader does not flag disagreement against a threshold or affect
passedbased on it. The raw spread is recorded inmetadata.disagreementso downstream tooling (reporters, dashboards, alerts) can apply its own policy. Wiring disagreement into diagnostics / reporter footnotes / soft-fail semantics is tracked in #365.
- The panel grader intentionally does not expose a per-invocation
Fixed
panelgrader:validateEvalSpec/vally lintnow rejects an emptymodelslist at lint time instead of letting the empty config slip through and only fail at runtime. Backed by a new genericminItemsschema constraint for array-shaped grader config fields.panelgrader:validateEvalSpec/vally lintnow also rejects empty-string entries inmodels(e.g.,models: ["gpt-5", ""]), which would previously pass lint and be silently dropped at runtime. Backed by a new genericitemMinLengthschema constraint for string-array fields. The constraint trims before measuring length, so whitespace-only entries like[" "]are also rejected.panelgrader:parseConfig()now trims model entries so whitespace-only model names (" ") are dropped rather than passed through to the LLM client.panelgrader:PanelGraderConfig.modelsis now typed as required (string[]) to match the validator schema and the eval.yaml shape, giving programmatic callers compile-time enforcement consistent withvally lint.panelgrader: per-judge metadata keyfailed_judgesis now snake_case in both the partial-failure and all-judges-failed result paths (the all-failed path previously emittedfailedJudges), consistent with the other emitted metadata keys (token_usage,latency_ms,raw_overall_score).panelgrader: per-judge information (score, raw score, latency, token usage, reasoning) is now only emitted indetails[*]; the redundantmetadata.judgesarray (a denormalized copy of the same data) is gone. Consumers should walkdetailsto inspect per-judge results.- Eval-level
tagsare now merged onto each stimulus during resolution (child-wins), so custom executors receive the effective tags. (#337) - CLI: standardized
-eas the short alias for--eval-specacrosseval,lint,grade,compare, andexport. (#277) - Use the proper workdir for the program grader. (#274)
- Eval runs now abort when MCP servers fail to load instead of silently continuing. Each failed MCP server load will show up as an
errorevent in the trajectory. (#288) tool-callsgrader: thenamefield of aToolMatchis now matched as an unanchored regex, matching its documented behavior. Use^name$for an exact match; the inline-flag convention ((?i),(?m),(?s)) is supported. Emptynamepatterns are now rejected with a clear error (an empty regex would otherwise match every tool call). Behavior change: configs whose tool names contain any regex metacharacter will now be interpreted as regex — escape each metacharacter with\to preserve a literal match (and optionally wrap with^...$to also require an exact, non-substring match).
Changed
- CLI:
vally evalnow always writes result files to a directory. The default is./vally-results/<timestamp>/(a summary at the end of the run gives the exact path). Use--output-dirto specify a different directory. - CLI: The
--junit requires --output-dirand--keep-executor-session-logs requires --output-dirguards have been removed since output is now always written to disk.