Observed since 20 Oct, 23:14 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Compare baseline vs current agent runs and surface regressions as structured reasons: success loss, new errors, failed tool calls, output drift, step/latency/cost bloat.
Compare baseline vs current agent runs and surface regressions as structured reasons, not vibes. Answers "why does the agent feel worse?" with seven named signals:
Zero runtime dependencies. Works on any agent framework — you hand it JSONL traces, it tells you what changed.
pip install agent-run-diff
agent-run-diff baseline.jsonl current.jsonl
Exits 0 on clean, 1 on any regression, 2 on bad input. The markdown report prints to stdout:
# Agent Regression Report
Pass rate: baseline **92%** → current **78%** (-14pp)
Total latency: 48,200 ms → 81,400 ms
Total cost: $1.2400 → $2.1800
## Summary
- Success losses: **3**
- New error kinds: **1**
- Tool failure rises: **2**
- Step bloat cases: **4**
- Latency bloat: **6**
- Cost bloat: **5**
## Success losses (was passing, now not)
- `login-flow-happy-path` — status: success → failed
...
## Tool failures rising
| Tool | Baseline | Current | Sample errors |
| --- | ---: | ---: | --- |
| browser.click | 0 | 4 | `Element not found: #submit` |
...
A run is one JSON object. The shape is lenient — accepts snake_case or camelCase, and several common aliases:
{
"run_id": "run-2026-04-24-abc",
"case_id": "login-flow-happy-path",
"status": "success",
"final_output": "Logged in as alice.",
"steps": [
{
"type": "tool_call",
"tool_name": "browser.click",
"tool_args": {"selector": "#submit"},
"error": null,
"latency_ms": 420,
"cost_usd": 0.001
}
],
"total_latency_ms": 2300,
"total_cost_usd": 0.08
}
Aliases recognized:
case_id | caseId | test_id | testId (falls back to run_id if none present)status | outcome | result.status — values like pass/passed/ok/success all normalize to "success"final_output | finalOutput | outputsteps | trace | eventstool_name/toolName/name, error/error.message, latency_ms/latencyMs/duration_mstotal_cost_usd/totalCostUsd, total_latency_ms/totalLatencyMs (auto-summed from steps if absent)Runs are matched between baseline and current by case_id.
Defaults are transparent (1.3x bloat, 0.7 output-drift F1) and overridable:
agent-run-diff base.jsonl curr.jsonl \
--step-ratio 1.5 \
--latency-ratio 2.0 \
--cost-ratio 1.2 \
--output-drift-f1 0.6 \
--min-latency-ms 200 \
--min-cost-usd 0.01
The --min-latency-ms and --min-cost-usd floors prevent noise on trivially-short or trivially-cheap runs.
- name: Compare against baseline
run: |
agent-run-diff \
baselines/2026-04-20.jsonl \
runs/$GITHUB_SHA.jsonl \
--format json > regression.json
The workflow step fails when any regression is detected (exit 1). Attach regression.json as an artifact to make the seven signals browsable in the PR review.
cost_usd we use it; otherwise cost bloat is skipped. Pricing is your framework's job, not this tool's.from pathlib import Path
from agent_run_diff import parse_runs_file, analyze, render_markdown, Thresholds
baseline = parse_runs_file("baseline.jsonl")
current = parse_runs_file("current.jsonl")
report = analyze(baseline, current, thresholds=Thresholds(latency_ratio=1.5))
print(render_markdown(report))
if report.has_regressions:
raise SystemExit(1)
MIT.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.0 | 24 Apr 2026 | 1 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 23:14 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:e890138b7793aaa755be2855e5387b467ec9d5f330e39d8373e09645e63dda54