Skip to main content

REST API: Evals

The eval endpoints serve the JSON reports written by agentflow eval over HTTP, so the playground's Evals inspector can browse them. They read eval_reports/*.json from the server's working directory; they do not run evaluations.

Base path: /v1/evals

These endpoints are public

/v1/evals/runs and /v1/evals/runs/{run_id} are on the server's public allowlist. They carry no authentication and no authorization guard, even when auth is configured in agentflow.json. Anyone who can reach the server can read every file in eval_reports/, including the prompts, model outputs, and criteria recorded in each run.

They exist as a local report viewer. Before exposing a server to a network you do not control, either keep eval_reports/ out of the deployed image and working directory, or block /v1/evals/* at your ingress or reverse proxy. Treat anything you put in an eval case as publicly readable otherwise.


GET /v1/evals/runs

List every run found under eval_reports/, newest first.

Response:

{
"success": true,
"data": {
"runs": [
{
"id": "eval_20260721_101500",
"name": "Weather agent suite",
"run": "#3",
"rate": 91.7,
"status": "fail",
"cases": 12,
"ago": "14m ago"
}
]
}
}
FieldTypeDescription
idstringRun id. This is the report filename without its .json extension, and is what you pass to the detail endpoint.
namestringEval set name (falls back to the eval set id)
runstringRun number within this eval set, as #N, counted chronologically per eval set
ratenumberPass rate as a percentage, one decimal place
statusstringpass only when the pass rate is 100 percent, otherwise fail
casesintegerTotal cases in the run
agostringRelative age, for example just now, 14m ago, 3h ago, 2d ago

Reports that are missing, unreadable, or not valid JSON are skipped silently. When eval_reports/ does not exist the list is empty.


GET /v1/evals/runs/{run_id}

Full drilldown for one run.

Path parameters:

ParameterTypeDescription
run_idstringRun id from the listing. An unknown id returns 404.

Response:

{
"success": true,
"data": {
"title": "Weather agent suite · run #3",
"sub": "weather-suite · gpt-4o-mini · 2026-07-21 10:15 · 42.3s",
"rate": 91.7,
"status": "fail",
"threshold": 80,
"stats": [
{"label": "cases", "value": "12"},
{"label": "passed", "value": "11", "tone": "ok"},
{"label": "failed", "value": "1", "tone": "bad"},
{"label": "avg score", "value": "0.93"},
{"label": "avg latency", "value": "3.5s"},
{"label": "total tokens", "value": "18.4k tok"}
],
"cases": [
{
"id": "case-paris",
"name": "Weather in Paris",
"type": "eval",
"score": 0.96,
"status": "pass",
"lat": "3.1s",
"cost": "1.4k tok",
"input": "What is the weather in Paris?",
"expected": "—",
"actual": "The weather in Paris is 24 degrees and sunny.",
"rubric": [
{"key": "accuracy", "value": 0.96, "tone": "accent"},
{"key": "weighted score", "value": 0.96, "tone": "accent"}
],
"conversation": null
}
],
"regression": null
}
}
FieldTypeDescription
titlestringEval set label plus run number
substringEval set id, model (when recorded), run timestamp in UTC, and total duration, joined with ·
ratenumberPass rate as a percentage
statusstringpass or fail
thresholdintegerAverage criterion threshold across the run, as a percentage. Defaults to 80 when the report records no thresholds.
statsarraySummary tiles: cases, passed, failed (failures plus errors), average score, average latency, total tokens
casesarrayOne entry per case, see below
regressionobject or nullComparison against the previous run of the same eval set, or null when this is the first run of that set

Case

FieldTypeDescription
idstringEval case id
namestringCase name (falls back to the id)
typestringsim for a user-simulation case (the case carries turns metadata), otherwise eval
scorenumberMean criterion score, rounded to two decimals. Falls back to 1.0/0.0 from the pass flag when the case has no criteria.
statusstringpass or fail
latstringCase duration, for example 3.1s
coststringToken total, for example 1.4k tok. Token counts only; the report records no dollar cost.
inputstringFirst user message in the case, or
expectedstringAlways ; the report schema records no per-case expected value
actualstringThe agent's response
rubricarray or nullOne row per criterion plus a weighted score row. null when the case has no criteria.
conversationarray or nullParsed turns for sim cases, each {role, text} with role sim or agent. null for eval cases.

Regression

Present only when an earlier run of the same eval set exists. It compares case-by-case against the immediately preceding run.

FieldTypeDescription
noteobjectWhich two runs are being compared
summaryarrayPass-rate drift in percentage points, newly failing count, newly passing count, average score drift
rowsarrayPer-case rows with the score delta, direction (up, down, flat), and the pass/fail flip

Cases that exist in only one of the two runs are omitted from rows.


See also