whileai 0.57__tar.gz → 0.58__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.
- {whileai-0.57/whileai.egg-info → whileai-0.58}/PKG-INFO +6 -2
- {whileai-0.57 → whileai-0.58}/README.md +5 -1
- {whileai-0.57 → whileai-0.58}/pyproject.toml +1 -1
- {whileai-0.57 → whileai-0.58}/whileai/simulations/ingest/traces.py +17 -11
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/delta.py +15 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/stats.py +34 -9
- {whileai-0.57 → whileai-0.58/whileai.egg-info}/PKG-INFO +6 -2
- {whileai-0.57 → whileai-0.58}/LICENSE +0 -0
- {whileai-0.57 → whileai-0.58}/MANIFEST.in +0 -0
- {whileai-0.57 → whileai-0.58}/setup.cfg +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/_env.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/auth.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/cli.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/ingest.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/py.typed +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/__main__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/data.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/environment.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/export.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/actionspace.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/adapters.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/agents.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/coverage.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/diversity.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/embeddings.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/explore.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/generator.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/offline_agent.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/scenarios.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/generate/usage_meter.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/ingest/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/ingest/otel.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/ingest/platform.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/monitor.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/py.typed +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/run/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/run/config.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/run/engine.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/run/rows.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/run/spec.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/schema.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/schemas/row-v1.json +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/agreement.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/audit.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/checklist.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/curriculum.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/grade_llm.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/grading.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/grounding.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/hack_scan.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/hygiene.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/judge_trust.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/judging.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/labels.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/llm_judge.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/logprobs.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/markers.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/optimize.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/pairwise.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/passat.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/preflight.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/privileged.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/publish_gate.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/quality.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/reference.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/rubric.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/spec.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/stage.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/style.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/score/trace.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/simulation.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/training.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/verify/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/verify/base.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/verify/code.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/verify/math.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/verify/structured.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/verify/text.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/world/__init__.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai/simulations/world/sandbox.py +0 -0
- {whileai-0.57 → whileai-0.58}/whileai.egg-info/SOURCES.txt +0 -0
- {whileai-0.57 → whileai-0.58}/whileai.egg-info/dependency_links.txt +0 -0
- {whileai-0.57 → whileai-0.58}/whileai.egg-info/entry_points.txt +0 -0
- {whileai-0.57 → whileai-0.58}/whileai.egg-info/requires.txt +0 -0
- {whileai-0.57 → whileai-0.58}/whileai.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: whileai
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.58
|
|
4
4
|
Summary: While Python SDK: trace ingestion and verification client, plus agent simulations grounded in your tools and system prompt.
|
|
5
5
|
Author: While
|
|
6
6
|
License: Apache-2.0
|
|
@@ -219,7 +219,11 @@ rollout touched, a marker that fired on no row. A 1.00 on a run like that is not
|
|
|
219
219
|
|
|
220
220
|
Bring your own model. Any OpenAI-compatible chat endpoint that returns tool
|
|
221
221
|
calls works; it writes the situations and plays the agent, so both run on
|
|
222
|
-
your key
|
|
222
|
+
your key. To put a number on a model you serve (`wai.serve`, or your own
|
|
223
|
+
vLLM), make it the agent: `wai.simulate(tasks=pinned,
|
|
224
|
+
agent=wai.local_model(endpoint, name, tools=TOOLS, system=POLICY,
|
|
225
|
+
thinking=False))`, and run both arms of a before/after through that same
|
|
226
|
+
call so the only difference is the weights.
|
|
223
227
|
|
|
224
228
|
```bash
|
|
225
229
|
export OPENAI_API_KEY=...
|
|
@@ -183,7 +183,11 @@ rollout touched, a marker that fired on no row. A 1.00 on a run like that is not
|
|
|
183
183
|
|
|
184
184
|
Bring your own model. Any OpenAI-compatible chat endpoint that returns tool
|
|
185
185
|
calls works; it writes the situations and plays the agent, so both run on
|
|
186
|
-
your key
|
|
186
|
+
your key. To put a number on a model you serve (`wai.serve`, or your own
|
|
187
|
+
vLLM), make it the agent: `wai.simulate(tasks=pinned,
|
|
188
|
+
agent=wai.local_model(endpoint, name, tools=TOOLS, system=POLICY,
|
|
189
|
+
thinking=False))`, and run both arms of a before/after through that same
|
|
190
|
+
call so the only difference is the weights.
|
|
187
191
|
|
|
188
192
|
```bash
|
|
189
193
|
export OPENAI_API_KEY=...
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "whileai"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.58"
|
|
8
8
|
description = "While Python SDK: trace ingestion and verification client, plus agent simulations grounded in your tools and system prompt."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Apache-2.0"}
|
|
@@ -278,15 +278,20 @@ def dimensions_from_traces(
|
|
|
278
278
|
def _task_key(row: dict, index: int) -> tuple[str, object]:
|
|
279
279
|
"""What makes two rows the same task for splitting purposes.
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
The unit every report counts in: ``task_key`` (``scenario_id`` when
|
|
282
|
+
the row has one, else ``task_id``, else the prompt), so repeats and
|
|
283
|
+
rephrasings of one situation land on the same side and the held-out
|
|
284
|
+
slice is disjoint from train in the unit ``pass_at``, ``compare_runs``
|
|
285
|
+
and ``delta_report`` group by (#268). Splitting on the prompt alone
|
|
286
|
+
left 16 of 28 held-out situations in train, and ``decontaminate``
|
|
287
|
+
cannot see that because it compares prompts. A row with no key is its
|
|
288
|
+
own task, so rows that merely lack one are not swept onto one side.
|
|
285
289
|
"""
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
+
from ..score.stats import task_key
|
|
291
|
+
|
|
292
|
+
key = task_key(row) if isinstance(row, dict) else ""
|
|
293
|
+
if key and str(key).strip():
|
|
294
|
+
return ("task", str(key))
|
|
290
295
|
return ("index", index)
|
|
291
296
|
|
|
292
297
|
|
|
@@ -295,9 +300,10 @@ def split_pseudo_production(
|
|
|
295
300
|
) -> tuple[list[dict], list[dict]]:
|
|
296
301
|
"""Set aside a pseudo-production slice; the rest stays for training.
|
|
297
302
|
|
|
298
|
-
The split is by task, not by row: every row sharing a ``
|
|
299
|
-
``scenario_id``,
|
|
300
|
-
|
|
303
|
+
The split is by task, not by row: every row sharing a ``task_key``
|
|
304
|
+
(the ``scenario_id``, else the prompt) lands on the same side, so the
|
|
305
|
+
held-out slice is disjoint from the training side in the unit every
|
|
306
|
+
report groups by, not just prompt-disjoint. Splitting
|
|
301
307
|
by row is not enough — under ``mode="rl"`` with ``repeats=k`` each
|
|
302
308
|
prompt has k rows, and scattering siblings across the two sides trains
|
|
303
309
|
the student on every prompt it is then evaluated on.
|
|
@@ -33,6 +33,7 @@ from .stats import (
|
|
|
33
33
|
eval_variance,
|
|
34
34
|
holdout_size,
|
|
35
35
|
marker_names,
|
|
36
|
+
metric_summary,
|
|
36
37
|
task_means,
|
|
37
38
|
)
|
|
38
39
|
|
|
@@ -214,6 +215,13 @@ def delta_report(
|
|
|
214
215
|
|
|
215
216
|
guarded = {_key(m) for m in must_not_regress}
|
|
216
217
|
target_key = _key(target) if target else None
|
|
218
|
+
degenerate_guards: list[str] = []
|
|
219
|
+
for m in sorted(guarded):
|
|
220
|
+
if m not in results:
|
|
221
|
+
continue
|
|
222
|
+
sides = [metric_summary(rows, m, n_boot=10) for rows in (before, after)]
|
|
223
|
+
if all(s.get("degenerate") for s in sides):
|
|
224
|
+
degenerate_guards.append(m)
|
|
217
225
|
eval_runs = {"before": len(_eval_runs(before)), "after": len(_eval_runs(after))}
|
|
218
226
|
run_std_source = "given" if run_std is not None else None
|
|
219
227
|
if run_std is None and min(eval_runs.values()) >= 2:
|
|
@@ -255,6 +263,12 @@ def delta_report(
|
|
|
255
263
|
f"One eval run on {where}, so this could be noise. Run each side three times with "
|
|
256
264
|
"simulate(tasks=..., runs=3) and the report will say."
|
|
257
265
|
)
|
|
266
|
+
for m in degenerate_guards:
|
|
267
|
+
warnings.append(
|
|
268
|
+
f"must_not_regress {m} is degenerate on both sides (every applicable row scored the "
|
|
269
|
+
"same value): this guard cannot fail, so it catches nothing. Check that the marker "
|
|
270
|
+
"fires at all."
|
|
271
|
+
)
|
|
258
272
|
if run_std_source == "eval_run" and min(eval_runs.values()) < 3:
|
|
259
273
|
warnings.append(
|
|
260
274
|
"Two eval runs on a side is a difference, not a distribution, so run_std is rough; "
|
|
@@ -434,6 +448,7 @@ def delta_report(
|
|
|
434
448
|
"ceiling": ceiling,
|
|
435
449
|
"detectable_effect": can_prove,
|
|
436
450
|
"tasks_needed": tasks_needed,
|
|
451
|
+
"degenerate_guards": degenerate_guards,
|
|
437
452
|
"proxy": proxy_key,
|
|
438
453
|
"proxy_verdict": proxy_verdict,
|
|
439
454
|
"proxy_delta": proxy_result["delta"] if proxy_result else None,
|
|
@@ -250,21 +250,46 @@ def task_means(rows: Sequence[dict], metric: str = "pass_at_1") -> dict[str, flo
|
|
|
250
250
|
def metric_summary(
|
|
251
251
|
rows: Sequence[dict], metric: str = "pass_at_1", *, n_boot: int = DEFAULT_BOOT, seed: int = 0
|
|
252
252
|
) -> dict[str, Any]:
|
|
253
|
-
"""Mean over tasks with a task-bootstrap 95% interval.
|
|
253
|
+
"""Mean over tasks with a task-bootstrap 95% interval.
|
|
254
|
+
|
|
255
|
+
``degenerate`` is set when every applicable row scored the same
|
|
256
|
+
value: the metric has not been shown to be able to come out any
|
|
257
|
+
other way, so ``ci95`` is ``None`` (the way ``pass_at`` returns
|
|
258
|
+
``None`` below three groups) and ``warning`` says so. A marker that
|
|
259
|
+
is silently unfireable (a key-name mismatch) and one that is
|
|
260
|
+
genuinely always true look identical otherwise, and either one passed
|
|
261
|
+
to ``must_not_regress`` is a guard that cannot fail (#270).
|
|
262
|
+
``n_rows_at_1`` and ``n_rows_at_0`` put the row-level split next to
|
|
263
|
+
the mean.
|
|
264
|
+
"""
|
|
254
265
|
means = task_means(rows, metric)
|
|
255
266
|
values = list(means.values())
|
|
256
|
-
|
|
267
|
+
per_task = _by_task(
|
|
268
|
+
rows, _binary if metric == "pass_at_1" else _marker(metric.split(":", 1)[1])
|
|
269
|
+
)
|
|
270
|
+
row_values = [v for vs in per_task.values() for v in vs]
|
|
271
|
+
distinct = {round(float(v), 9) for v in row_values}
|
|
272
|
+
degenerate = len(row_values) > 0 and len(distinct) == 1
|
|
273
|
+
out: dict[str, Any] = {
|
|
257
274
|
"metric": metric,
|
|
258
275
|
"n_tasks": len(values),
|
|
259
|
-
"n_rows":
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
rows, _binary if metric == "pass_at_1" else _marker(metric.split(":", 1)[1])
|
|
263
|
-
).values()
|
|
264
|
-
),
|
|
276
|
+
"n_rows": len(row_values),
|
|
277
|
+
"n_rows_at_1": sum(1 for v in row_values if float(v) == 1.0),
|
|
278
|
+
"n_rows_at_0": sum(1 for v in row_values if float(v) == 0.0),
|
|
265
279
|
"mean": _mean(values) if values else None,
|
|
266
|
-
"ci95": bootstrap_ci(values, n_boot=n_boot, seed=seed),
|
|
280
|
+
"ci95": None if degenerate else bootstrap_ci(values, n_boot=n_boot, seed=seed),
|
|
281
|
+
"degenerate": degenerate,
|
|
267
282
|
}
|
|
283
|
+
if degenerate:
|
|
284
|
+
only = next(iter(distinct))
|
|
285
|
+
name = metric.split(":", 1)[1] if metric.startswith("marker:") else metric
|
|
286
|
+
out["warning"] = (
|
|
287
|
+
f"all {len(row_values)} applicable rows scored {only:g}; {name} has not been shown "
|
|
288
|
+
"to be able to come out any other way. Check the marker fires at all (a key-name "
|
|
289
|
+
"mismatch looks exactly like this) before reading the mean, and do not put it in "
|
|
290
|
+
"must_not_regress: a guard that cannot fail catches nothing."
|
|
291
|
+
)
|
|
292
|
+
return out
|
|
268
293
|
|
|
269
294
|
|
|
270
295
|
def marker_names(rows: Sequence[dict]) -> list[str]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: whileai
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.58
|
|
4
4
|
Summary: While Python SDK: trace ingestion and verification client, plus agent simulations grounded in your tools and system prompt.
|
|
5
5
|
Author: While
|
|
6
6
|
License: Apache-2.0
|
|
@@ -219,7 +219,11 @@ rollout touched, a marker that fired on no row. A 1.00 on a run like that is not
|
|
|
219
219
|
|
|
220
220
|
Bring your own model. Any OpenAI-compatible chat endpoint that returns tool
|
|
221
221
|
calls works; it writes the situations and plays the agent, so both run on
|
|
222
|
-
your key
|
|
222
|
+
your key. To put a number on a model you serve (`wai.serve`, or your own
|
|
223
|
+
vLLM), make it the agent: `wai.simulate(tasks=pinned,
|
|
224
|
+
agent=wai.local_model(endpoint, name, tools=TOOLS, system=POLICY,
|
|
225
|
+
thinking=False))`, and run both arms of a before/after through that same
|
|
226
|
+
call so the only difference is the weights.
|
|
223
227
|
|
|
224
228
|
```bash
|
|
225
229
|
export OPENAI_API_KEY=...
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|