evalshift 0.3.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.
- evalshift-0.3.0/.gitignore +77 -0
- evalshift-0.3.0/CHANGELOG.md +193 -0
- evalshift-0.3.0/LICENSE +21 -0
- evalshift-0.3.0/PKG-INFO +185 -0
- evalshift-0.3.0/README.md +133 -0
- evalshift-0.3.0/examples/agent/README.md +41 -0
- evalshift-0.3.0/examples/showcase/README.md +79 -0
- evalshift-0.3.0/pyproject.toml +106 -0
- evalshift-0.3.0/src/evalshift/__init__.py +12 -0
- evalshift-0.3.0/src/evalshift/__main__.py +17 -0
- evalshift-0.3.0/src/evalshift/analysis/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/analysis/slicing.py +143 -0
- evalshift-0.3.0/src/evalshift/analysis/statistics.py +382 -0
- evalshift-0.3.0/src/evalshift/cache/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/cache/schema.py +102 -0
- evalshift-0.3.0/src/evalshift/cache/store.py +214 -0
- evalshift-0.3.0/src/evalshift/cli/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/cli/commands/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/cli/commands/all.py +591 -0
- evalshift-0.3.0/src/evalshift/cli/commands/analyze.py +334 -0
- evalshift-0.3.0/src/evalshift/cli/commands/cache.py +42 -0
- evalshift-0.3.0/src/evalshift/cli/commands/doctor.py +232 -0
- evalshift-0.3.0/src/evalshift/cli/commands/evaluate.py +434 -0
- evalshift-0.3.0/src/evalshift/cli/commands/init.py +415 -0
- evalshift-0.3.0/src/evalshift/cli/commands/report.py +137 -0
- evalshift-0.3.0/src/evalshift/cli/commands/run.py +266 -0
- evalshift-0.3.0/src/evalshift/cli/commands/test_call.py +254 -0
- evalshift-0.3.0/src/evalshift/cli/commands/validate.py +128 -0
- evalshift-0.3.0/src/evalshift/cli/main.py +72 -0
- evalshift-0.3.0/src/evalshift/config/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/config/loader.py +217 -0
- evalshift-0.3.0/src/evalshift/config/models.py +338 -0
- evalshift-0.3.0/src/evalshift/evaluators/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/evaluators/base.py +93 -0
- evalshift-0.3.0/src/evalshift/evaluators/llm_judge.py +154 -0
- evalshift-0.3.0/src/evalshift/evaluators/semantic.py +93 -0
- evalshift-0.3.0/src/evalshift/evaluators/structural.py +131 -0
- evalshift-0.3.0/src/evalshift/evaluators/tool_arguments.py +216 -0
- evalshift-0.3.0/src/evalshift/evaluators/tool_loader.py +198 -0
- evalshift-0.3.0/src/evalshift/evaluators/tool_models.py +194 -0
- evalshift-0.3.0/src/evalshift/evaluators/tool_parser.py +328 -0
- evalshift-0.3.0/src/evalshift/evaluators/tool_selection.py +294 -0
- evalshift-0.3.0/src/evalshift/evaluators/tool_trace_structure.py +108 -0
- evalshift-0.3.0/src/evalshift/models/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/models/client.py +456 -0
- evalshift-0.3.0/src/evalshift/models/registry.py +272 -0
- evalshift-0.3.0/src/evalshift/models/replay_client.py +203 -0
- evalshift-0.3.0/src/evalshift/parsers/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/parsers/base.py +144 -0
- evalshift-0.3.0/src/evalshift/parsers/manual.py +45 -0
- evalshift-0.3.0/src/evalshift/parsers/python_string.py +204 -0
- evalshift-0.3.0/src/evalshift/py.typed +0 -0
- evalshift-0.3.0/src/evalshift/reports/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/reports/html.py +69 -0
- evalshift-0.3.0/src/evalshift/reports/json.py +523 -0
- evalshift-0.3.0/src/evalshift/reports/templates/report.css +203 -0
- evalshift-0.3.0/src/evalshift/reports/templates/report.html.j2 +268 -0
- evalshift-0.3.0/src/evalshift/runner/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/runner/checkpoint.py +280 -0
- evalshift-0.3.0/src/evalshift/runner/models.py +152 -0
- evalshift-0.3.0/src/evalshift/runner/orchestrator.py +703 -0
- evalshift-0.3.0/src/evalshift/suite/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/suite/loader.py +216 -0
- evalshift-0.3.0/src/evalshift/suite/models.py +156 -0
- evalshift-0.3.0/src/evalshift/utils/__init__.py +1 -0
- evalshift-0.3.0/src/evalshift/utils/cost.py +195 -0
- evalshift-0.3.0/src/evalshift/utils/templating.py +213 -0
- evalshift-0.3.0/tests/__init__.py +0 -0
- evalshift-0.3.0/tests/conftest.py +7 -0
- evalshift-0.3.0/tests/integration/__init__.py +0 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_missing_var/evalshift.yaml +6 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_missing_var/golden.jsonl +2 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_non_literal/evalshift.yaml +7 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_non_literal/golden.jsonl +1 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_non_literal/prompts.py +8 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_ok/evalshift.yaml +7 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_ok/golden.jsonl +2 -0
- evalshift-0.3.0/tests/integration/fixtures/validate_ok/prompts.py +3 -0
- evalshift-0.3.0/tests/integration/test_tool_pipeline.py +343 -0
- evalshift-0.3.0/tests/integration/test_validate_command.py +96 -0
- evalshift-0.3.0/tests/unit/__init__.py +0 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/anthropic/parallel_tool_calls.json +30 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/anthropic/refusal.json +19 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/anthropic/single_tool_call.json +24 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/anthropic/text_only.json +19 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/anthropic/tool_call_with_text.json +25 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/gemini/single_tool_call.json +26 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/gemini/text_only.json +16 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/openai/parallel_tool_calls.json +34 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/openai/refusal.json +17 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/openai/single_tool_call.json +26 -0
- evalshift-0.3.0/tests/unit/fixtures/tool_responses/openai/text_only.json +16 -0
- evalshift-0.3.0/tests/unit/test_all_command.py +271 -0
- evalshift-0.3.0/tests/unit/test_analysis.py +310 -0
- evalshift-0.3.0/tests/unit/test_analyze_command.py +222 -0
- evalshift-0.3.0/tests/unit/test_cache.py +225 -0
- evalshift-0.3.0/tests/unit/test_checkpoint.py +302 -0
- evalshift-0.3.0/tests/unit/test_cli_smoke.py +34 -0
- evalshift-0.3.0/tests/unit/test_config_loader.py +295 -0
- evalshift-0.3.0/tests/unit/test_config_models.py +312 -0
- evalshift-0.3.0/tests/unit/test_cost.py +199 -0
- evalshift-0.3.0/tests/unit/test_doctor.py +188 -0
- evalshift-0.3.0/tests/unit/test_evaluate_command.py +261 -0
- evalshift-0.3.0/tests/unit/test_evaluators.py +366 -0
- evalshift-0.3.0/tests/unit/test_init.py +267 -0
- evalshift-0.3.0/tests/unit/test_model_client.py +523 -0
- evalshift-0.3.0/tests/unit/test_model_registry.py +125 -0
- evalshift-0.3.0/tests/unit/test_orchestrator.py +462 -0
- evalshift-0.3.0/tests/unit/test_parsers.py +305 -0
- evalshift-0.3.0/tests/unit/test_reports.py +476 -0
- evalshift-0.3.0/tests/unit/test_run_command.py +301 -0
- evalshift-0.3.0/tests/unit/test_runner_models.py +197 -0
- evalshift-0.3.0/tests/unit/test_suite_loader.py +243 -0
- evalshift-0.3.0/tests/unit/test_suite_models.py +147 -0
- evalshift-0.3.0/tests/unit/test_templating.py +214 -0
- evalshift-0.3.0/tests/unit/test_test_call_command.py +295 -0
- evalshift-0.3.0/tests/unit/test_tool_arguments.py +216 -0
- evalshift-0.3.0/tests/unit/test_tool_loader.py +139 -0
- evalshift-0.3.0/tests/unit/test_tool_models.py +250 -0
- evalshift-0.3.0/tests/unit/test_tool_parser.py +403 -0
- evalshift-0.3.0/tests/unit/test_tool_selection.py +232 -0
- evalshift-0.3.0/tests/unit/test_tool_trace_structure.py +177 -0
- evalshift-0.3.0/tests/unit/test_version.py +12 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
.Python
|
|
9
|
+
build/
|
|
10
|
+
develop-eggs/
|
|
11
|
+
dist/
|
|
12
|
+
downloads/
|
|
13
|
+
eggs/
|
|
14
|
+
.eggs/
|
|
15
|
+
lib/
|
|
16
|
+
lib64/
|
|
17
|
+
parts/
|
|
18
|
+
sdist/
|
|
19
|
+
var/
|
|
20
|
+
wheels/
|
|
21
|
+
share/python-wheels/
|
|
22
|
+
*.egg-info/
|
|
23
|
+
.installed.cfg
|
|
24
|
+
*.egg
|
|
25
|
+
MANIFEST
|
|
26
|
+
|
|
27
|
+
# Virtual environments
|
|
28
|
+
.venv/
|
|
29
|
+
venv/
|
|
30
|
+
ENV/
|
|
31
|
+
env/
|
|
32
|
+
|
|
33
|
+
# Testing
|
|
34
|
+
.tox/
|
|
35
|
+
.nox/
|
|
36
|
+
.coverage
|
|
37
|
+
.coverage.*
|
|
38
|
+
.cache
|
|
39
|
+
htmlcov/
|
|
40
|
+
.pytest_cache/
|
|
41
|
+
.hypothesis/
|
|
42
|
+
coverage.xml
|
|
43
|
+
*.cover
|
|
44
|
+
|
|
45
|
+
# Type checking
|
|
46
|
+
.mypy_cache/
|
|
47
|
+
.dmypy.json
|
|
48
|
+
dmypy.json
|
|
49
|
+
.pyre/
|
|
50
|
+
.pytype/
|
|
51
|
+
|
|
52
|
+
# Linting
|
|
53
|
+
.ruff_cache/
|
|
54
|
+
|
|
55
|
+
# IDE
|
|
56
|
+
.vscode/
|
|
57
|
+
.idea/
|
|
58
|
+
*.swp
|
|
59
|
+
*.swo
|
|
60
|
+
*~
|
|
61
|
+
.DS_Store
|
|
62
|
+
|
|
63
|
+
# EvalShift runtime
|
|
64
|
+
.evalshift/
|
|
65
|
+
*.db
|
|
66
|
+
*.sqlite
|
|
67
|
+
*.sqlite3
|
|
68
|
+
|
|
69
|
+
# Docs build
|
|
70
|
+
site/
|
|
71
|
+
|
|
72
|
+
# uv
|
|
73
|
+
uv.lock
|
|
74
|
+
|
|
75
|
+
# Build plan source (kept locally, not in git)
|
|
76
|
+
evalshift-cli-mvp-build-plan.md.pdf
|
|
77
|
+
.claude/agents/brainstormer.md
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.0] — 2026-05-12
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `evalshift all` runs the full `doctor → run → evaluate → analyze →
|
|
15
|
+
report` pipeline in one command, with a single Rich Live region:
|
|
16
|
+
stacked status rows, an inline block-bar for the run stage, and a
|
|
17
|
+
final verdict block (`✓ candidate is significantly better` /
|
|
18
|
+
`✗ candidate regressed` / `~ no significant change`) plus a minor-
|
|
19
|
+
regression callout. Forwards every flag the underlying commands
|
|
20
|
+
accept (`--from/--to`, `--config`, `--suite`, `--offline`,
|
|
21
|
+
`--fixtures`, `--yes`, `--resume`, `--gate`, `--open`).
|
|
22
|
+
- `evaluate`, `analyze`, and `report` now expose reusable cores
|
|
23
|
+
(`run_evaluate`, `run_analyze`, `run_report`) returning typed
|
|
24
|
+
result dataclasses; the existing Typer commands are thin wrappers.
|
|
25
|
+
- Orchestrator gained an optional `on_progress` callback
|
|
26
|
+
(`ProgressEvent`) so a caller can drive its own progress UI in
|
|
27
|
+
place of the built-in Rich `Progress`. `preflight_cost(...)`
|
|
28
|
+
exposes the cost estimate without dispatching any work.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- `evalshift all`: the cost preflight row is now labelled
|
|
33
|
+
`max cost ........... ≤ $X.XX` instead of `estimated cost ... $X.XX`.
|
|
34
|
+
The underlying figure is unchanged — it has always been a
|
|
35
|
+
worst-case ceiling (priced as if every call emits the model's full
|
|
36
|
+
`default_max_tokens`) — but the new wording makes that explicit so
|
|
37
|
+
users don't read it as a forecast. The interactive cost-confirmation
|
|
38
|
+
prompt also now reads "at most $X" instead of "estimated cost $X".
|
|
39
|
+
- `evalshift init` now always scaffolds an agent project. The brief
|
|
40
|
+
`--agent` flag introduced in the previous unreleased entry has been
|
|
41
|
+
removed — there's only one starter, and it's the v0.2 agent flow.
|
|
42
|
+
Existing v0.1-style projects are unaffected (no breaking change to
|
|
43
|
+
the config schema or runner).
|
|
44
|
+
- Agent scaffold ships 6 customer-support tools (`search_orders`,
|
|
45
|
+
`lookup_customer`, `issue_refund`, `update_order_status`,
|
|
46
|
+
`send_email`, `notify_security_team`) and 40 suite rows across 5
|
|
47
|
+
slices (security, routine, refund, customer_lookup, text_only) so
|
|
48
|
+
the analysis layer produces real severity badges on a first run
|
|
49
|
+
instead of "insufficient" / zero-variance warnings.
|
|
50
|
+
- Dropped `structural.length` from the scaffolded `evalshift.yaml`.
|
|
51
|
+
Agent runs frequently produce empty `final_text` (model returned
|
|
52
|
+
only tool calls) which made length scores 0/0 across every routine
|
|
53
|
+
+ security row — pure noise. Users who want length checks can
|
|
54
|
+
add the block back manually for prompts that produce text.
|
|
55
|
+
|
|
56
|
+
## [0.2.0] — Tool-call evaluation
|
|
57
|
+
|
|
58
|
+
Adds agent-migration support: detects regressions in *which* tools the
|
|
59
|
+
new model calls, *what* arguments it passes, and *how* it sequences
|
|
60
|
+
them. v0.1 backward compatible — every existing example keeps working
|
|
61
|
+
without changes.
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
|
|
65
|
+
- `evalshift.evaluators.tool_models`: provider-agnostic `ToolSpec`,
|
|
66
|
+
`ToolCall`, `ToolTrace`. `ToolSpec.to_anthropic` / `to_openai` /
|
|
67
|
+
`from_dict` adapters keep wire-format details out of user code.
|
|
68
|
+
- `evalshift.evaluators.tool_parser`: `parse_response_to_trace`
|
|
69
|
+
dispatcher with three provider parsers. Handles the LiteLLM
|
|
70
|
+
Anthropic-normalised-to-OpenAI shape transparently. Malformed
|
|
71
|
+
argument JSON marked `_parse_error` instead of crashing.
|
|
72
|
+
- `evalshift.evaluators.tool_loader`: `load_tools(yaml or json)` with
|
|
73
|
+
the same plain/rich error rendering pattern as `ConfigError`.
|
|
74
|
+
- `evalshift.models.client.complete_with_tools` and
|
|
75
|
+
`ToolCompletionResult` — tool-aware call path that doesn't replace
|
|
76
|
+
the existing `complete` / `CompletionResult`.
|
|
77
|
+
- `evalshift test-call --tools <path>` smoke command extension.
|
|
78
|
+
- `scripts/smoke_live_tools.py` for fixture capture (manual; not in CI).
|
|
79
|
+
- Three new evaluators wired into `evalshift evaluate`:
|
|
80
|
+
- `ToolSelectionEvaluator` (modes: exact / set / first / expected)
|
|
81
|
+
- `ToolArgumentsEvaluator` (per-field strategies: exact / subset /
|
|
82
|
+
numeric / semantic; greedy nearest-index call matching)
|
|
83
|
+
- `ToolTraceStructureEvaluator` (call_count / parallelism /
|
|
84
|
+
refusal_alignment / expected_count_alignment; refusal mismatches
|
|
85
|
+
force severity_floor: high)
|
|
86
|
+
- Suite extension: optional `expected_tools` (with per-call
|
|
87
|
+
`match_strategy`), `expected_tool_count`, `expected_no_tools`,
|
|
88
|
+
`expected_parallel`. Mutual-exclusion checks where appropriate.
|
|
89
|
+
- Config extension: `prompts[].tools_path` makes a prompt agent-style;
|
|
90
|
+
`evaluators.{tool_selection, tool_arguments, tool_trace_structure}`
|
|
91
|
+
blocks added.
|
|
92
|
+
- Orchestrator dispatch: agent prompts route through
|
|
93
|
+
`complete_with_tools`; the resulting `Call.trace` round-trips via
|
|
94
|
+
pydantic so `raw.jsonl` Just Works.
|
|
95
|
+
- HTML report extension: per-prompt "Top regressions" section now
|
|
96
|
+
renders side-by-side trace diffs for tool-evaluator regressions
|
|
97
|
+
with green / yellow / red colour coding for matching / different-
|
|
98
|
+
args / missing-extra calls. CSS stays inlined.
|
|
99
|
+
- `evalshift doctor` warns about common agent-config mistakes:
|
|
100
|
+
prompts with `tools_path` but no tool evaluators, and suite
|
|
101
|
+
examples with `expected_tools` but no agent prompts.
|
|
102
|
+
- Docs: `docs/agents.md` walkthrough, plus configuration / evaluators
|
|
103
|
+
/ faq updates.
|
|
104
|
+
- `examples/agent/` runnable customer-routing example with 12 golden
|
|
105
|
+
rows across security / routine / text-only slices.
|
|
106
|
+
|
|
107
|
+
### Quality
|
|
108
|
+
|
|
109
|
+
- 512+ tests, including end-to-end integration tests covering the
|
|
110
|
+
PRD §9.3 failure-mode grid. ruff + format + mypy --strict clean.
|
|
111
|
+
- v0.1 backward compatibility verified: existing 462 tests still
|
|
112
|
+
green; `examples/simple/` unchanged.
|
|
113
|
+
|
|
114
|
+
## [0.1.0]
|
|
115
|
+
|
|
116
|
+
First alpha release. Every command in the planned MVP pipeline is shipped.
|
|
117
|
+
|
|
118
|
+
### Live commands
|
|
119
|
+
|
|
120
|
+
| Command | What it does |
|
|
121
|
+
| ---------------------- | ----------------------------------------------------------------------- |
|
|
122
|
+
| `evalshift doctor` | Check Python version, provider API keys, and `evalshift.yaml` validity. |
|
|
123
|
+
| `evalshift init` | Scaffold a starter project (yaml + prompts.py + golden.jsonl). |
|
|
124
|
+
| `evalshift run` | Call source + target models on every (prompt, example) → `raw.jsonl`. |
|
|
125
|
+
| `evalshift evaluate` | Score every (source, target) pair → `scores.jsonl`. |
|
|
126
|
+
| `evalshift analyze` | Paired tests + BH correction → `analysis.json`. |
|
|
127
|
+
| `evalshift report` | Single-file HTML report → `report.html` + `report.json`. |
|
|
128
|
+
| `evalshift cache clear`| Wipe the local SQLite response cache. |
|
|
129
|
+
| `evalshift validate` | (hidden dev) Verify config + suite + prompts are compatible. |
|
|
130
|
+
| `evalshift test-call` | (hidden dev) One-shot smoke call to confirm provider connectivity. |
|
|
131
|
+
|
|
132
|
+
### Added — Phase 0–1
|
|
133
|
+
|
|
134
|
+
- `pyproject.toml` (Python ≥3.14, hatchling, MIT, pinned deps), `ruff.toml`, `mypy.ini`, pytest config, `.pre-commit-config.yaml`, GitHub Actions CI.
|
|
135
|
+
- Full `src/evalshift` package skeleton across cli/config/parsers/models/suite/runner/evaluators/analysis/reports/cache/utils with module docstrings and a `py.typed` marker.
|
|
136
|
+
- `evalshift.config.models`: pydantic v2 schema for `evalshift.yaml` (prompts, evaluators, slices, defaults) with strict validation, `extra='forbid'`, and detection-mode field invariants.
|
|
137
|
+
- `evalshift.config.loader`: `load_config()` plus a structured `ConfigError` with both plain-text and Rich panel rendering.
|
|
138
|
+
- `evalshift doctor`: reports Python version, provider API keys, and `evalshift.yaml` validity. Exits 1 only on hard failures.
|
|
139
|
+
- `evalshift init`: scaffolds `evalshift.yaml` + `prompts.py` + `golden.jsonl`. `--force` overwrite, `--directory` target dir.
|
|
140
|
+
|
|
141
|
+
### Added — Phase 2 (suite + prompt loading)
|
|
142
|
+
|
|
143
|
+
- `evalshift.suite` package: pydantic `SuiteExample` + `Suite` models, JSONL loader with line-numbered errors, blank-line tolerance, multi-error collection.
|
|
144
|
+
- `evalshift.parsers` package: `ManualParser` (inline content) and `PythonStringParser` (AST-walks `.py` for module-level string literals; rejects f-strings, concatenation, function calls, attribute access, name references — never runs user code).
|
|
145
|
+
- `evalshift.utils.templating`: `extract_variables`, `render` with strict missing-var detection, and a bulk `validate_suite_against_prompts` pre-flight check.
|
|
146
|
+
- `evalshift validate` (hidden): end-to-end pre-flight that confirms config + suite + prompts are mutually compatible.
|
|
147
|
+
|
|
148
|
+
### Added — Phase 3 (model client + cache)
|
|
149
|
+
|
|
150
|
+
- `evalshift.models.registry`: advisory, not gating. `resolve_model()` accepts any model id, falling back to prefix-inferred provider when not in the curated registry. `get_model()` strict variant kept for tests.
|
|
151
|
+
- `evalshift.cache`: SQLAlchemy 2.0 + async `CacheStore` (sha256 keys, 7-day TTL) at `~/.evalshift/cache.db`. Added `greenlet` runtime dep.
|
|
152
|
+
- `evalshift cache clear` CLI command (under a `cache` sub-app).
|
|
153
|
+
- `evalshift.models.client`: async `ModelClient` wrapping `litellm.acompletion` with uniform error mapping (`RateLimitError` / `AuthError` / `ModelError`), full-jitter exponential backoff retries (auth short-circuits), and per-call cost + token bookkeeping.
|
|
154
|
+
- `evalshift.utils.cost`: `estimate_run_cost(...)` for pre-flight cost estimation with defensive fallbacks for missing LiteLLM pricing/token-counter data.
|
|
155
|
+
- `evalshift test-call` (hidden): one-shot smoke test renderer with response/tokens/cost/latency Rich panel.
|
|
156
|
+
|
|
157
|
+
### Added — Phase 4 (run orchestrator)
|
|
158
|
+
|
|
159
|
+
- `evalshift.runner` package: pydantic `RunState` + `Call` models, atomic `state.json` checkpointing, append-only `raw.jsonl`, crash-safe iterator, `validate_resume` with hash-drift detection.
|
|
160
|
+
- `run_orchestrator`: async loop with `asyncio.Semaphore(concurrency)`, cache-check → live-call → record per (prompt, example, role), Rich progress bar, $10 cost gate (skip with `--yes`), 50-call checkpoint cadence.
|
|
161
|
+
- `evalshift run` command: `--from`, `--to`, `--config`, `--suite`, `--resume`, `--yes`. Outputs go to `.evalshift/runs/<run-id>/`. Per-call errors are recorded but don't fail the run.
|
|
162
|
+
|
|
163
|
+
### Added — Phase 5 (evaluators)
|
|
164
|
+
|
|
165
|
+
- `evalshift.evaluators` package: `Evaluator` Protocol, `PairedScore`, `EvalRecord`.
|
|
166
|
+
- Structural: `JsonSchemaEvaluator`, `RegexEvaluator`, `LengthEvaluator` (1.0 inside bounds, distance-decayed outside).
|
|
167
|
+
- Semantic: `CosineSimilarityEvaluator` (target preservation framing — source = 1.0, target = cosine to source).
|
|
168
|
+
- LLM judge: `PairwiseJudgeEvaluator` with order-randomization and defensive JSON parsing.
|
|
169
|
+
- `evalshift evaluate <run-id>` command: pairs source/target calls, runs every configured evaluator, writes `scores.jsonl`.
|
|
170
|
+
|
|
171
|
+
### Added — Phase 6 (statistics)
|
|
172
|
+
|
|
173
|
+
- `evalshift.analysis.slicing`: `build_slices` groups records by tag (with implicit `"all"` slice); `aggregates()` computes per-slice n/mean/std.
|
|
174
|
+
- `evalshift.analysis.statistics`: per-comparison Shapiro-Wilk → paired t-test or Wilcoxon signed-rank, Cohen's d, 95% CI (analytical for t-test, bootstrap for Wilcoxon), Benjamini-Hochberg correction across the whole run, severity classification (critical/high/medium/low/improved/none/insufficient).
|
|
175
|
+
- `evalshift analyze <run-id>` command: writes `analysis.json` and prints a Rich summary table.
|
|
176
|
+
|
|
177
|
+
### Added — Phase 7 (report)
|
|
178
|
+
|
|
179
|
+
- `evalshift.reports.json`: `build_report_payload` + `ReportData` stitching state + raw + scores + analysis into a single payload. Persists `report.json`.
|
|
180
|
+
- `evalshift.reports.templates/report.html.j2` + `report.css`: self-contained HTML (CSS inlined, zero external assets, no JS) with executive summary, per-prompt aggregate + slice tables, top-5 regressions side-by-side, methodology appendix.
|
|
181
|
+
- `evalshift report <run-id>` command, with optional `--open` to launch in the user's default browser.
|
|
182
|
+
|
|
183
|
+
### Added — Phase 8 (polish + OSS)
|
|
184
|
+
|
|
185
|
+
- Documentation site (MkDocs Material) covering Getting Started, Configuration, Evaluators, Methodology, FAQ.
|
|
186
|
+
- `examples/simple/` runnable example.
|
|
187
|
+
- `CODE_OF_CONDUCT.md` (Contributor Covenant 2.1), `SECURITY.md`, GitHub issue + PR templates.
|
|
188
|
+
- README polished with badges, status, full pipeline walkthrough, non-goals.
|
|
189
|
+
|
|
190
|
+
### Quality
|
|
191
|
+
|
|
192
|
+
- 371+ tests, ≥95% line coverage, `mypy --strict` clean, `ruff check` clean, `ruff format` clean.
|
|
193
|
+
- Mocked CI throughout (no API keys needed); `scripts/smoke_live.py` deferred for the user's manual live verification.
|
evalshift-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lukas Babaliauskas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
evalshift-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: evalshift
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Run your prompts on two LLMs and find out, with statistical confidence, what regressed.
|
|
5
|
+
Project-URL: Homepage, https://github.com/babaliauskas/EvalShift
|
|
6
|
+
Project-URL: Documentation, https://github.com/babaliauskas/EvalShift#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/babaliauskas/EvalShift
|
|
8
|
+
Project-URL: Issues, https://github.com/babaliauskas/EvalShift/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/babaliauskas/EvalShift/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Lukas Babaliauskas
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: anthropic,evaluation,gemini,llm,migration,openai,regression-testing
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Classifier: Topic :: Software Development :: Testing
|
|
24
|
+
Requires-Python: >=3.14
|
|
25
|
+
Requires-Dist: aiosqlite>=0.19
|
|
26
|
+
Requires-Dist: greenlet>=3.0
|
|
27
|
+
Requires-Dist: httpx>=0.27
|
|
28
|
+
Requires-Dist: jinja2>=3.1
|
|
29
|
+
Requires-Dist: jsonschema>=4.22
|
|
30
|
+
Requires-Dist: litellm>=1.40
|
|
31
|
+
Requires-Dist: numpy>=1.26
|
|
32
|
+
Requires-Dist: pydantic>=2.5
|
|
33
|
+
Requires-Dist: pygments>=2.18
|
|
34
|
+
Requires-Dist: pyyaml>=6.0
|
|
35
|
+
Requires-Dist: rich>=13.7
|
|
36
|
+
Requires-Dist: scipy>=1.12
|
|
37
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
38
|
+
Requires-Dist: tiktoken>=0.7
|
|
39
|
+
Requires-Dist: typer>=0.12
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'dev'
|
|
42
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
43
|
+
Requires-Dist: pre-commit>=3.7; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
48
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
49
|
+
Requires-Dist: types-jsonschema>=4.22; extra == 'dev'
|
|
50
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
# EvalShift
|
|
54
|
+
|
|
55
|
+
> Run your prompts on two LLMs and find out, with statistical confidence, what regressed.
|
|
56
|
+
|
|
57
|
+
[](https://github.com/babaliauskas/EvalShift/actions/workflows/ci.yml)
|
|
58
|
+
[](LICENSE)
|
|
59
|
+
[](https://www.python.org/downloads/)
|
|
60
|
+
[](#status)
|
|
61
|
+
|
|
62
|
+
EvalShift is a local-first CLI that helps engineering teams migrate safely between
|
|
63
|
+
LLM versions (e.g. `claude-4.5-sonnet` → `claude-5-sonnet`). Point it at your
|
|
64
|
+
prompts and a golden suite of inputs; it runs both models, scores the outputs
|
|
65
|
+
with structural / semantic / LLM-as-judge evaluators, and produces a single-file
|
|
66
|
+
HTML report with **defensible statistics**: paired tests, Cohen's d, 95% CIs,
|
|
67
|
+
and Benjamini–Hochberg correction across every (prompt × evaluator × slice)
|
|
68
|
+
comparison.
|
|
69
|
+
|
|
70
|
+
## Status
|
|
71
|
+
|
|
72
|
+
**Alpha.** Every command in the pipeline is shipped and the test suite is at
|
|
73
|
+
95%+ coverage. APIs may still change as feedback comes in.
|
|
74
|
+
|
|
75
|
+
## Install
|
|
76
|
+
|
|
77
|
+
Requires Python 3.14+.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Recommended
|
|
81
|
+
uv pip install evalshift # or: pip install evalshift
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
From source (for contributors):
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
git clone https://github.com/babaliauskas/EvalShift.git
|
|
88
|
+
cd EvalShift
|
|
89
|
+
uv venv --python 3.14
|
|
90
|
+
source .venv/bin/activate
|
|
91
|
+
uv pip install -e ".[dev]"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Quick start
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 1. Scaffold a starter project. Writes evalshift.yaml + prompts.py +
|
|
98
|
+
# tools.yaml + a 40-row golden.jsonl for a customer-support agent.
|
|
99
|
+
mkdir my-eval && cd my-eval
|
|
100
|
+
evalshift init
|
|
101
|
+
|
|
102
|
+
# 2. Set whichever provider keys you'll use
|
|
103
|
+
export GOOGLE_API_KEY=... # or ANTHROPIC_API_KEY / OPENAI_API_KEY
|
|
104
|
+
|
|
105
|
+
# 3. Run the whole pipeline in one command (doctor → run → evaluate
|
|
106
|
+
# → analyze → report). Pass --open to launch the report.
|
|
107
|
+
evalshift all --yes --open
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`evalshift all` drives the full five-stage pipeline under a single
|
|
111
|
+
Rich Live region — stacked status rows, an inline progress bar for
|
|
112
|
+
the run stage, and a final verdict block that tells you whether the
|
|
113
|
+
candidate is significantly better, regressed, or showed no
|
|
114
|
+
significant change.
|
|
115
|
+
|
|
116
|
+
If you want to drive each stage by hand (useful in CI, or when
|
|
117
|
+
re-running just one stage after fixing config):
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
evalshift doctor
|
|
121
|
+
evalshift run --yes
|
|
122
|
+
evalshift evaluate <run-id>
|
|
123
|
+
evalshift analyze <run-id>
|
|
124
|
+
evalshift report <run-id> --open
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Every artefact lives under `.evalshift/runs/<run-id>/` — `state.json`,
|
|
128
|
+
`raw.jsonl`, `scores.jsonl`, `analysis.json`, `report.json`,
|
|
129
|
+
`report.html`. None of it leaves your machine.
|
|
130
|
+
|
|
131
|
+
## Agent migrations (v0.2)
|
|
132
|
+
|
|
133
|
+
Migrating an agent (a prompt that uses tools)? EvalShift v0.2 detects
|
|
134
|
+
regressions in *which* tools the new model calls, *what* arguments it
|
|
135
|
+
passes, and *how* it sequences them. The killer scenario: a routing
|
|
136
|
+
agent that silently stops calling `notify_security_team` after the
|
|
137
|
+
migration — text-only eval reports green, v0.2 marks it CRITICAL.
|
|
138
|
+
|
|
139
|
+
The default `evalshift init` scaffold *is* an agent project — six tools
|
|
140
|
+
plus a 40-row golden suite. Just run the quick-start above and the
|
|
141
|
+
tool-call evaluators kick in automatically.
|
|
142
|
+
|
|
143
|
+
See [`docs/agents.md`](docs/agents.md) for the full walkthrough and
|
|
144
|
+
the [`examples/agent/`](examples/agent/) directory for a runnable
|
|
145
|
+
customer-support example.
|
|
146
|
+
|
|
147
|
+
## What the report looks like
|
|
148
|
+
|
|
149
|
+
The HTML report (single file, no external assets, works offline) has:
|
|
150
|
+
|
|
151
|
+
* **Executive summary** — one row per prompt with a severity badge.
|
|
152
|
+
* **Per-prompt deep dive** — aggregate stats, per-slice breakdown,
|
|
153
|
+
top-5 worst regressions side-by-side.
|
|
154
|
+
* **Methodology appendix** — every test, p-value, effect size, and
|
|
155
|
+
CI is documented.
|
|
156
|
+
|
|
157
|
+
## Why local-first?
|
|
158
|
+
|
|
159
|
+
Your prompts and your suite never leave your machine. The only outbound calls
|
|
160
|
+
are to the LLM providers you configure (Anthropic, OpenAI, Google) using your
|
|
161
|
+
own API keys. There is no EvalShift cloud.
|
|
162
|
+
|
|
163
|
+
## Documentation
|
|
164
|
+
|
|
165
|
+
* [Getting started](docs/getting-started.md) — install + first run walkthrough
|
|
166
|
+
* [Configuration reference](docs/configuration.md) — every `evalshift.yaml` field
|
|
167
|
+
* [Evaluators](docs/evaluators.md) — when to use which family
|
|
168
|
+
* [Methodology](docs/methodology.md) — the statistical machinery
|
|
169
|
+
* [FAQ](docs/faq.md) — common questions
|
|
170
|
+
* [`MVP_TODO.md`](MVP_TODO.md) — the build checklist (every box ticked)
|
|
171
|
+
|
|
172
|
+
## Non-goals (for v0.1)
|
|
173
|
+
|
|
174
|
+
* Hosted backend / web UI
|
|
175
|
+
* Multi-criterion judge in a single call
|
|
176
|
+
* Custom evaluator plugin system
|
|
177
|
+
* Comparing more than 2 models in one run
|
|
178
|
+
* Auto-detection of LangChain / LlamaIndex prompt patterns
|
|
179
|
+
|
|
180
|
+
These are deferred to v0.2+; see the PDF spec in the repo for the
|
|
181
|
+
full deferred-features list.
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
[MIT](LICENSE) — free for any use.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# EvalShift
|
|
2
|
+
|
|
3
|
+
> Run your prompts on two LLMs and find out, with statistical confidence, what regressed.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/babaliauskas/EvalShift/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://www.python.org/downloads/)
|
|
8
|
+
[](#status)
|
|
9
|
+
|
|
10
|
+
EvalShift is a local-first CLI that helps engineering teams migrate safely between
|
|
11
|
+
LLM versions (e.g. `claude-4.5-sonnet` → `claude-5-sonnet`). Point it at your
|
|
12
|
+
prompts and a golden suite of inputs; it runs both models, scores the outputs
|
|
13
|
+
with structural / semantic / LLM-as-judge evaluators, and produces a single-file
|
|
14
|
+
HTML report with **defensible statistics**: paired tests, Cohen's d, 95% CIs,
|
|
15
|
+
and Benjamini–Hochberg correction across every (prompt × evaluator × slice)
|
|
16
|
+
comparison.
|
|
17
|
+
|
|
18
|
+
## Status
|
|
19
|
+
|
|
20
|
+
**Alpha.** Every command in the pipeline is shipped and the test suite is at
|
|
21
|
+
95%+ coverage. APIs may still change as feedback comes in.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Requires Python 3.14+.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Recommended
|
|
29
|
+
uv pip install evalshift # or: pip install evalshift
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
From source (for contributors):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/babaliauskas/EvalShift.git
|
|
36
|
+
cd EvalShift
|
|
37
|
+
uv venv --python 3.14
|
|
38
|
+
source .venv/bin/activate
|
|
39
|
+
uv pip install -e ".[dev]"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# 1. Scaffold a starter project. Writes evalshift.yaml + prompts.py +
|
|
46
|
+
# tools.yaml + a 40-row golden.jsonl for a customer-support agent.
|
|
47
|
+
mkdir my-eval && cd my-eval
|
|
48
|
+
evalshift init
|
|
49
|
+
|
|
50
|
+
# 2. Set whichever provider keys you'll use
|
|
51
|
+
export GOOGLE_API_KEY=... # or ANTHROPIC_API_KEY / OPENAI_API_KEY
|
|
52
|
+
|
|
53
|
+
# 3. Run the whole pipeline in one command (doctor → run → evaluate
|
|
54
|
+
# → analyze → report). Pass --open to launch the report.
|
|
55
|
+
evalshift all --yes --open
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`evalshift all` drives the full five-stage pipeline under a single
|
|
59
|
+
Rich Live region — stacked status rows, an inline progress bar for
|
|
60
|
+
the run stage, and a final verdict block that tells you whether the
|
|
61
|
+
candidate is significantly better, regressed, or showed no
|
|
62
|
+
significant change.
|
|
63
|
+
|
|
64
|
+
If you want to drive each stage by hand (useful in CI, or when
|
|
65
|
+
re-running just one stage after fixing config):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
evalshift doctor
|
|
69
|
+
evalshift run --yes
|
|
70
|
+
evalshift evaluate <run-id>
|
|
71
|
+
evalshift analyze <run-id>
|
|
72
|
+
evalshift report <run-id> --open
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Every artefact lives under `.evalshift/runs/<run-id>/` — `state.json`,
|
|
76
|
+
`raw.jsonl`, `scores.jsonl`, `analysis.json`, `report.json`,
|
|
77
|
+
`report.html`. None of it leaves your machine.
|
|
78
|
+
|
|
79
|
+
## Agent migrations (v0.2)
|
|
80
|
+
|
|
81
|
+
Migrating an agent (a prompt that uses tools)? EvalShift v0.2 detects
|
|
82
|
+
regressions in *which* tools the new model calls, *what* arguments it
|
|
83
|
+
passes, and *how* it sequences them. The killer scenario: a routing
|
|
84
|
+
agent that silently stops calling `notify_security_team` after the
|
|
85
|
+
migration — text-only eval reports green, v0.2 marks it CRITICAL.
|
|
86
|
+
|
|
87
|
+
The default `evalshift init` scaffold *is* an agent project — six tools
|
|
88
|
+
plus a 40-row golden suite. Just run the quick-start above and the
|
|
89
|
+
tool-call evaluators kick in automatically.
|
|
90
|
+
|
|
91
|
+
See [`docs/agents.md`](docs/agents.md) for the full walkthrough and
|
|
92
|
+
the [`examples/agent/`](examples/agent/) directory for a runnable
|
|
93
|
+
customer-support example.
|
|
94
|
+
|
|
95
|
+
## What the report looks like
|
|
96
|
+
|
|
97
|
+
The HTML report (single file, no external assets, works offline) has:
|
|
98
|
+
|
|
99
|
+
* **Executive summary** — one row per prompt with a severity badge.
|
|
100
|
+
* **Per-prompt deep dive** — aggregate stats, per-slice breakdown,
|
|
101
|
+
top-5 worst regressions side-by-side.
|
|
102
|
+
* **Methodology appendix** — every test, p-value, effect size, and
|
|
103
|
+
CI is documented.
|
|
104
|
+
|
|
105
|
+
## Why local-first?
|
|
106
|
+
|
|
107
|
+
Your prompts and your suite never leave your machine. The only outbound calls
|
|
108
|
+
are to the LLM providers you configure (Anthropic, OpenAI, Google) using your
|
|
109
|
+
own API keys. There is no EvalShift cloud.
|
|
110
|
+
|
|
111
|
+
## Documentation
|
|
112
|
+
|
|
113
|
+
* [Getting started](docs/getting-started.md) — install + first run walkthrough
|
|
114
|
+
* [Configuration reference](docs/configuration.md) — every `evalshift.yaml` field
|
|
115
|
+
* [Evaluators](docs/evaluators.md) — when to use which family
|
|
116
|
+
* [Methodology](docs/methodology.md) — the statistical machinery
|
|
117
|
+
* [FAQ](docs/faq.md) — common questions
|
|
118
|
+
* [`MVP_TODO.md`](MVP_TODO.md) — the build checklist (every box ticked)
|
|
119
|
+
|
|
120
|
+
## Non-goals (for v0.1)
|
|
121
|
+
|
|
122
|
+
* Hosted backend / web UI
|
|
123
|
+
* Multi-criterion judge in a single call
|
|
124
|
+
* Custom evaluator plugin system
|
|
125
|
+
* Comparing more than 2 models in one run
|
|
126
|
+
* Auto-detection of LangChain / LlamaIndex prompt patterns
|
|
127
|
+
|
|
128
|
+
These are deferred to v0.2+; see the PDF spec in the repo for the
|
|
129
|
+
full deferred-features list.
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
[MIT](LICENSE) — free for any use.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Agent example (v0.2)
|
|
2
|
+
|
|
3
|
+
A small customer-routing agent that EvalShift's v0.2 tool-call evaluators
|
|
4
|
+
exercise end to end.
|
|
5
|
+
|
|
6
|
+
## What's here
|
|
7
|
+
|
|
8
|
+
| File | Purpose |
|
|
9
|
+
| ----------------- | ---------------------------------------------------------------------- |
|
|
10
|
+
| `evalshift.yaml` | Run config with a single agent prompt + the `tool_selection` evaluator.|
|
|
11
|
+
| `prompts.py` | The agent's system prompt, referenced via `python_string`. |
|
|
12
|
+
| `tools.yaml` | Three tools: `search_orders`, `notify_security_team`, `send_email`. |
|
|
13
|
+
| `golden.jsonl` | 12 examples mixing security, routine, and text-only cases. |
|
|
14
|
+
|
|
15
|
+
## Run it
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd examples/agent
|
|
19
|
+
export GOOGLE_API_KEY=... # or any provider you set up
|
|
20
|
+
evalshift run --yes --from gemini-2.5-flash --to gemini-2.5-pro
|
|
21
|
+
RUN_ID=$(ls .evalshift/runs/ | head -1)
|
|
22
|
+
evalshift evaluate $RUN_ID
|
|
23
|
+
evalshift analyze $RUN_ID
|
|
24
|
+
evalshift report $RUN_ID --open
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`evalshift run` notices `tools_path` on the prompt and dispatches via
|
|
28
|
+
`ModelClient.complete_with_tools` — each `Call` row in `raw.jsonl` carries
|
|
29
|
+
a parsed `ToolTrace`. `evalshift evaluate` then runs `tool_selection`
|
|
30
|
+
against the per-example `expected_tools` ground truth.
|
|
31
|
+
|
|
32
|
+
## What the example demonstrates
|
|
33
|
+
|
|
34
|
+
* **Tool-call regression detection.** If you set `target_model` to a
|
|
35
|
+
weaker model, the report will flag examples where the target stops
|
|
36
|
+
calling `notify_security_team` on security-flagged inputs.
|
|
37
|
+
* **Slice analysis.** The `security` and `routine` slices report
|
|
38
|
+
per-segment regressions, so a model that's fine on routine traffic
|
|
39
|
+
but worse on security can't hide.
|
|
40
|
+
* **Text-only fallback.** The `text_only` examples check that the
|
|
41
|
+
model knows when *not* to call a tool — also a real regression mode.
|