deriva-dev 0.8.3__tar.gz → 0.8.4__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.
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/PKG-INFO +2 -2
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/pyproject.toml +2 -2
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/pyproject.toml.orig +2 -2
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/benchmarking.py +96 -9
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/cli.py +50 -2
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/config_deviation.py +1 -1
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/router.py +35 -2
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/session.py +26 -3
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/session_metrics.py +5 -4
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/LICENSE +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/README.md +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/__init__.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/analysis.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/baseline_b1.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/benchmark_views.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/conventions_report.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/data/conventions.json +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/gate.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/reference_eval.py +0 -0
- {deriva_dev-0.8.3 → deriva_dev-0.8.4}/src/deriva/bench/step_benchmark.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deriva-dev
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.4
|
|
4
4
|
Summary: Deriva with benchmarking: the studio, the CLI and multi-model consistency benchmarks.
|
|
5
5
|
Author: S. T. Grond
|
|
6
6
|
Author-email: S. T. Grond <steven@deriva.dev>
|
|
7
7
|
License-Expression: AGPL-3.0-or-later
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Requires-Dist: deriva-studio==0.8.
|
|
9
|
+
Requires-Dist: deriva-studio==0.8.4
|
|
10
10
|
Requires-Python: >=3.14
|
|
11
11
|
Project-URL: Homepage, https://deriva.dev
|
|
12
12
|
Project-URL: Documentation, https://docs.deriva.dev
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "deriva-dev"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.4"
|
|
4
4
|
description = "Deriva with benchmarking: the studio, the CLI and multi-model consistency benchmarks."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
7
7
|
license = "AGPL-3.0-or-later"
|
|
8
8
|
license-files = ["LICENSE"]
|
|
9
|
-
dependencies = ["deriva-studio==0.8.
|
|
9
|
+
dependencies = ["deriva-studio==0.8.4"]
|
|
10
10
|
|
|
11
11
|
[[project.authors]]
|
|
12
12
|
name = "S. T. Grond"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "deriva-dev"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.4"
|
|
4
4
|
description = "Deriva with benchmarking: the studio, the CLI and multi-model consistency benchmarks."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
@@ -8,7 +8,7 @@ license = "AGPL-3.0-or-later"
|
|
|
8
8
|
# A copy of the repository LICENSE (a package cannot point outside its folder); tests/test_packaging.py keeps it identical
|
|
9
9
|
license-files = ["LICENSE"]
|
|
10
10
|
authors = [{ name = "S. T. Grond", email = "steven@deriva.dev" }]
|
|
11
|
-
dependencies = ["deriva-studio==0.8.
|
|
11
|
+
dependencies = ["deriva-studio==0.8.4"]
|
|
12
12
|
|
|
13
13
|
[project.urls]
|
|
14
14
|
Homepage = "https://deriva.dev"
|
|
@@ -1347,7 +1347,7 @@ class BenchmarkOrchestrator:
|
|
|
1347
1347
|
return response
|
|
1348
1348
|
|
|
1349
1349
|
# Attach cache keys list to function for retrieval after run
|
|
1350
|
-
query_fn.used_cache_keys = used_cache_keys # type: ignore[attr-defined]
|
|
1350
|
+
query_fn.used_cache_keys = used_cache_keys # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
|
|
1351
1351
|
return query_fn
|
|
1352
1352
|
|
|
1353
1353
|
def _record_llm_call(self, llm: Any, step: str | None, prompt: str, schema: dict | None, system_prompt: str | None, response: Any, error: str | None) -> None:
|
|
@@ -1884,27 +1884,66 @@ def export_process_logs(benchmarks_dir: str | Path, session_ids: list[str], out_
|
|
|
1884
1884
|
return paths
|
|
1885
1885
|
|
|
1886
1886
|
|
|
1887
|
-
def list_benchmark_sessions(
|
|
1887
|
+
def list_benchmark_sessions(
|
|
1888
|
+
engine: Any,
|
|
1889
|
+
limit: int = 10,
|
|
1890
|
+
offset: int = 0,
|
|
1891
|
+
search: str | None = None,
|
|
1892
|
+
repository: str | None = None,
|
|
1893
|
+
model: str | None = None,
|
|
1894
|
+
status: str | None = None,
|
|
1895
|
+
) -> list[dict[str, Any]]:
|
|
1888
1896
|
"""
|
|
1889
|
-
List
|
|
1897
|
+
List benchmark sessions, newest first, with the repositories, models and runs they hold.
|
|
1890
1898
|
|
|
1891
1899
|
Args:
|
|
1892
1900
|
engine: DuckDB connection
|
|
1893
1901
|
limit: Maximum number of sessions to return
|
|
1902
|
+
offset: Sessions to skip (a page at a time)
|
|
1903
|
+
search: Text in the session id or description (any case)
|
|
1904
|
+
repository: Only sessions with a run of this repository
|
|
1905
|
+
model: Only sessions with a run of this model config
|
|
1906
|
+
status: Only sessions with this status (completed, failed, running)
|
|
1894
1907
|
|
|
1895
1908
|
Returns:
|
|
1896
1909
|
List of session dictionaries
|
|
1897
1910
|
"""
|
|
1911
|
+
where: list[str] = []
|
|
1912
|
+
params: list[Any] = []
|
|
1913
|
+
if search:
|
|
1914
|
+
where.append("(s.session_id ILIKE ? OR coalesce(s.description, '') ILIKE ?)")
|
|
1915
|
+
params += [f"%{search}%", f"%{search}%"]
|
|
1916
|
+
if repository:
|
|
1917
|
+
where.append("EXISTS (SELECT 1 FROM benchmark_runs r WHERE r.session_id = s.session_id AND r.repository = ?)")
|
|
1918
|
+
params.append(repository)
|
|
1919
|
+
if model:
|
|
1920
|
+
where.append("EXISTS (SELECT 1 FROM benchmark_runs r WHERE r.session_id = s.session_id AND r.model_name = ?)")
|
|
1921
|
+
params.append(model)
|
|
1922
|
+
if status:
|
|
1923
|
+
where.append("s.status = ?")
|
|
1924
|
+
params.append(status)
|
|
1925
|
+
clause = f"WHERE {' AND '.join(where)}" if where else ""
|
|
1898
1926
|
rows = engine.execute(
|
|
1899
|
-
"""
|
|
1900
|
-
SELECT session_id, description, status, started_at, completed_at
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1927
|
+
f"""
|
|
1928
|
+
SELECT s.session_id, s.description, s.status, s.started_at, s.completed_at, s.config,
|
|
1929
|
+
count(r.run_id), list(DISTINCT r.repository), list(DISTINCT r.model_name)
|
|
1930
|
+
FROM benchmark_sessions s
|
|
1931
|
+
LEFT JOIN benchmark_runs r ON r.session_id = s.session_id
|
|
1932
|
+
{clause}
|
|
1933
|
+
GROUP BY s.session_id, s.description, s.status, s.started_at, s.completed_at, s.config
|
|
1934
|
+
ORDER BY s.started_at DESC, s.session_id DESC
|
|
1935
|
+
LIMIT ? OFFSET ?
|
|
1904
1936
|
""",
|
|
1905
|
-
[limit],
|
|
1937
|
+
[*params, limit, offset],
|
|
1906
1938
|
).fetchall()
|
|
1907
1939
|
|
|
1940
|
+
def stages(config: Any) -> list[str]:
|
|
1941
|
+
try:
|
|
1942
|
+
found = json.loads(config) if isinstance(config, str) else (config or {})
|
|
1943
|
+
except ValueError:
|
|
1944
|
+
return []
|
|
1945
|
+
return [str(stage) for stage in found.get("stages") or []] if isinstance(found, dict) else []
|
|
1946
|
+
|
|
1908
1947
|
return [
|
|
1909
1948
|
{
|
|
1910
1949
|
"session_id": row[0],
|
|
@@ -1912,11 +1951,59 @@ def list_benchmark_sessions(engine: Any, limit: int = 10) -> list[dict[str, Any]
|
|
|
1912
1951
|
"status": row[2],
|
|
1913
1952
|
"started_at": row[3],
|
|
1914
1953
|
"completed_at": row[4],
|
|
1954
|
+
"stages": stages(row[5]),
|
|
1955
|
+
"runs": int(row[6]),
|
|
1956
|
+
"repositories": sorted(x for x in row[7] or [] if x is not None),
|
|
1957
|
+
"models": sorted(x for x in row[8] or [] if x is not None),
|
|
1915
1958
|
}
|
|
1916
1959
|
for row in rows
|
|
1917
1960
|
]
|
|
1918
1961
|
|
|
1919
1962
|
|
|
1963
|
+
def folder_bytes(folder: Path) -> int:
|
|
1964
|
+
"""Bytes the files under a folder take (0 when it does not exist)."""
|
|
1965
|
+
return sum(f.stat().st_size for f in folder.rglob("*") if f.is_file()) if folder.is_dir() else 0
|
|
1966
|
+
|
|
1967
|
+
|
|
1968
|
+
def delete_benchmark_session(engine: Any, session_id: str, benchmarks_dir: str | Path) -> dict[str, Any]:
|
|
1969
|
+
"""Delete a session: its rows (session, runs, metrics) and its folder (event logs, snapshots, inputs).
|
|
1970
|
+
|
|
1971
|
+
Raises:
|
|
1972
|
+
KeyError: no such session
|
|
1973
|
+
ValueError: the session is still running (mark it failed first when its process stopped)
|
|
1974
|
+
"""
|
|
1975
|
+
info = get_benchmark_session(engine, session_id)
|
|
1976
|
+
if info is None:
|
|
1977
|
+
raise KeyError(session_id)
|
|
1978
|
+
if info["status"] == "running":
|
|
1979
|
+
raise ValueError(f"Session {session_id} is running; mark it failed first when its process has stopped")
|
|
1980
|
+
(runs,) = engine.execute("SELECT count(*) FROM benchmark_runs WHERE session_id = ?", [session_id]).fetchone()
|
|
1981
|
+
for table in ("benchmark_metrics", "benchmark_runs", "benchmark_sessions"):
|
|
1982
|
+
engine.execute(f"DELETE FROM {table} WHERE session_id = ?", [session_id])
|
|
1983
|
+
folder = Path(benchmarks_dir) / session_id
|
|
1984
|
+
size = folder_bytes(folder)
|
|
1985
|
+
if folder.is_dir():
|
|
1986
|
+
shutil.rmtree(folder)
|
|
1987
|
+
return {"session_id": session_id, "runs": int(runs), "bytes": size}
|
|
1988
|
+
|
|
1989
|
+
|
|
1990
|
+
def prune_benchmark_sessions(engine: Any, benchmarks_dir: str | Path, keep: int | None = None, failed: bool = False) -> list[str]:
|
|
1991
|
+
"""Delete the failed sessions, or every session past the latest ``keep``; running sessions always stay.
|
|
1992
|
+
|
|
1993
|
+
Returns the deleted session ids, newest first.
|
|
1994
|
+
"""
|
|
1995
|
+
rows = engine.execute("SELECT session_id, status FROM benchmark_sessions ORDER BY started_at DESC, session_id DESC").fetchall()
|
|
1996
|
+
if failed:
|
|
1997
|
+
victims = [sid for sid, status in rows if status == "failed"]
|
|
1998
|
+
elif keep is not None:
|
|
1999
|
+
victims = [sid for sid, status in rows[max(keep, 0) :] if status != "running"]
|
|
2000
|
+
else:
|
|
2001
|
+
return []
|
|
2002
|
+
for session_id in victims:
|
|
2003
|
+
delete_benchmark_session(engine, session_id, benchmarks_dir)
|
|
2004
|
+
return victims
|
|
2005
|
+
|
|
2006
|
+
|
|
1920
2007
|
def get_benchmark_session(engine: Any, session_id: str) -> dict[str, Any] | None:
|
|
1921
2008
|
"""
|
|
1922
2009
|
Get details for a specific benchmark session.
|
|
@@ -7,7 +7,7 @@ Provides commands for multi-model benchmarking.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
|
-
from collections.abc import
|
|
10
|
+
from collections.abc import Generator
|
|
11
11
|
from contextlib import contextmanager
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import TYPE_CHECKING, Annotated
|
|
@@ -26,7 +26,7 @@ app = typer.Typer(name="benchmark", help="Multi-model benchmarking")
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@contextmanager
|
|
29
|
-
def _benchmarks() ->
|
|
29
|
+
def _benchmarks() -> Generator[BenchmarkSession]:
|
|
30
30
|
"""A connected PipelineSession with the benchmark operations."""
|
|
31
31
|
with PipelineSession() as session:
|
|
32
32
|
yield BenchmarkSession(session)
|
|
@@ -328,6 +328,54 @@ def benchmark_list(
|
|
|
328
328
|
typer.echo("")
|
|
329
329
|
|
|
330
330
|
|
|
331
|
+
def _megabytes(size: int) -> str:
|
|
332
|
+
return f"{size / 1024 / 1024:.1f} MB"
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
@app.command("delete")
|
|
336
|
+
def benchmark_delete(
|
|
337
|
+
session_ids: Annotated[list[str], typer.Argument(help="Benchmark sessions to delete")],
|
|
338
|
+
) -> None:
|
|
339
|
+
"""Delete benchmark sessions with their runs, metrics and folders (a running session is refused)."""
|
|
340
|
+
failed = False
|
|
341
|
+
with _benchmarks() as session:
|
|
342
|
+
for session_id in session_ids:
|
|
343
|
+
try:
|
|
344
|
+
result = session.delete_benchmark(session_id)
|
|
345
|
+
except KeyError:
|
|
346
|
+
typer.echo(f"Error: Benchmark session not found: {session_id}", err=True)
|
|
347
|
+
failed = True
|
|
348
|
+
continue
|
|
349
|
+
except ValueError as e:
|
|
350
|
+
typer.echo(f"Error: {e}", err=True)
|
|
351
|
+
failed = True
|
|
352
|
+
continue
|
|
353
|
+
typer.echo(f"Deleted {session_id} ({result['runs']} runs, {_megabytes(result['bytes'])})")
|
|
354
|
+
if failed:
|
|
355
|
+
raise typer.Exit(1)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@app.command("prune")
|
|
359
|
+
def benchmark_prune(
|
|
360
|
+
keep: Annotated[int | None, typer.Option("--keep", min=0, help="Keep the latest N sessions, delete the older ones")] = None,
|
|
361
|
+
failed: Annotated[bool, typer.Option("--failed", help="Delete the failed sessions")] = False,
|
|
362
|
+
yes: Annotated[bool, typer.Option("-y", "--yes", help="Do not ask first")] = False,
|
|
363
|
+
) -> None:
|
|
364
|
+
"""Delete the failed sessions, or every session past the latest N, with their runs, metrics and folders; running sessions stay."""
|
|
365
|
+
if keep is None and not failed:
|
|
366
|
+
typer.echo("Error: say which sessions to delete: --keep N or --failed", err=True)
|
|
367
|
+
raise typer.Exit(1)
|
|
368
|
+
which = "the failed sessions" if failed else f"every session past the latest {keep}"
|
|
369
|
+
if not yes and not typer.confirm(f"Delete {which}, with their runs, metrics and folders?"):
|
|
370
|
+
raise typer.Exit(1)
|
|
371
|
+
with _benchmarks() as session:
|
|
372
|
+
deleted = session.prune_benchmarks(keep=None if failed else keep, failed=failed)
|
|
373
|
+
if not deleted:
|
|
374
|
+
typer.echo("No sessions to delete.")
|
|
375
|
+
return
|
|
376
|
+
typer.echo(f"Deleted {len(deleted)} session{'' if len(deleted) == 1 else 's'}: {', '.join(deleted)}")
|
|
377
|
+
|
|
378
|
+
|
|
331
379
|
@app.command("conventions")
|
|
332
380
|
def benchmark_conventions(
|
|
333
381
|
session_ids: Annotated[list[str], typer.Argument(help="Benchmark sessions whose run snapshots are checked")],
|
|
@@ -198,7 +198,7 @@ class ConfigDeviationAnalyzer:
|
|
|
198
198
|
return {"config_id": config_id, "error": "No objects found for config"}
|
|
199
199
|
|
|
200
200
|
# Build per-object breakdown
|
|
201
|
-
object_details = []
|
|
201
|
+
object_details: list[dict[str, Any]] = []
|
|
202
202
|
objects_by_run = {run_id: nodes_by_run.get(run_id, set()) | elements_by_run.get(run_id, set()) for run_id in all_runs}
|
|
203
203
|
|
|
204
204
|
for obj_id in config_objects:
|
|
@@ -53,8 +53,41 @@ def _view(read: Any) -> Any:
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
@router.get("")
|
|
56
|
-
def list_sessions(
|
|
57
|
-
|
|
56
|
+
def list_sessions(
|
|
57
|
+
limit: int = Query(20, ge=1, le=500),
|
|
58
|
+
offset: int = Query(0, ge=0),
|
|
59
|
+
search: str | None = None,
|
|
60
|
+
repository: str | None = None,
|
|
61
|
+
model: str | None = None,
|
|
62
|
+
status: str | None = None,
|
|
63
|
+
session: Any = Depends(get_benchmarks),
|
|
64
|
+
) -> list[dict[str, Any]]:
|
|
65
|
+
"""Sessions newest first, a page at a time: by text (id or description), repository, model and status."""
|
|
66
|
+
return session.list_benchmarks(limit, offset=offset, search=search, repository=repository, model=model, status=status)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _when_idle(request: Request, action: Any) -> Any:
|
|
70
|
+
"""Session changes wait for a run to end: a benchmark in progress writes its session."""
|
|
71
|
+
try:
|
|
72
|
+
return request.app.state.runs.while_idle(action)
|
|
73
|
+
except RunBusy as exc:
|
|
74
|
+
raise HTTPException(status_code=409, detail="A run is in progress; try again when it has finished") from exc
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@router.post("/{session_id}/mark-failed")
|
|
78
|
+
def mark_session_failed(session_id: str, request: Request, session: Any = Depends(get_benchmarks)) -> dict[str, Any]:
|
|
79
|
+
"""End a session whose process stopped without finishing (still running) as failed; its files stay."""
|
|
80
|
+
runs = _view(lambda: _when_idle(request, lambda: session.mark_benchmark_failed(session_id)))
|
|
81
|
+
return {"session_id": session_id, "runs_marked": runs}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@router.delete("/{session_id}")
|
|
85
|
+
def delete_session(session_id: str, request: Request, session: Any = Depends(get_benchmarks)) -> dict[str, Any]:
|
|
86
|
+
"""Delete a finished or failed session with its runs, metrics and folder."""
|
|
87
|
+
try:
|
|
88
|
+
return _view(lambda: _when_idle(request, lambda: session.delete_benchmark(session_id)))
|
|
89
|
+
except KeyError as exc:
|
|
90
|
+
raise HTTPException(status_code=404, detail=f"Benchmark session not found: {session_id}") from exc
|
|
58
91
|
|
|
59
92
|
|
|
60
93
|
@router.get("/models")
|
|
@@ -297,16 +297,39 @@ class BenchmarkSession:
|
|
|
297
297
|
order = _pipeline_order(engine)
|
|
298
298
|
return {repo: [s.to_dict() for s in sorted(steps, key=lambda s: order(s.step))] for repo, steps in stability.items()}
|
|
299
299
|
|
|
300
|
-
def list_benchmarks(
|
|
300
|
+
def list_benchmarks(
|
|
301
|
+
self,
|
|
302
|
+
limit: int = 10,
|
|
303
|
+
offset: int = 0,
|
|
304
|
+
search: str | None = None,
|
|
305
|
+
repository: str | None = None,
|
|
306
|
+
model: str | None = None,
|
|
307
|
+
status: str | None = None,
|
|
308
|
+
benchmarks_dir: str | Path | None = None,
|
|
309
|
+
) -> list[dict]:
|
|
301
310
|
"""
|
|
302
|
-
List
|
|
311
|
+
List benchmark sessions, newest first, each with the bytes its folder takes.
|
|
303
312
|
|
|
304
313
|
Args:
|
|
305
314
|
limit: Maximum number of sessions to return
|
|
315
|
+
offset: Sessions to skip (a page at a time)
|
|
316
|
+
search, repository, model, status: filters (see ``benchmarking.list_benchmark_sessions``)
|
|
306
317
|
|
|
307
318
|
Returns:
|
|
308
319
|
List of session dictionaries
|
|
309
320
|
"""
|
|
310
321
|
engine, _, _ = self.session.managers()
|
|
322
|
+
rows = benchmarking.list_benchmark_sessions(engine, limit, offset=offset, search=search, repository=repository, model=model, status=status)
|
|
323
|
+
folder = _folder(benchmarks_dir)
|
|
324
|
+
return [{**row, "bytes": benchmarking.folder_bytes(folder / str(row["session_id"]))} for row in rows]
|
|
311
325
|
|
|
312
|
-
|
|
326
|
+
def delete_benchmark(self, session_id: str, benchmarks_dir: str | Path | None = None) -> dict[str, Any]:
|
|
327
|
+
"""Delete a finished or failed session with its runs, metrics and folder."""
|
|
328
|
+
_check_session_id(session_id)
|
|
329
|
+
engine, _, _ = self.session.managers()
|
|
330
|
+
return benchmarking.delete_benchmark_session(engine, session_id, _folder(benchmarks_dir))
|
|
331
|
+
|
|
332
|
+
def prune_benchmarks(self, keep: int | None = None, failed: bool = False, benchmarks_dir: str | Path | None = None) -> list[str]:
|
|
333
|
+
"""Delete the failed sessions, or every session past the latest ``keep``; running sessions stay."""
|
|
334
|
+
engine, _, _ = self.session.managers()
|
|
335
|
+
return benchmarking.prune_benchmark_sessions(engine, _folder(benchmarks_dir), keep=keep, failed=failed)
|
|
@@ -18,7 +18,7 @@ from __future__ import annotations
|
|
|
18
18
|
import ast
|
|
19
19
|
import itertools
|
|
20
20
|
import json
|
|
21
|
-
from collections import
|
|
21
|
+
from collections import defaultdict
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from typing import Any
|
|
24
24
|
|
|
@@ -128,10 +128,11 @@ def _identity_report(views: list[dict[str, Any]], identity: str) -> dict[str, An
|
|
|
128
128
|
return [{x for x in s if keep(x)} for s in sets]
|
|
129
129
|
|
|
130
130
|
all_elements = set().union(*elements) if elements else set()
|
|
131
|
+
present = sorted({str(layer) for x in all_elements if (layer := layers.get(x)) is not None})
|
|
131
132
|
report = {
|
|
132
133
|
"elements": {"cons": _share(elements), "jbar": _jbar(elements), "count": len(all_elements)},
|
|
133
134
|
"relationships": {"cons": _share(rels), "jbar": _jbar(rels), "count": len(set().union(*rels)) if rels else 0},
|
|
134
|
-
"layers": {layer: _share(part(elements, lambda x, layer=layer: layers.get(x) == layer)) for layer in
|
|
135
|
+
"layers": {layer: _share(part(elements, lambda x, layer=layer: layers.get(x) == layer)) for layer in present},
|
|
135
136
|
"origin": {},
|
|
136
137
|
}
|
|
137
138
|
for name, wanted in (("llm", True), ("structural", False)):
|
|
@@ -174,13 +175,13 @@ def krippendorff_alpha(runs: list[dict[str, Any]]) -> float | None:
|
|
|
174
175
|
for run in runs:
|
|
175
176
|
for item, value in run.items():
|
|
176
177
|
values.setdefault(item, []).append(repr(value))
|
|
177
|
-
coincidence:
|
|
178
|
+
coincidence: dict[tuple[str, str], float] = defaultdict(float)
|
|
178
179
|
for found in values.values():
|
|
179
180
|
if len(found) < 2:
|
|
180
181
|
continue
|
|
181
182
|
for a, b in itertools.permutations(range(len(found)), 2):
|
|
182
183
|
coincidence[(found[a], found[b])] += 1 / (len(found) - 1)
|
|
183
|
-
totals:
|
|
184
|
+
totals: dict[str, float] = defaultdict(float)
|
|
184
185
|
for (a, _), n in coincidence.items():
|
|
185
186
|
totals[a] += n
|
|
186
187
|
n = sum(totals.values())
|
|
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
|