skill-evals 0.1.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.
- skill_evals-0.1.0/LICENSE +21 -0
- skill_evals-0.1.0/PKG-INFO +20 -0
- skill_evals-0.1.0/pyproject.toml +116 -0
- skill_evals-0.1.0/pyproject.toml.orig +132 -0
- skill_evals-0.1.0/src/skill_evals/__init__.py +7 -0
- skill_evals-0.1.0/src/skill_evals/cli.py +162 -0
- skill_evals-0.1.0/src/skill_evals/config.py +494 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/base.sbxenv.yaml +55 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/claude/cli/spec.yaml +32 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/claude/harness.yaml +24 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/claude/sbxenv.yaml +16 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/claude/tracing/spec.yaml +28 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/codex/cli/spec.yaml +28 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/codex/harness.yaml +17 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/codex/sbxenv.yaml +16 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/codex/tracing/files/home/.mlflow-codex/setup_tracing.py +123 -0
- skill_evals-0.1.0/src/skill_evals/harnesses/codex/tracing/spec.yaml +66 -0
- skill_evals-0.1.0/src/skill_evals/init.py +84 -0
- skill_evals-0.1.0/src/skill_evals/mlflow_server.py +140 -0
- skill_evals-0.1.0/src/skill_evals/run.py +481 -0
- skill_evals-0.1.0/src/skill_evals/schemas/config.schema.json +44 -0
- skill_evals-0.1.0/src/skill_evals/schemas/eval.schema.json +217 -0
- skill_evals-0.1.0/src/skill_evals/schemas/harness.schema.json +48 -0
- skill_evals-0.1.0/src/skill_evals/score.py +362 -0
- skill_evals-0.1.0/src/skill_evals/scorers/__init__.py +60 -0
- skill_evals-0.1.0/src/skill_evals/scorers/answers.py +37 -0
- skill_evals-0.1.0/src/skill_evals/scorers/skills.py +61 -0
- skill_evals-0.1.0/src/skill_evals/traces/__init__.py +49 -0
- skill_evals-0.1.0/src/skill_evals/traces/base.py +150 -0
- skill_evals-0.1.0/src/skill_evals/traces/claude.py +55 -0
- skill_evals-0.1.0/src/skill_evals/traces/codex.py +45 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Max van den Hoven
|
|
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.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: skill-evals
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Evaluate how coding-agent harnesses load and follow skills, in Docker sandboxes, traced with MLflow.
|
|
5
|
+
Author: Max van den Hoven
|
|
6
|
+
Author-email: Max van den Hoven <max.hoven@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Software Development :: Testing
|
|
16
|
+
Requires-Dist: jsonschema>=4.26.0
|
|
17
|
+
Requires-Dist: mlflow>=3.17
|
|
18
|
+
Requires-Dist: pandas>=3.0.6
|
|
19
|
+
Requires-Dist: pyyaml>=6
|
|
20
|
+
Requires-Python: >=3.12
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "skill-evals"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Evaluate how coding-agent harnesses load and follow skills, in Docker sandboxes, traced with MLflow."
|
|
5
|
+
license = "MIT"
|
|
6
|
+
license-files = ["LICENSE"]
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Development Status :: 3 - Alpha",
|
|
9
|
+
"Environment :: Console",
|
|
10
|
+
"Intended Audience :: Developers",
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Programming Language :: Python :: 3.12",
|
|
13
|
+
"Programming Language :: Python :: 3.13",
|
|
14
|
+
"Topic :: Software Development :: Testing",
|
|
15
|
+
]
|
|
16
|
+
requires-python = ">=3.12"
|
|
17
|
+
dependencies = [
|
|
18
|
+
"jsonschema>=4.26.0",
|
|
19
|
+
"mlflow>=3.17",
|
|
20
|
+
"pandas>=3.0.6",
|
|
21
|
+
"pyyaml>=6",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[[project.authors]]
|
|
25
|
+
name = "Max van den Hoven"
|
|
26
|
+
email = "max.hoven@gmail.com"
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
skill-evals = "skill_evals.cli:main"
|
|
30
|
+
|
|
31
|
+
[build-system]
|
|
32
|
+
requires = ["uv_build>=0.11.2,<0.12.0"]
|
|
33
|
+
build-backend = "uv_build"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"commitizen>=4.19.2",
|
|
38
|
+
"pre-commit>=4.6.2",
|
|
39
|
+
"pytest>=9.1.1",
|
|
40
|
+
"pytest-cov>=7.1.0",
|
|
41
|
+
"ruff>=0.17.0",
|
|
42
|
+
"ty>=0.0.86",
|
|
43
|
+
"types-jsonschema>=4.26.0.20261006",
|
|
44
|
+
"yamllint>=1.38.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
addopts = "-m 'not integration'"
|
|
50
|
+
strict_markers = true
|
|
51
|
+
markers = ["integration: needs sbx and Docker login, no model credentials; not run by default"]
|
|
52
|
+
|
|
53
|
+
[tool.ty.environment]
|
|
54
|
+
python-version = "3.12"
|
|
55
|
+
|
|
56
|
+
[tool.ty.src]
|
|
57
|
+
include = [
|
|
58
|
+
"src/**",
|
|
59
|
+
"example/scorers/**",
|
|
60
|
+
"tests/**",
|
|
61
|
+
]
|
|
62
|
+
exclude = ["example/fixtures/**"]
|
|
63
|
+
|
|
64
|
+
[tool.ruff]
|
|
65
|
+
line-length = 90
|
|
66
|
+
indent-width = 4
|
|
67
|
+
force-exclude = true
|
|
68
|
+
extend-exclude = [
|
|
69
|
+
".runs",
|
|
70
|
+
".mlflow",
|
|
71
|
+
"example/fixtures",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[tool.ruff.lint]
|
|
75
|
+
preview = true
|
|
76
|
+
explicit-preview-rules = true
|
|
77
|
+
select = [
|
|
78
|
+
"B",
|
|
79
|
+
"D",
|
|
80
|
+
"E",
|
|
81
|
+
"F",
|
|
82
|
+
"I",
|
|
83
|
+
"EM",
|
|
84
|
+
"T20",
|
|
85
|
+
"RET",
|
|
86
|
+
"ANN",
|
|
87
|
+
"DOC201",
|
|
88
|
+
"DOC202",
|
|
89
|
+
"DOC402",
|
|
90
|
+
"DOC501",
|
|
91
|
+
"DOC502",
|
|
92
|
+
]
|
|
93
|
+
ignore = [
|
|
94
|
+
"D100",
|
|
95
|
+
"D104",
|
|
96
|
+
"D203",
|
|
97
|
+
"D213",
|
|
98
|
+
"D400",
|
|
99
|
+
"D413",
|
|
100
|
+
"ANN002",
|
|
101
|
+
"ANN003",
|
|
102
|
+
"ANN401",
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
[tool.ruff.lint.per-file-ignores]
|
|
106
|
+
"src/skill_evals/{cli,run,score,init,mlflow_server}.py" = ["T201"]
|
|
107
|
+
"tests/record_trace.py" = ["T201"]
|
|
108
|
+
"src/skill_evals/harnesses/codex/tracing/files/home/.mlflow-codex/setup_tracing.py" = ["T201"]
|
|
109
|
+
|
|
110
|
+
[tool.ruff.lint.pydocstyle]
|
|
111
|
+
convention = "google"
|
|
112
|
+
|
|
113
|
+
[tool.commitizen]
|
|
114
|
+
name = "cz_conventional_commits"
|
|
115
|
+
version_provider = "uv"
|
|
116
|
+
tag_format = "v$version"
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# The `skill-evals` command (src/skill_evals/). It runs on the host; the only Python
|
|
2
|
+
# that runs inside sandboxes is the Codex tracing helper of the shipped harnesses
|
|
3
|
+
# (harnesses/codex/tracing/files/home/.mlflow-codex/setup_tracing.py). The example
|
|
4
|
+
# project in example/ isn't part of the package.
|
|
5
|
+
[project]
|
|
6
|
+
name = "skill-evals"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Evaluate how coding-agent harnesses load and follow skills, in Docker sandboxes, traced with MLflow."
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Max van den Hoven", email = "max.hoven@gmail.com" },
|
|
11
|
+
]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Software Development :: Testing",
|
|
22
|
+
]
|
|
23
|
+
requires-python = ">=3.12"
|
|
24
|
+
dependencies = [
|
|
25
|
+
"jsonschema>=4.26.0", # Validates project files against the packaged schemas
|
|
26
|
+
"mlflow>=3.17", # Tracking server, trace search and mlflow.genai.evaluate
|
|
27
|
+
"pandas>=3.0.6", # Trace tables from mlflow.search_traces
|
|
28
|
+
"pyyaml>=6", # Reads project files
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
skill-evals = "skill_evals.cli:main"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["uv_build>=0.11.2,<0.12.0"]
|
|
36
|
+
build-backend = "uv_build"
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"commitizen>=4.19.2",
|
|
41
|
+
"pre-commit>=4.6.2",
|
|
42
|
+
"pytest>=9.1.1",
|
|
43
|
+
"pytest-cov>=7.1.0",
|
|
44
|
+
"ruff>=0.17.0",
|
|
45
|
+
"ty>=0.0.86",
|
|
46
|
+
"types-jsonschema>=4.26.0.20261006",
|
|
47
|
+
"yamllint>=1.38.0",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
# Unit tests: no sbx, Docker, network, model credentials or MLflow server. Run them
|
|
51
|
+
# with `make test`, which adds a coverage report.
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
testpaths = ["tests"]
|
|
54
|
+
addopts = "-m 'not integration'"
|
|
55
|
+
strict_markers = true
|
|
56
|
+
markers = [
|
|
57
|
+
"integration: needs sbx and Docker login, no model credentials; not run by default",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.ty.environment]
|
|
61
|
+
python-version = "3.12" # The oldest supported version
|
|
62
|
+
|
|
63
|
+
[tool.ty.src]
|
|
64
|
+
include = [
|
|
65
|
+
"src/**",
|
|
66
|
+
"example/scorers/**",
|
|
67
|
+
"tests/**",
|
|
68
|
+
]
|
|
69
|
+
# Fixture files are test material for the agents (e.g. deliberately without docstrings).
|
|
70
|
+
exclude = [
|
|
71
|
+
"example/fixtures/**",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[tool.ruff]
|
|
75
|
+
line-length = 90
|
|
76
|
+
indent-width = 4
|
|
77
|
+
force-exclude = true # Also skip excluded files that pre-commit passes explicitly
|
|
78
|
+
extend-exclude = [
|
|
79
|
+
".runs",
|
|
80
|
+
".mlflow",
|
|
81
|
+
"example/fixtures", # Test material for the agents, not our code
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[tool.ruff.lint]
|
|
85
|
+
# The DOC (pydoclint) rules are preview-only; enable exactly those, nothing else in preview.
|
|
86
|
+
preview = true
|
|
87
|
+
explicit-preview-rules = true
|
|
88
|
+
select = [
|
|
89
|
+
"B", # flake8-bugbear
|
|
90
|
+
"D", # pydocstyle
|
|
91
|
+
"E", # pycodestyle
|
|
92
|
+
"F", # pyflakes
|
|
93
|
+
"I", # isort
|
|
94
|
+
"EM", # flake8-errmsg
|
|
95
|
+
"T20", # flake8-print
|
|
96
|
+
"RET", # flake8-return
|
|
97
|
+
"ANN", # flake8-annotations
|
|
98
|
+
"DOC201", # pydoclint: return value not documented in docstring
|
|
99
|
+
"DOC202", # pydoclint: docstring documents a return value the function lacks
|
|
100
|
+
"DOC402", # pydoclint: yield value not documented in docstring
|
|
101
|
+
"DOC501", # pydoclint: raised exception not documented in docstring
|
|
102
|
+
"DOC502", # pydoclint: docstring documents an exception that is not raised
|
|
103
|
+
]
|
|
104
|
+
ignore = [
|
|
105
|
+
"D100", # Ignore missing docstring in public module
|
|
106
|
+
"D104", # Ignore missing docstring in public package
|
|
107
|
+
"D203", # Ignore one blank line before class docstring
|
|
108
|
+
"D213", # Ignore multi-line docstring start on second line
|
|
109
|
+
"D400", # Ignore missing period in docstring first line (also captured by D415)
|
|
110
|
+
"D413", # Ignore missing newline after final section in docstring
|
|
111
|
+
"ANN002", # Ignore missing *args type annotations
|
|
112
|
+
"ANN003", # Ignore missing **kwargs type annotations
|
|
113
|
+
"ANN401", # Ignore Any type annotations
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
[tool.ruff.lint.per-file-ignores]
|
|
117
|
+
# Command-line code: printing is its output, not leftover debugging.
|
|
118
|
+
"src/skill_evals/{cli,run,score,init,mlflow_server}.py" = ["T201"]
|
|
119
|
+
"tests/record_trace.py" = ["T201"]
|
|
120
|
+
"src/skill_evals/harnesses/codex/tracing/files/home/.mlflow-codex/setup_tracing.py" = [
|
|
121
|
+
"T201",
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
[tool.ruff.lint.pydocstyle]
|
|
125
|
+
convention = "google"
|
|
126
|
+
|
|
127
|
+
# Pull request titles follow Conventional Commits (feat:, fix:, docs:, ...), and squash
|
|
128
|
+
# merges make them the commit messages. `cz bump` reads them to pick the next version.
|
|
129
|
+
[tool.commitizen]
|
|
130
|
+
name = "cz_conventional_commits"
|
|
131
|
+
version_provider = "uv"
|
|
132
|
+
tag_format = "v$version"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Evaluate whether coding agents load and follow skills, in Docker Sandboxes.
|
|
2
|
+
|
|
3
|
+
The `skill-evals` command (see cli.py) runs evals in sandboxes (run.py) and scores
|
|
4
|
+
their MLflow traces (score.py, with the scorers in scorers/ and the per-harness trace
|
|
5
|
+
readers in traces/). What it runs comes from the project that .skill-evals.yaml
|
|
6
|
+
describes (config.py); `skill-evals init` creates one with the shipped harnesses/.
|
|
7
|
+
"""
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""skill-evals: test whether coding agents load and follow your skills.
|
|
2
|
+
|
|
3
|
+
skill-evals init [DIR] Set up a project (.skill-evals.yaml + folders)
|
|
4
|
+
skill-evals evaluate Run the evals, then score them (run + score)
|
|
5
|
+
skill-evals run Run evals in sandboxes
|
|
6
|
+
skill-evals score Score runs' traces; check thresholds
|
|
7
|
+
skill-evals validate Check the project's eval and harness files
|
|
8
|
+
skill-evals mlflow Open the MLflow server (UI) on the project's store
|
|
9
|
+
|
|
10
|
+
run, score and evaluate start an MLflow server for their duration if none is up.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import sys
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from skill_evals import init, mlflow_server, run, score
|
|
19
|
+
from skill_evals.config import (
|
|
20
|
+
discover_evals,
|
|
21
|
+
discover_harnesses,
|
|
22
|
+
eval_cases,
|
|
23
|
+
load_harness,
|
|
24
|
+
use_config,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# A subcommand's function: takes the parsed options, returns an exit code (or, like
|
|
28
|
+
# `run`, something else that counts as success).
|
|
29
|
+
Handler = Callable[[argparse.Namespace], object]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def validate(args: argparse.Namespace) -> int:
|
|
33
|
+
"""Validate every eval file and harness.yaml.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
args: The parsed options; `validate` has none of its own.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The exit code, 0 (invalid files stop with a message instead).
|
|
40
|
+
"""
|
|
41
|
+
del args # Every subcommand takes the parsed options; this one has none
|
|
42
|
+
evals, harnesses = discover_evals(), discover_harnesses()
|
|
43
|
+
for name in evals:
|
|
44
|
+
eval_cases(name) # Validates the file and resolves fixtures and scorers
|
|
45
|
+
for name in harnesses:
|
|
46
|
+
load_harness(name)
|
|
47
|
+
print(f"valid: {len(evals)} eval(s), {len(harnesses)} harness(es)")
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def evaluate(args: argparse.Namespace) -> int:
|
|
52
|
+
"""Run the selected evals, then score exactly that run.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
args: The parsed options of `run` plus the threshold options of `score`.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The exit code of the scoring: 1 if a threshold was missed, else 0.
|
|
59
|
+
"""
|
|
60
|
+
args.stamp = run.main(args)
|
|
61
|
+
return score.main(args)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def serve(args: argparse.Namespace) -> int:
|
|
65
|
+
"""Run the MLflow server in the foreground.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
args: The parsed options; `mlflow` has none of its own.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The exit code, 0.
|
|
72
|
+
"""
|
|
73
|
+
del args # Every subcommand takes the parsed options; this one has none
|
|
74
|
+
mlflow_server.serve()
|
|
75
|
+
return 0
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _with_mlflow(handler: Handler) -> Handler:
|
|
79
|
+
"""Wrap a subcommand so an MLflow server runs while it does.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
handler: The subcommand's function, taking the parsed options.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
A function with the same signature.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def wrapped(args: argparse.Namespace) -> int:
|
|
89
|
+
"""Run the wrapped subcommand inside `mlflow_server.running`.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
args: The parsed options.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
The subcommand's exit code; a non-integer result counts as 0.
|
|
96
|
+
"""
|
|
97
|
+
with mlflow_server.running():
|
|
98
|
+
result = handler(args)
|
|
99
|
+
return result if isinstance(result, int) else 0
|
|
100
|
+
|
|
101
|
+
return wrapped
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
105
|
+
"""Build the command-line parser with every subcommand.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The parser; each subcommand sets `handler`.
|
|
109
|
+
"""
|
|
110
|
+
fmt = argparse.RawDescriptionHelpFormatter
|
|
111
|
+
ap = argparse.ArgumentParser(
|
|
112
|
+
prog="skill-evals", description=__doc__, formatter_class=fmt
|
|
113
|
+
)
|
|
114
|
+
ap.add_argument(
|
|
115
|
+
"--config",
|
|
116
|
+
type=Path,
|
|
117
|
+
help="the project's .skill-evals.yaml (default: the nearest one above the "
|
|
118
|
+
"current folder)",
|
|
119
|
+
)
|
|
120
|
+
sub = ap.add_subparsers(required=True, metavar="COMMAND")
|
|
121
|
+
|
|
122
|
+
p = sub.add_parser(
|
|
123
|
+
"init", help="set up a project", description=init.__doc__, formatter_class=fmt
|
|
124
|
+
)
|
|
125
|
+
p.add_argument(
|
|
126
|
+
"dir", nargs="?", default="skill-evals", help="folder (default: skill-evals)"
|
|
127
|
+
)
|
|
128
|
+
p.set_defaults(handler=init.main)
|
|
129
|
+
|
|
130
|
+
p = sub.add_parser(
|
|
131
|
+
"evaluate", help="run, then score that run", description=evaluate.__doc__
|
|
132
|
+
)
|
|
133
|
+
run.add_arguments(p)
|
|
134
|
+
score.add_threshold_arguments(p)
|
|
135
|
+
p.set_defaults(handler=_with_mlflow(evaluate))
|
|
136
|
+
|
|
137
|
+
p = sub.add_parser(
|
|
138
|
+
"run", help="run evals in sandboxes", description=run.__doc__, formatter_class=fmt
|
|
139
|
+
)
|
|
140
|
+
run.add_arguments(p)
|
|
141
|
+
p.set_defaults(handler=_with_mlflow(run.main))
|
|
142
|
+
|
|
143
|
+
p = sub.add_parser(
|
|
144
|
+
"score", help="score runs' traces", description=score.__doc__, formatter_class=fmt
|
|
145
|
+
)
|
|
146
|
+
score.add_arguments(p)
|
|
147
|
+
p.set_defaults(handler=_with_mlflow(score.main))
|
|
148
|
+
|
|
149
|
+
p = sub.add_parser("validate", help="check eval and harness files")
|
|
150
|
+
p.set_defaults(handler=validate)
|
|
151
|
+
|
|
152
|
+
p = sub.add_parser("mlflow", help="open the MLflow server (UI) in the foreground")
|
|
153
|
+
p.set_defaults(handler=serve)
|
|
154
|
+
return ap
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def main() -> None:
|
|
158
|
+
"""Parse the command line and run the chosen subcommand."""
|
|
159
|
+
args = build_parser().parse_args()
|
|
160
|
+
use_config(args.config)
|
|
161
|
+
code = args.handler(args)
|
|
162
|
+
sys.exit(code if isinstance(code, int) else 0)
|