evalcore 0.2.0__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. evalcore-1.0.0/CHANGELOG.md +96 -0
  2. {evalcore-0.2.0 → evalcore-1.0.0}/PKG-INFO +26 -20
  3. {evalcore-0.2.0 → evalcore-1.0.0}/README.md +24 -18
  4. evalcore-1.0.0/docs/clickhouse-schema.html +1112 -0
  5. evalcore-1.0.0/docs/clickhouse-schema.sql +412 -0
  6. {evalcore-0.2.0 → evalcore-1.0.0}/docs/design.md +20 -20
  7. {evalcore-0.2.0 → evalcore-1.0.0}/pyproject.toml +2 -2
  8. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/__init__.py +6 -9
  9. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/cli.py +36 -19
  10. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/errors.py +2 -1
  11. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/models.py +6 -0
  12. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/runner.py +26 -2
  13. evalcore-1.0.0/src/evalcore/store.py +505 -0
  14. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_cli.py +1 -1
  15. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_runner.py +34 -0
  16. evalcore-1.0.0/tests/test_store.py +376 -0
  17. {evalcore-0.2.0 → evalcore-1.0.0}/uv.lock +1 -1
  18. evalcore-0.2.0/CHANGELOG.md +0 -35
  19. evalcore-0.2.0/src/evalcore/store.py +0 -286
  20. evalcore-0.2.0/tests/test_store.py +0 -173
  21. {evalcore-0.2.0 → evalcore-1.0.0}/.github/workflows/ci.yml +0 -0
  22. {evalcore-0.2.0 → evalcore-1.0.0}/.github/workflows/publish.yml +0 -0
  23. {evalcore-0.2.0 → evalcore-1.0.0}/.gitignore +0 -0
  24. {evalcore-0.2.0 → evalcore-1.0.0}/.pre-commit-config.yaml +0 -0
  25. {evalcore-0.2.0 → evalcore-1.0.0}/LICENSE +0 -0
  26. {evalcore-0.2.0 → evalcore-1.0.0}/examples/__init__.py +0 -0
  27. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/README.md +0 -0
  28. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/__init__.py +0 -0
  29. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/adapter.py +0 -0
  30. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/angry_complaint.yaml +0 -0
  31. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/billing_question.yaml +0 -0
  32. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/double_charge.yaml +0 -0
  33. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/refund_request.yaml +0 -0
  34. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/fixtures/support_reply_judge.yaml +0 -0
  35. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/fixtures/support_reply_pairwise.yaml +0 -0
  36. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/fixtures/support_reply_replay.yaml +0 -0
  37. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/graders.py +0 -0
  38. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/run_eval.py +0 -0
  39. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/suite.yaml +0 -0
  40. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/tests/__init__.py +0 -0
  41. {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/tests/test_quickstart.py +0 -0
  42. {evalcore-0.2.0 → evalcore-1.0.0}/justfile +0 -0
  43. {evalcore-0.2.0 → evalcore-1.0.0}/pyrightconfig.json +0 -0
  44. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/__init__.py +0 -0
  45. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/base.py +0 -0
  46. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/env.py +0 -0
  47. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/http.py +0 -0
  48. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/replay.py +0 -0
  49. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/compare.py +0 -0
  50. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/__init__.py +0 -0
  51. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/base.py +0 -0
  52. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/classification.py +0 -0
  53. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/deterministic.py +0 -0
  54. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/judge.py +0 -0
  55. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/numeric.py +0 -0
  56. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/loader.py +0 -0
  57. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/pairwise.py +0 -0
  58. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/py.typed +0 -0
  59. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/rating.py +0 -0
  60. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/refs.py +0 -0
  61. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/report.py +0 -0
  62. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/__init__.py +0 -0
  63. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/base.py +0 -0
  64. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/html.py +0 -0
  65. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/markdown.py +0 -0
  66. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/retry.py +0 -0
  67. {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/sweep.py +0 -0
  68. {evalcore-0.2.0 → evalcore-1.0.0}/tests/__init__.py +0 -0
  69. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_adapters.py +0 -0
  70. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_edge_cases.py +0 -0
  71. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_judge.py +0 -0
  72. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_judge_extra.py +0 -0
  73. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_live_clients.py +0 -0
  74. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_pairwise_extra.py +0 -0
  75. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_rating.py +0 -0
  76. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_rating_server.py +0 -0
  77. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_reporters.py +0 -0
  78. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_retry.py +0 -0
  79. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_sweep_pairwise.py +0 -0
  80. {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_unit.py +0 -0
  81. {evalcore-0.2.0 → evalcore-1.0.0}/uv.toml +0 -0
@@ -0,0 +1,96 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/), and the project follows
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2026-07-28
10
+
11
+ First stable release. The public API and the outbox row shape are now covered
12
+ by semantic versioning: a breaking change to either means a 2.0.
13
+
14
+ ### Changed
15
+ - **Breaking:** outbox rows no longer carry `input_tokens`, `output_tokens` or
16
+ `cost`. `Output.tokens` is an open dict an adapter may put anything in, and
17
+ usage accounting is captured outside the results store.
18
+ - **Breaking:** the run-grain `revision` key is emitted as
19
+ `application_revision`, which is its column name in the store.
20
+
21
+ ### Added
22
+ - `docs/clickhouse-schema.sql`: the ClickHouse schema the outbox rows target -
23
+ the written `evaluation_scores` table, the run-grain `evaluations` view over
24
+ it, the row grammar as `CONSTRAINT`s, and the trend queries. Also rendered as
25
+ `docs/clickhouse-schema.html`.
26
+
27
+ ## [0.3.0] - 2026-07-28
28
+
29
+ ### Changed
30
+ - **Breaking:** the results-store outbox is now one feed at
31
+ `(run, case, sample, grader, metric)` grain, targeting a single flat
32
+ `evaluation_scores` table with the run trend and the invocation grain as
33
+ plain views over it. `store.scorecard_rows` and
34
+ `JsonlOutboxExporter.export` are removed; use `store.score_rows` and
35
+ `export_scores`. `--export-scores` is now an alias for `--export`.
36
+ - **Breaking:** a missing measurement is emitted as `null` rather than the
37
+ `(value=0, has_value=false)` sentinel pair, and the `has_value` / `has_stdev`
38
+ companion keys are gone. The store columns are `Nullable`, and a real `0.0` is
39
+ a meaningful score.
40
+ - **Breaking:** outbox row keys are the store column names, so `project` is
41
+ emitted as `application`, `mode` as `adapter_mode`, `created_at` as
42
+ `timestamp`, and `Output.error` as `is_error` plus `error_text`.
43
+ - **Breaking:** outbox rows no longer carry `model_id` or `prompt_version`. Both
44
+ are `variant.knobs.get(...)` projections and travel inside `variant_knobs`.
45
+ - **Breaking:** `run_id` is now a dashed UUIDv7 rather than `uuid4().hex`, so it
46
+ parses as a ClickHouse `UUID` and carries its own creation time. Uses
47
+ `uuid.uuid7()` on 3.14 and an RFC 9562 implementation on 3.11 through 3.13.
48
+ - Outbox rows now carry the gate: `gate_verdict`, `gate_win`,
49
+ `baseline_run_id`, `baseline_variant`, `win_baseline`, `win_candidate`,
50
+ `win_delta` and `gate_summary` at run grain, plus `win`, `guardrail` and
51
+ `guardrail_gap` on the metric each one refers to. Pass the `Comparison` to
52
+ `score_rows`; without it a run reads as ungated.
53
+
54
+ ### Added
55
+ - `RunResult.aggregate_scores`, retaining the `kind='aggregate'` scores so a
56
+ store row keeps the grader that emitted them and what it reported. The
57
+ scorecard kept only their values.
58
+ - `store.grader_lookups`, mapping grader names to a category and to a judge
59
+ scale from a suite's grader specs, since a `Score` carries neither.
60
+ - Three outbox row shapes that previously had no representation: an aggregate
61
+ metric (no `case_id`), an invocation that failed before any grader ran (no
62
+ `grader` or `metric`), and a metric a guardrail or the win metric names but
63
+ never scored (null value).
64
+
65
+ ## [0.2.0] - 2026-07-16
66
+
67
+ ### Changed
68
+ - **Breaking:** the import package and CLI are now `evalcore` (were `evalkit`).
69
+ Update `import evalkit` to `import evalcore` and the `evalkit` command to
70
+ `evalcore`. The distribution name (`evalcore`) is unchanged.
71
+ - Lowered the minimum Python to **3.11** (was 3.14).
72
+
73
+ ### Added
74
+ - `evalcore.__version__`.
75
+ - Public `evalcore.adapters.expand_env` for `${VAR}` expansion in custom
76
+ adapters (replaces the private `adapters._env` module).
77
+ - Exception hierarchy: `EvalcoreError` (base) and `ConfigError` (also a
78
+ `ValueError`, so existing handlers keep working).
79
+ - Top-level convenience entry points: `load_suite`, `load_cases`, `run_suite`,
80
+ `run_suite_sync`.
81
+ - HTML rendering for `sweep` and `pairwise` reports, and `--report` /
82
+ `--report-out` on those CLI commands.
83
+
84
+ ## [0.1.0] - 2026-07-16
85
+
86
+ - Initial public release: adapters (http/replay), graders (deterministic,
87
+ numeric, classification, LLM judge + panel), runner (N-sampling, concurrency,
88
+ retries, checkpoint/resume), compare/gate, sweep, pairwise, blind human
89
+ rating + ranking with judge agreement, Markdown/HTML reporters, JSON +
90
+ column-store outbox, and content-hash provenance.
91
+
92
+ [Unreleased]: https://github.com/scottpmiller/evalcore/compare/1.0.0...HEAD
93
+ [1.0.0]: https://github.com/scottpmiller/evalcore/compare/0.3.0...1.0.0
94
+ [0.3.0]: https://github.com/scottpmiller/evalcore/compare/0.2.0...0.3.0
95
+ [0.2.0]: https://github.com/scottpmiller/evalcore/compare/0.1.0...0.2.0
96
+ [0.1.0]: https://github.com/scottpmiller/evalcore/releases/tag/0.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evalcore
3
- Version: 0.2.0
3
+ Version: 1.0.0
4
4
  Summary: A generic, consumer-agnostic evaluation engine for prompt, model, and API outputs.
5
5
  Project-URL: Homepage, https://github.com/scottpmiller/evalcore
6
6
  Project-URL: Repository, https://github.com/scottpmiller/evalcore
@@ -8,7 +8,7 @@ Project-URL: Issues, https://github.com/scottpmiller/evalcore/issues
8
8
  Author: AWeber Communications
9
9
  License-Expression: BSD-3-Clause
10
10
  License-File: LICENSE
11
- Classifier: Development Status :: 4 - Beta
11
+ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Natural Language :: English
14
14
  Classifier: Operating System :: OS Independent
@@ -768,17 +768,19 @@ offline pairwise config.
768
768
  ## The outbox
769
769
 
770
770
  `JsonlOutboxExporter` flattens results into JSONL for a column-store shipper
771
- (e.g. ClickHouse) to drain, in a flat `eval_runs`/`eval_scores` shape:
772
- `export(scorecard)` writes one **metric** row each (`metric, value, stdev,
773
- metric_kind, n`), and `export_scores(run)` writes one **per-case score** row
774
- each (`case_id, sample_idx, grader, metric, value, passed, detail`). Both
775
- repeat the full reproducibility key (incl. `run_id`) so a multi-tenant
776
- trend table can filter/group on any dimension without joins. Swap the
777
- exporter for a real database client without touching the runner or any
778
- consumer. The rows use a no-`Nullable` convention (a missing value is the
779
- sentinel pair `(value=0, has_value=false)`; `passed` is the tri-state string
780
- `'true'|'false'|'null'`), so a JSONEachRow-style feed maps straight onto a
781
- flat schema.
771
+ (e.g. ClickHouse) to drain. `export_scores(run)` writes one feed at
772
+ `(run, case, sample, grader, metric)` grain - one row per score, carrying the
773
+ scored value, the invocation it came from, the gate verdict, and the full
774
+ reproducibility key (incl. `run_id`), so a multi-tenant trend table can
775
+ filter/group on any dimension without joins. Nothing derived is written: a
776
+ run's scorecard is a read-time aggregation over the same rows, so it cannot
777
+ disagree with the scores behind it. A missing measurement is `null` (those
778
+ columns are `Nullable`, and a real `0.0` is a meaningful score); `passed` is
779
+ the tri-state string `'true'|'false'|'null'`, matching its `Enum8`. Row keys
780
+ are the store's column names, so a JSONEachRow-style feed maps onto the schema
781
+ in
782
+ [`docs/clickhouse-schema.sql`](docs/clickhouse-schema.sql). Swap the exporter
783
+ for a real database client without touching the runner or any consumer.
782
784
 
783
785
  ---
784
786
 
@@ -825,16 +827,19 @@ src/evalcore/
825
827
  tests/ engine unit tests
826
828
  examples/quickstart a runnable consumer that doubles as an implementation test
827
829
  docs/design.md the design overview
830
+ docs/clickhouse-schema.sql the results-store schema the outbox rows target
828
831
  ```
829
832
 
830
833
  ## Status
831
834
 
832
- MVP. Built: deterministic + classification + **LLM-judge** (rubric scoring;
833
- single judge or a Claude/GPT **panel** with per-dimension means, per-judge
834
- overalls, inter-judge disagreement flagging, and image/screenshot inputs)
835
- graders, http/replay/browser adapters, runner (N-sampling, optional
836
- concurrency, per-sample `RunResult` + `run_id` + variance), comparison/gate,
837
- JSON + run + outbox store (metric and per-case-score rows), **N-way sweeps
835
+ 1.0. The public API and the outbox row shape are stable; a breaking change to
836
+ either means a 2.0. Built: deterministic + classification + **LLM-judge**
837
+ (rubric scoring; single judge or a Claude/GPT **panel** with per-dimension
838
+ means, per-judge overalls, inter-judge disagreement flagging, and
839
+ image/screenshot inputs) graders, http/replay/browser adapters, runner
840
+ (N-sampling, optional concurrency, per-sample `RunResult` + `run_id` +
841
+ variance), comparison/gate, JSON + run + outbox store (one score-grain feed,
842
+ `docs/clickhouse-schema.sql`), **N-way sweeps
838
843
  + counterbalanced pairwise A-vs-B win-rate** (`sweep`/`pairwise`), **blind
839
844
  human-rating + side-by-side ranking web apps** with judge↔human agreement and
840
845
  human-vs-judge pairwise agreement (`rate`/`agreement`, `rank`/`preferences`),
@@ -847,7 +852,8 @@ Known gaps / next:
847
852
  in, in `store.py`).
848
853
  - Cost/token capture: `Output.tokens`/`cost` fields exist but nothing
849
854
  populates them (an adapter must fill them from whatever usage its target
850
- reports).
855
+ reports), and neither is exported to the results store - usage accounting
856
+ is captured outside it.
851
857
  - Run robustness lands: retry with exponential backoff on transient failures
852
858
  for both the adapter (suite `retry:` + `Output.retryable`) and the LLM judge
853
859
  client, plus idempotent mid-run resume from a `run --checkpoint`.
@@ -736,17 +736,19 @@ offline pairwise config.
736
736
  ## The outbox
737
737
 
738
738
  `JsonlOutboxExporter` flattens results into JSONL for a column-store shipper
739
- (e.g. ClickHouse) to drain, in a flat `eval_runs`/`eval_scores` shape:
740
- `export(scorecard)` writes one **metric** row each (`metric, value, stdev,
741
- metric_kind, n`), and `export_scores(run)` writes one **per-case score** row
742
- each (`case_id, sample_idx, grader, metric, value, passed, detail`). Both
743
- repeat the full reproducibility key (incl. `run_id`) so a multi-tenant
744
- trend table can filter/group on any dimension without joins. Swap the
745
- exporter for a real database client without touching the runner or any
746
- consumer. The rows use a no-`Nullable` convention (a missing value is the
747
- sentinel pair `(value=0, has_value=false)`; `passed` is the tri-state string
748
- `'true'|'false'|'null'`), so a JSONEachRow-style feed maps straight onto a
749
- flat schema.
739
+ (e.g. ClickHouse) to drain. `export_scores(run)` writes one feed at
740
+ `(run, case, sample, grader, metric)` grain - one row per score, carrying the
741
+ scored value, the invocation it came from, the gate verdict, and the full
742
+ reproducibility key (incl. `run_id`), so a multi-tenant trend table can
743
+ filter/group on any dimension without joins. Nothing derived is written: a
744
+ run's scorecard is a read-time aggregation over the same rows, so it cannot
745
+ disagree with the scores behind it. A missing measurement is `null` (those
746
+ columns are `Nullable`, and a real `0.0` is a meaningful score); `passed` is
747
+ the tri-state string `'true'|'false'|'null'`, matching its `Enum8`. Row keys
748
+ are the store's column names, so a JSONEachRow-style feed maps onto the schema
749
+ in
750
+ [`docs/clickhouse-schema.sql`](docs/clickhouse-schema.sql). Swap the exporter
751
+ for a real database client without touching the runner or any consumer.
750
752
 
751
753
  ---
752
754
 
@@ -793,16 +795,19 @@ src/evalcore/
793
795
  tests/ engine unit tests
794
796
  examples/quickstart a runnable consumer that doubles as an implementation test
795
797
  docs/design.md the design overview
798
+ docs/clickhouse-schema.sql the results-store schema the outbox rows target
796
799
  ```
797
800
 
798
801
  ## Status
799
802
 
800
- MVP. Built: deterministic + classification + **LLM-judge** (rubric scoring;
801
- single judge or a Claude/GPT **panel** with per-dimension means, per-judge
802
- overalls, inter-judge disagreement flagging, and image/screenshot inputs)
803
- graders, http/replay/browser adapters, runner (N-sampling, optional
804
- concurrency, per-sample `RunResult` + `run_id` + variance), comparison/gate,
805
- JSON + run + outbox store (metric and per-case-score rows), **N-way sweeps
803
+ 1.0. The public API and the outbox row shape are stable; a breaking change to
804
+ either means a 2.0. Built: deterministic + classification + **LLM-judge**
805
+ (rubric scoring; single judge or a Claude/GPT **panel** with per-dimension
806
+ means, per-judge overalls, inter-judge disagreement flagging, and
807
+ image/screenshot inputs) graders, http/replay/browser adapters, runner
808
+ (N-sampling, optional concurrency, per-sample `RunResult` + `run_id` +
809
+ variance), comparison/gate, JSON + run + outbox store (one score-grain feed,
810
+ `docs/clickhouse-schema.sql`), **N-way sweeps
806
811
  + counterbalanced pairwise A-vs-B win-rate** (`sweep`/`pairwise`), **blind
807
812
  human-rating + side-by-side ranking web apps** with judge↔human agreement and
808
813
  human-vs-judge pairwise agreement (`rate`/`agreement`, `rank`/`preferences`),
@@ -815,7 +820,8 @@ Known gaps / next:
815
820
  in, in `store.py`).
816
821
  - Cost/token capture: `Output.tokens`/`cost` fields exist but nothing
817
822
  populates them (an adapter must fill them from whatever usage its target
818
- reports).
823
+ reports), and neither is exported to the results store - usage accounting
824
+ is captured outside it.
819
825
  - Run robustness lands: retry with exponential backoff on transient failures
820
826
  for both the adapter (suite `retry:` + `Output.retryable`) and the LLM judge
821
827
  client, plus idempotent mid-run resume from a `run --checkpoint`.