evalt 0.8.5__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.
- evalt-0.8.5/LICENSE +21 -0
- evalt-0.8.5/PKG-INFO +264 -0
- evalt-0.8.5/README.md +237 -0
- evalt-0.8.5/pyproject.toml +48 -0
- evalt-0.8.5/setup.cfg +4 -0
- evalt-0.8.5/src/evalt/__init__.py +39 -0
- evalt-0.8.5/src/evalt/__main__.py +5 -0
- evalt-0.8.5/src/evalt/cli.py +228 -0
- evalt-0.8.5/src/evalt/core.py +431 -0
- evalt-0.8.5/src/evalt/py.typed +1 -0
- evalt-0.8.5/src/evalt/router.py +636 -0
- evalt-0.8.5/src/evalt.egg-info/PKG-INFO +264 -0
- evalt-0.8.5/src/evalt.egg-info/SOURCES.txt +22 -0
- evalt-0.8.5/src/evalt.egg-info/dependency_links.txt +1 -0
- evalt-0.8.5/src/evalt.egg-info/entry_points.txt +4 -0
- evalt-0.8.5/src/evalt.egg-info/top_level.txt +3 -0
- evalt-0.8.5/src/last_good_prompt/__init__.py +25 -0
- evalt-0.8.5/src/last_good_prompt/__main__.py +4 -0
- evalt-0.8.5/src/last_good_prompt/cli.py +80 -0
- evalt-0.8.5/src/last_good_prompt/core.py +1429 -0
- evalt-0.8.5/src/modelsieve/__init__.py +25 -0
- evalt-0.8.5/src/modelsieve/cli.py +75 -0
- evalt-0.8.5/src/modelsieve/core.py +4 -0
- evalt-0.8.5/tests/test_sdk.py +880 -0
evalt-0.8.5/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonathan Larson
|
|
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.
|
evalt-0.8.5/PKG-INFO
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: evalt
|
|
3
|
+
Version: 0.8.5
|
|
4
|
+
Summary: A durable LLM router that finds the most accurate configuration at your price.
|
|
5
|
+
Author: Jonathan Larson
|
|
6
|
+
Maintainer: Jonathan Larson
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://evalt.dev
|
|
9
|
+
Project-URL: Documentation, https://evalt.dev/#sdk
|
|
10
|
+
Project-URL: Changelog, https://evalt.dev/#sdk
|
|
11
|
+
Keywords: llm,prompt-engineering,evaluation,model-routing,ci
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# Evalt Python SDK
|
|
29
|
+
|
|
30
|
+
Evalt is a durable runtime router. Your application gives it a prompt, an input, and a
|
|
31
|
+
stable route name. Evalt finds the lowest-cost prompt/model/reasoning configuration that
|
|
32
|
+
clears the approved validation target (95% by default), records the decision in SQLite,
|
|
33
|
+
and uses a separate capped test budget when traffic, a new model, or a provider-price
|
|
34
|
+
change makes retesting worthwhile.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
After the public package is released:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python -m pip install evalt
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Until that account-bound publication is complete, install the verified versioned wheel
|
|
45
|
+
from this repository checkout:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python -m venv .venv
|
|
49
|
+
python -m pip install dist/evalt-0.8.5-py3-none-any.whl
|
|
50
|
+
evalt --version
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`evalt` is the primary import and command. `modelsieve`, `last_good_prompt`, and `lgp`
|
|
54
|
+
remain compatibility aliases for existing integrations.
|
|
55
|
+
|
|
56
|
+
The SDK is MIT licensed. Hosted Evalt Pro is a separate managed service; using the free
|
|
57
|
+
package never creates a platform charge.
|
|
58
|
+
|
|
59
|
+
## Production API
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from evalt import Evalt
|
|
63
|
+
|
|
64
|
+
evalt = Evalt(api_key=OPENROUTER_API_KEY)
|
|
65
|
+
answer = evalt.run(
|
|
66
|
+
"Classify this support request as billing, account, or technical.",
|
|
67
|
+
ticket,
|
|
68
|
+
route="support-routing",
|
|
69
|
+
test_budget_usd="auto",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
send(answer.content)
|
|
73
|
+
answer.accept() # or answer.correct("billing")
|
|
74
|
+
print(evalt.route_status("support-routing"))
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The first call uses the selected bootstrap route within the production price ceiling.
|
|
78
|
+
Explicit feedback becomes the route-specific evaluation set. On a later call, Evalt can
|
|
79
|
+
launch a background maintenance run after the configured evidence/traffic threshold is
|
|
80
|
+
met. Automatic test spend is bounded by `max_test_budget_usd` (USD 1 by default); a
|
|
81
|
+
retest never spends from an unlimited hidden allowance.
|
|
82
|
+
|
|
83
|
+
The focused default is `objective="lowest_cost_at_accuracy"` with
|
|
84
|
+
`target_accuracy=0.95`: Evalt promotes the cheapest tested configuration that clears that
|
|
85
|
+
approved bar. A price-first frontier and an incumbent-preservation migration mode remain
|
|
86
|
+
available:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
answer = evalt.run(
|
|
90
|
+
prompt,
|
|
91
|
+
input,
|
|
92
|
+
route="support-routing",
|
|
93
|
+
price_usd=0.05,
|
|
94
|
+
target_accuracy=0.97,
|
|
95
|
+
objective="lowest_cost_at_accuracy", # or "best_within_price"
|
|
96
|
+
test_budget_usd=0.75,
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`incumbent_model` is optional. Use it with
|
|
101
|
+
`objective="match_baseline_at_lowest_cost"` when migrating an existing workflow and you
|
|
102
|
+
specifically want the incumbent's measured validation quality to be the bar. New
|
|
103
|
+
workflows need no comparison model: their approved validation target is the bar.
|
|
104
|
+
|
|
105
|
+
Reasoning effort is tested as part of the model configuration only when the current ZDR
|
|
106
|
+
endpoint supports it. The adaptive search first runs one configuration across a broad
|
|
107
|
+
price/intelligence frontier, then spends the remaining test budget on effort variants for
|
|
108
|
+
models in the observed task-capability band. Reasoning configurations receive larger,
|
|
109
|
+
budget-reserved completion headroom so internal reasoning cannot silently consume the
|
|
110
|
+
requested visible response size. A transient empty response gets one budget-checked
|
|
111
|
+
retry. An explicitly truncated response fails that configuration immediately: Evalt does
|
|
112
|
+
not double a costly reasoning allowance after the provider has already hit the bounded
|
|
113
|
+
limit. Production cost uses the route's
|
|
114
|
+
90th-percentile approved input and output lengths. The default quality floor is 95%, and
|
|
115
|
+
held-out cases are repeated twice before promotion. A measured 100% means every repeated
|
|
116
|
+
approved final-test scenario passed on every configured repeat; it is not a guarantee
|
|
117
|
+
about every future input. Reports show distinct scenario count and execution count
|
|
118
|
+
separately.
|
|
119
|
+
|
|
120
|
+
Model roles are selected separately:
|
|
121
|
+
|
|
122
|
+
- the test designer / prompt improver uses the cheapest catalog model near the top of the
|
|
123
|
+
current intelligence range;
|
|
124
|
+
- the judge may use a lower-cost model only after route-specific verdict calibration;
|
|
125
|
+
- production targets come from the price/intelligence frontier, then win or lose on the
|
|
126
|
+
route's frozen human-approved cases.
|
|
127
|
+
|
|
128
|
+
Higher maintenance budgets tighten the intelligence floors and broaden the target field.
|
|
129
|
+
Catalog benchmarks shortlist contenders only; they never promote a route without the
|
|
130
|
+
task-specific holdout.
|
|
131
|
+
|
|
132
|
+
## Explicit optimization and CI
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
evalt init evalt.json
|
|
136
|
+
evalt validate evalt.json
|
|
137
|
+
export OPENROUTER_API_KEY="..."
|
|
138
|
+
evalt optimize evalt.json --output evalt-result.json
|
|
139
|
+
evalt check evalt-result.json --min-pass-rate 0.95
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`init`, `validate`, and `check` are offline and make no provider calls. `optimize` uses the
|
|
143
|
+
single `max_optimization_cost_usd` value in the suite as a hard cap across optimization,
|
|
144
|
+
target runs, judging, and every selected model. The command reports partial coverage
|
|
145
|
+
instead of calling an unfinished tournament globally best. It emits line-delimited
|
|
146
|
+
progress events to stderr as each model starts, finishes, or fails, while the final JSON
|
|
147
|
+
stays on stdout and at the requested output path. Model/scenario concurrency and the
|
|
148
|
+
wall-clock timeout for one provider response can be overridden per run.
|
|
149
|
+
|
|
150
|
+
Use stricter CI gates when needed:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
evalt check evalt-result.json \
|
|
154
|
+
--min-pass-rate 0.95 \
|
|
155
|
+
--max-cost-per-success 0.002 \
|
|
156
|
+
--require-complete-coverage
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The command exits `0` on pass, `1` when the measured result fails the gate, and `2` for an
|
|
160
|
+
invalid file or runtime error.
|
|
161
|
+
|
|
162
|
+
To inspect the CI contract without a provider call:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
evalt check examples/passing-result.json --min-pass-rate 0.95 --require-complete-coverage
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Explicit suite API
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from evalt import Evalt, Suite
|
|
172
|
+
|
|
173
|
+
suite = Suite.load("evalt.json") # validates without a provider call
|
|
174
|
+
result = Evalt().run(suite)
|
|
175
|
+
|
|
176
|
+
print(result.winner.model)
|
|
177
|
+
print(result.winner.selected_prompt)
|
|
178
|
+
print(result.winner.holdout_pass_rate)
|
|
179
|
+
print(result.winner.estimated_cost_per_successful_call_usd)
|
|
180
|
+
|
|
181
|
+
result.save("evalt-result.json")
|
|
182
|
+
result.save_regression_suite("evalt-regression.json")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
For lower-level integrations, `Client.optimize(...)` remains available. `Suite` is the
|
|
186
|
+
recommended surface because the full evaluation contract stays inspectable, serializable,
|
|
187
|
+
and offline-validatable before spend.
|
|
188
|
+
|
|
189
|
+
## Suite shape
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"schema": "evalt-suite-v1",
|
|
194
|
+
"name": "support-routing",
|
|
195
|
+
"prompt": "Classify the support message. Return one route label.",
|
|
196
|
+
"examples": [
|
|
197
|
+
{"id": "billing-1", "input": "I was charged twice", "approved_output": "billing"},
|
|
198
|
+
{"id": "account-1", "input": "My reset link expired", "approved_output": "account"},
|
|
199
|
+
{"id": "technical-1", "input": "The app freezes", "approved_output": "technical"}
|
|
200
|
+
],
|
|
201
|
+
"models": ["qwen/qwen3.5-9b", "google/gemini-3-flash-preview"],
|
|
202
|
+
"optimizer_model": "openai/gpt-5.6-luna",
|
|
203
|
+
"evaluator_model": "openai/gpt-5.6-luna",
|
|
204
|
+
"evaluator": {"type": "semantic"},
|
|
205
|
+
"quality_threshold": 0.95,
|
|
206
|
+
"max_optimization_cost_usd": 2.0,
|
|
207
|
+
"rounds": 3,
|
|
208
|
+
"max_parallel_models": 8,
|
|
209
|
+
"max_parallel_scenarios": 16,
|
|
210
|
+
"allow_few_shot": true,
|
|
211
|
+
"max_few_shot_examples": 3
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
With the default 20% final-test split, use at least 25 approved scenarios to obtain the
|
|
216
|
+
minimum five distinct final-test scenarios for a non-exploratory result. Repeats measure
|
|
217
|
+
consistency; they never inflate the distinct scenario count. A scenario may contain
|
|
218
|
+
a `turns` array for multi-turn behavior; Evalt keeps the whole conversation in one split
|
|
219
|
+
and replays prior assistant context. Few-shot examples can come only from the training
|
|
220
|
+
split and are removed while evaluating their own scenario.
|
|
221
|
+
|
|
222
|
+
For exact outputs, replace the semantic evaluator with a deterministic contract:
|
|
223
|
+
|
|
224
|
+
```json
|
|
225
|
+
"evaluator": {
|
|
226
|
+
"type": "exact_json",
|
|
227
|
+
"required_keys": ["x", "y"],
|
|
228
|
+
"allow_additional_properties": false,
|
|
229
|
+
"normalize_rational_strings": true
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This makes no evaluator-model call. `exact_text` is also available for strict labels.
|
|
234
|
+
Independent model lanes run concurrently (eight by default) and each lane evaluates up
|
|
235
|
+
to sixteen independent case executions concurrently. Model lanes are configurable up to
|
|
236
|
+
16 and case execution concurrency up to 64. Repeated executions are parallel work units;
|
|
237
|
+
turns inside one multi-turn scenario remain ordered. Every in-flight estimate is reserved
|
|
238
|
+
against the one hard suite budget. A prompt that already scores 100% on the validation
|
|
239
|
+
split skips training replay and rewriting and moves directly to the frozen final test.
|
|
240
|
+
|
|
241
|
+
## Provider and data contract
|
|
242
|
+
|
|
243
|
+
- The API key is read from `OPENROUTER_API_KEY`; it is never written to a suite or result.
|
|
244
|
+
- Every OpenRouter request requires Zero Data Retention and denies provider data collection.
|
|
245
|
+
- Current provider pricing is refreshed at least hourly by default before calls; a changed
|
|
246
|
+
price changes the catalog revision and makes the durable route due for a bounded re-test.
|
|
247
|
+
An unpriced or unbounded route fails closed. Set `catalog_ttl_seconds` on
|
|
248
|
+
`OpenRouterTransport` when a different refresh interval is required.
|
|
249
|
+
- Exact provider-reported cost is accumulated in the result.
|
|
250
|
+
- The SDK adds no platform or usage fee. Hosted BYOK is also free during early access.
|
|
251
|
+
A future paid hosted control plane for shared history, CI, scheduled Model Watch,
|
|
252
|
+
permissions, managed credentials, and support is an evidence-gated hypothesis rather
|
|
253
|
+
than a current subscription offer.
|
|
254
|
+
|
|
255
|
+
## Compatibility
|
|
256
|
+
|
|
257
|
+
Evalt follows semantic versioning for the primary `evalt` Python API, CLI command names,
|
|
258
|
+
suite schema, result schema, and exit-code contract. Deprecations remain available for
|
|
259
|
+
at least one minor release and are documented before removal. The legacy
|
|
260
|
+
`modelsieve`/`last_good_prompt` imports and `lgp` command are compatibility shims, not the
|
|
261
|
+
recommended surface for new integrations.
|
|
262
|
+
|
|
263
|
+
An exported result is evidence about its frozen examples and named model versions—not a
|
|
264
|
+
general intelligence ranking or a promise about unseen production traffic.
|
evalt-0.8.5/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Evalt Python SDK
|
|
2
|
+
|
|
3
|
+
Evalt is a durable runtime router. Your application gives it a prompt, an input, and a
|
|
4
|
+
stable route name. Evalt finds the lowest-cost prompt/model/reasoning configuration that
|
|
5
|
+
clears the approved validation target (95% by default), records the decision in SQLite,
|
|
6
|
+
and uses a separate capped test budget when traffic, a new model, or a provider-price
|
|
7
|
+
change makes retesting worthwhile.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
After the public package is released:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python -m pip install evalt
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Until that account-bound publication is complete, install the verified versioned wheel
|
|
18
|
+
from this repository checkout:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
python -m venv .venv
|
|
22
|
+
python -m pip install dist/evalt-0.8.5-py3-none-any.whl
|
|
23
|
+
evalt --version
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`evalt` is the primary import and command. `modelsieve`, `last_good_prompt`, and `lgp`
|
|
27
|
+
remain compatibility aliases for existing integrations.
|
|
28
|
+
|
|
29
|
+
The SDK is MIT licensed. Hosted Evalt Pro is a separate managed service; using the free
|
|
30
|
+
package never creates a platform charge.
|
|
31
|
+
|
|
32
|
+
## Production API
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from evalt import Evalt
|
|
36
|
+
|
|
37
|
+
evalt = Evalt(api_key=OPENROUTER_API_KEY)
|
|
38
|
+
answer = evalt.run(
|
|
39
|
+
"Classify this support request as billing, account, or technical.",
|
|
40
|
+
ticket,
|
|
41
|
+
route="support-routing",
|
|
42
|
+
test_budget_usd="auto",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
send(answer.content)
|
|
46
|
+
answer.accept() # or answer.correct("billing")
|
|
47
|
+
print(evalt.route_status("support-routing"))
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The first call uses the selected bootstrap route within the production price ceiling.
|
|
51
|
+
Explicit feedback becomes the route-specific evaluation set. On a later call, Evalt can
|
|
52
|
+
launch a background maintenance run after the configured evidence/traffic threshold is
|
|
53
|
+
met. Automatic test spend is bounded by `max_test_budget_usd` (USD 1 by default); a
|
|
54
|
+
retest never spends from an unlimited hidden allowance.
|
|
55
|
+
|
|
56
|
+
The focused default is `objective="lowest_cost_at_accuracy"` with
|
|
57
|
+
`target_accuracy=0.95`: Evalt promotes the cheapest tested configuration that clears that
|
|
58
|
+
approved bar. A price-first frontier and an incumbent-preservation migration mode remain
|
|
59
|
+
available:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
answer = evalt.run(
|
|
63
|
+
prompt,
|
|
64
|
+
input,
|
|
65
|
+
route="support-routing",
|
|
66
|
+
price_usd=0.05,
|
|
67
|
+
target_accuracy=0.97,
|
|
68
|
+
objective="lowest_cost_at_accuracy", # or "best_within_price"
|
|
69
|
+
test_budget_usd=0.75,
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`incumbent_model` is optional. Use it with
|
|
74
|
+
`objective="match_baseline_at_lowest_cost"` when migrating an existing workflow and you
|
|
75
|
+
specifically want the incumbent's measured validation quality to be the bar. New
|
|
76
|
+
workflows need no comparison model: their approved validation target is the bar.
|
|
77
|
+
|
|
78
|
+
Reasoning effort is tested as part of the model configuration only when the current ZDR
|
|
79
|
+
endpoint supports it. The adaptive search first runs one configuration across a broad
|
|
80
|
+
price/intelligence frontier, then spends the remaining test budget on effort variants for
|
|
81
|
+
models in the observed task-capability band. Reasoning configurations receive larger,
|
|
82
|
+
budget-reserved completion headroom so internal reasoning cannot silently consume the
|
|
83
|
+
requested visible response size. A transient empty response gets one budget-checked
|
|
84
|
+
retry. An explicitly truncated response fails that configuration immediately: Evalt does
|
|
85
|
+
not double a costly reasoning allowance after the provider has already hit the bounded
|
|
86
|
+
limit. Production cost uses the route's
|
|
87
|
+
90th-percentile approved input and output lengths. The default quality floor is 95%, and
|
|
88
|
+
held-out cases are repeated twice before promotion. A measured 100% means every repeated
|
|
89
|
+
approved final-test scenario passed on every configured repeat; it is not a guarantee
|
|
90
|
+
about every future input. Reports show distinct scenario count and execution count
|
|
91
|
+
separately.
|
|
92
|
+
|
|
93
|
+
Model roles are selected separately:
|
|
94
|
+
|
|
95
|
+
- the test designer / prompt improver uses the cheapest catalog model near the top of the
|
|
96
|
+
current intelligence range;
|
|
97
|
+
- the judge may use a lower-cost model only after route-specific verdict calibration;
|
|
98
|
+
- production targets come from the price/intelligence frontier, then win or lose on the
|
|
99
|
+
route's frozen human-approved cases.
|
|
100
|
+
|
|
101
|
+
Higher maintenance budgets tighten the intelligence floors and broaden the target field.
|
|
102
|
+
Catalog benchmarks shortlist contenders only; they never promote a route without the
|
|
103
|
+
task-specific holdout.
|
|
104
|
+
|
|
105
|
+
## Explicit optimization and CI
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
evalt init evalt.json
|
|
109
|
+
evalt validate evalt.json
|
|
110
|
+
export OPENROUTER_API_KEY="..."
|
|
111
|
+
evalt optimize evalt.json --output evalt-result.json
|
|
112
|
+
evalt check evalt-result.json --min-pass-rate 0.95
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`init`, `validate`, and `check` are offline and make no provider calls. `optimize` uses the
|
|
116
|
+
single `max_optimization_cost_usd` value in the suite as a hard cap across optimization,
|
|
117
|
+
target runs, judging, and every selected model. The command reports partial coverage
|
|
118
|
+
instead of calling an unfinished tournament globally best. It emits line-delimited
|
|
119
|
+
progress events to stderr as each model starts, finishes, or fails, while the final JSON
|
|
120
|
+
stays on stdout and at the requested output path. Model/scenario concurrency and the
|
|
121
|
+
wall-clock timeout for one provider response can be overridden per run.
|
|
122
|
+
|
|
123
|
+
Use stricter CI gates when needed:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
evalt check evalt-result.json \
|
|
127
|
+
--min-pass-rate 0.95 \
|
|
128
|
+
--max-cost-per-success 0.002 \
|
|
129
|
+
--require-complete-coverage
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The command exits `0` on pass, `1` when the measured result fails the gate, and `2` for an
|
|
133
|
+
invalid file or runtime error.
|
|
134
|
+
|
|
135
|
+
To inspect the CI contract without a provider call:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
evalt check examples/passing-result.json --min-pass-rate 0.95 --require-complete-coverage
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Explicit suite API
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from evalt import Evalt, Suite
|
|
145
|
+
|
|
146
|
+
suite = Suite.load("evalt.json") # validates without a provider call
|
|
147
|
+
result = Evalt().run(suite)
|
|
148
|
+
|
|
149
|
+
print(result.winner.model)
|
|
150
|
+
print(result.winner.selected_prompt)
|
|
151
|
+
print(result.winner.holdout_pass_rate)
|
|
152
|
+
print(result.winner.estimated_cost_per_successful_call_usd)
|
|
153
|
+
|
|
154
|
+
result.save("evalt-result.json")
|
|
155
|
+
result.save_regression_suite("evalt-regression.json")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
For lower-level integrations, `Client.optimize(...)` remains available. `Suite` is the
|
|
159
|
+
recommended surface because the full evaluation contract stays inspectable, serializable,
|
|
160
|
+
and offline-validatable before spend.
|
|
161
|
+
|
|
162
|
+
## Suite shape
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"schema": "evalt-suite-v1",
|
|
167
|
+
"name": "support-routing",
|
|
168
|
+
"prompt": "Classify the support message. Return one route label.",
|
|
169
|
+
"examples": [
|
|
170
|
+
{"id": "billing-1", "input": "I was charged twice", "approved_output": "billing"},
|
|
171
|
+
{"id": "account-1", "input": "My reset link expired", "approved_output": "account"},
|
|
172
|
+
{"id": "technical-1", "input": "The app freezes", "approved_output": "technical"}
|
|
173
|
+
],
|
|
174
|
+
"models": ["qwen/qwen3.5-9b", "google/gemini-3-flash-preview"],
|
|
175
|
+
"optimizer_model": "openai/gpt-5.6-luna",
|
|
176
|
+
"evaluator_model": "openai/gpt-5.6-luna",
|
|
177
|
+
"evaluator": {"type": "semantic"},
|
|
178
|
+
"quality_threshold": 0.95,
|
|
179
|
+
"max_optimization_cost_usd": 2.0,
|
|
180
|
+
"rounds": 3,
|
|
181
|
+
"max_parallel_models": 8,
|
|
182
|
+
"max_parallel_scenarios": 16,
|
|
183
|
+
"allow_few_shot": true,
|
|
184
|
+
"max_few_shot_examples": 3
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
With the default 20% final-test split, use at least 25 approved scenarios to obtain the
|
|
189
|
+
minimum five distinct final-test scenarios for a non-exploratory result. Repeats measure
|
|
190
|
+
consistency; they never inflate the distinct scenario count. A scenario may contain
|
|
191
|
+
a `turns` array for multi-turn behavior; Evalt keeps the whole conversation in one split
|
|
192
|
+
and replays prior assistant context. Few-shot examples can come only from the training
|
|
193
|
+
split and are removed while evaluating their own scenario.
|
|
194
|
+
|
|
195
|
+
For exact outputs, replace the semantic evaluator with a deterministic contract:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
"evaluator": {
|
|
199
|
+
"type": "exact_json",
|
|
200
|
+
"required_keys": ["x", "y"],
|
|
201
|
+
"allow_additional_properties": false,
|
|
202
|
+
"normalize_rational_strings": true
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This makes no evaluator-model call. `exact_text` is also available for strict labels.
|
|
207
|
+
Independent model lanes run concurrently (eight by default) and each lane evaluates up
|
|
208
|
+
to sixteen independent case executions concurrently. Model lanes are configurable up to
|
|
209
|
+
16 and case execution concurrency up to 64. Repeated executions are parallel work units;
|
|
210
|
+
turns inside one multi-turn scenario remain ordered. Every in-flight estimate is reserved
|
|
211
|
+
against the one hard suite budget. A prompt that already scores 100% on the validation
|
|
212
|
+
split skips training replay and rewriting and moves directly to the frozen final test.
|
|
213
|
+
|
|
214
|
+
## Provider and data contract
|
|
215
|
+
|
|
216
|
+
- The API key is read from `OPENROUTER_API_KEY`; it is never written to a suite or result.
|
|
217
|
+
- Every OpenRouter request requires Zero Data Retention and denies provider data collection.
|
|
218
|
+
- Current provider pricing is refreshed at least hourly by default before calls; a changed
|
|
219
|
+
price changes the catalog revision and makes the durable route due for a bounded re-test.
|
|
220
|
+
An unpriced or unbounded route fails closed. Set `catalog_ttl_seconds` on
|
|
221
|
+
`OpenRouterTransport` when a different refresh interval is required.
|
|
222
|
+
- Exact provider-reported cost is accumulated in the result.
|
|
223
|
+
- The SDK adds no platform or usage fee. Hosted BYOK is also free during early access.
|
|
224
|
+
A future paid hosted control plane for shared history, CI, scheduled Model Watch,
|
|
225
|
+
permissions, managed credentials, and support is an evidence-gated hypothesis rather
|
|
226
|
+
than a current subscription offer.
|
|
227
|
+
|
|
228
|
+
## Compatibility
|
|
229
|
+
|
|
230
|
+
Evalt follows semantic versioning for the primary `evalt` Python API, CLI command names,
|
|
231
|
+
suite schema, result schema, and exit-code contract. Deprecations remain available for
|
|
232
|
+
at least one minor release and are documented before removal. The legacy
|
|
233
|
+
`modelsieve`/`last_good_prompt` imports and `lgp` command are compatibility shims, not the
|
|
234
|
+
recommended surface for new integrations.
|
|
235
|
+
|
|
236
|
+
An exported result is evidence about its frozen examples and named model versions—not a
|
|
237
|
+
general intelligence ranking or a promise about unseen production traffic.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "evalt"
|
|
7
|
+
version = "0.8.5"
|
|
8
|
+
description = "A durable LLM router that finds the most accurate configuration at your price."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Jonathan Larson" }]
|
|
14
|
+
maintainers = [{ name = "Jonathan Larson" }]
|
|
15
|
+
keywords = ["llm", "prompt-engineering", "evaluation", "model-routing", "ci"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Software Development :: Testing",
|
|
28
|
+
]
|
|
29
|
+
dependencies = []
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://evalt.dev"
|
|
33
|
+
Documentation = "https://evalt.dev/#sdk"
|
|
34
|
+
Changelog = "https://evalt.dev/#sdk"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
evalt = "evalt.cli:main"
|
|
38
|
+
modelsieve = "modelsieve.cli:main"
|
|
39
|
+
lgp = "last_good_prompt.cli:main"
|
|
40
|
+
|
|
41
|
+
[tool.setuptools]
|
|
42
|
+
package-dir = {"" = "src"}
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.package-data]
|
|
48
|
+
evalt = ["py.typed"]
|
evalt-0.8.5/setup.cfg
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Public SDK surface for Evalt."""
|
|
2
|
+
|
|
3
|
+
from .core import (
|
|
4
|
+
BudgetExceeded,
|
|
5
|
+
Client,
|
|
6
|
+
DraftAnswer,
|
|
7
|
+
Evalt,
|
|
8
|
+
Example,
|
|
9
|
+
GateReport,
|
|
10
|
+
ModelResult,
|
|
11
|
+
OptimizationResult,
|
|
12
|
+
ProviderError,
|
|
13
|
+
RolePlan,
|
|
14
|
+
RoutedAnswer,
|
|
15
|
+
Suite,
|
|
16
|
+
Turn,
|
|
17
|
+
check_result,
|
|
18
|
+
select_role_plan,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"BudgetExceeded",
|
|
23
|
+
"Client",
|
|
24
|
+
"DraftAnswer",
|
|
25
|
+
"Evalt",
|
|
26
|
+
"Example",
|
|
27
|
+
"GateReport",
|
|
28
|
+
"ModelResult",
|
|
29
|
+
"OptimizationResult",
|
|
30
|
+
"ProviderError",
|
|
31
|
+
"RolePlan",
|
|
32
|
+
"RoutedAnswer",
|
|
33
|
+
"Suite",
|
|
34
|
+
"Turn",
|
|
35
|
+
"check_result",
|
|
36
|
+
"select_role_plan",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
__version__ = "0.8.5"
|