pytest-skill-engineering 0.6.22__tar.gz → 1.0.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.
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/.gitignore +63 -65
- pytest_skill_engineering-1.0.0/PKG-INFO +182 -0
- pytest_skill_engineering-1.0.0/README.md +134 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/pyproject.toml +28 -35
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/__init__.py +3 -37
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/api.py +1 -3
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/client.py +1 -1
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/contracts.py +0 -8
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/controls.py +83 -9
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/eval.py +0 -4
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/fixtures.py +3 -5
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/requests.py +34 -1
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/runner.py +49 -66
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/__init__.py +0 -26
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/evals.py +6 -6
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/prompt.py +2 -2
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/result.py +14 -28
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/serialization.py +3 -2
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/skill_evals.py +3 -12
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/skill_grading.py +2 -8
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/servers.py +1 -1
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/fixtures/__init__.py +0 -10
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/fixtures/factories.py +2 -2
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/onboarding.py +23 -8
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/plugin.py +18 -114
- pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/plugin_options.py +32 -0
- pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/plugin_report.py +18 -0
- pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/reporting/__init__.py +16 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/reporting/collector.py +12 -8
- pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/reporting/generator.py +55 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/reporting/schema.py +1 -1
- pytest_skill_engineering-0.6.22/PKG-INFO +0 -211
- pytest_skill_engineering-0.6.22/README.md +0 -159
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/cli.py +0 -401
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/copilot/judge.py +0 -186
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/scoring.py +0 -68
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/skill_benchmark.py +0 -158
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/skill_eval_results.py +0 -46
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/skill_refiner.py +0 -241
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/llm_assert.py +0 -129
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/llm_score.py +0 -267
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/skill_benchmark.py +0 -204
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/skill_eval.py +0 -201
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/skill_refine.py +0 -99
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/hooks.py +0 -40
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/plugin_options.py +0 -115
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/plugin_recording.py +0 -77
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/plugin_report.py +0 -262
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/prompts/__init__.py +0 -24
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/prompts/ai_summary.md +0 -398
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/prompts/coding_agent_analysis.md +0 -361
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/__init__.py +0 -30
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/__init__.py +0 -23
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/agent_leaderboard.py +0 -142
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/agent_selector.py +0 -58
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/overlay.py +0 -39
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/report.py +0 -482
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/test_comparison.py +0 -384
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/test_grid.py +0 -333
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/types.py +0 -199
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/generator.py +0 -680
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/identity.py +0 -64
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/insights.py +0 -713
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/markdown.py +0 -498
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/templates/partials/report.css +0 -1002
- pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/templates/partials/scripts.js +0 -89
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/LICENSE +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/__init__.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/config.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/events.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/personas.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/result.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/errors.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/plugin.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/skill.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/__init__.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/cost.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/rate_limiter.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/skill_tools.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/fixtures/iteration.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/__init__.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/banking.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/banking_mcp.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/todo.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/todo_mcp.py +0 -0
- {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/types.py +0 -0
|
@@ -1,67 +1,65 @@
|
|
|
1
|
-
# Python
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*$py.class
|
|
5
|
-
*.so
|
|
6
|
-
.Python
|
|
7
|
-
build/
|
|
8
|
-
develop-eggs/
|
|
9
|
-
dist/
|
|
10
|
-
downloads/
|
|
11
|
-
eggs/
|
|
12
|
-
.eggs/
|
|
13
|
-
lib/
|
|
14
|
-
lib64/
|
|
15
|
-
parts/
|
|
16
|
-
sdist/
|
|
17
|
-
var/
|
|
18
|
-
wheels/
|
|
19
|
-
*.egg-info/
|
|
20
|
-
.installed.cfg
|
|
21
|
-
*.egg
|
|
22
|
-
|
|
23
|
-
# Virtual environments
|
|
24
|
-
.venv/
|
|
25
|
-
venv/
|
|
26
|
-
ENV/
|
|
27
|
-
env/
|
|
28
|
-
|
|
29
|
-
# IDE
|
|
30
|
-
.idea/
|
|
31
|
-
.vscode/
|
|
32
|
-
*.swp
|
|
33
|
-
*.swo
|
|
34
|
-
*~
|
|
35
|
-
|
|
36
|
-
# Testing
|
|
37
|
-
.pytest_cache/
|
|
38
|
-
.coverage
|
|
39
|
-
htmlcov/
|
|
40
|
-
.tox/
|
|
41
|
-
.nox/
|
|
42
|
-
|
|
43
|
-
# Type checking
|
|
44
|
-
.mypy_cache/
|
|
45
|
-
|
|
46
|
-
# Test outputs
|
|
47
|
-
test_results/
|
|
48
|
-
aitest-reports/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
site/
|
|
64
|
-
.cache/
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
env/
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
*~
|
|
35
|
+
|
|
36
|
+
# Testing
|
|
37
|
+
.pytest_cache/
|
|
38
|
+
.coverage
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.nox/
|
|
42
|
+
|
|
43
|
+
# Type checking
|
|
44
|
+
.mypy_cache/
|
|
45
|
+
|
|
46
|
+
# Test outputs
|
|
47
|
+
test_results/
|
|
48
|
+
aitest-reports/
|
|
49
|
+
|
|
50
|
+
# Node.js
|
|
51
|
+
node_modules/
|
|
52
|
+
package-lock.json
|
|
53
|
+
|
|
54
|
+
# Environment
|
|
55
|
+
.env
|
|
56
|
+
.env.local
|
|
57
|
+
|
|
58
|
+
# OS
|
|
59
|
+
.DS_Store
|
|
60
|
+
Thumbs.db
|
|
61
|
+
site/
|
|
62
|
+
.cache/
|
|
65
63
|
# Squad: ignore runtime state (logs, inbox, sessions)
|
|
66
64
|
.squad/orchestration-log/
|
|
67
65
|
.squad/log/
|
|
@@ -71,4 +69,4 @@ site/
|
|
|
71
69
|
.squad-workstream
|
|
72
70
|
|
|
73
71
|
# pytest-skill-engineering test scratch (some server tests create a cwd dir)
|
|
74
|
-
.pytest-execution-servers/
|
|
72
|
+
.pytest-execution-servers/
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pytest-skill-engineering
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Reliable Copilot execution and evidence for coding-agent-led testing of MCP servers, CLI tools, skills, and custom agents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/sbroenne/pytest-skill-engineering
|
|
6
|
+
Project-URL: Repository, https://github.com/sbroenne/pytest-skill-engineering
|
|
7
|
+
Author: Stefan Brunner
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agents,ai,custom-agents,llm,mcp,pytest,skill-engineering,skills,testing
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Framework :: Pytest
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: github-copilot-sdk>=1.0.16
|
|
23
|
+
Requires-Dist: httpx>=0.28.1
|
|
24
|
+
Requires-Dist: mcp>=2.2.0
|
|
25
|
+
Requires-Dist: pydantic>=2.13.5
|
|
26
|
+
Requires-Dist: pytest-asyncio>=1.4.0
|
|
27
|
+
Requires-Dist: pytest>=9.1.1
|
|
28
|
+
Requires-Dist: python-frontmatter>=1.3.0
|
|
29
|
+
Requires-Dist: tomlkit>=0.15.1
|
|
30
|
+
Requires-Dist: trio>=0.34.0
|
|
31
|
+
Requires-Dist: websockets>=17.1
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pre-commit>=4.6.2; extra == 'dev'
|
|
34
|
+
Requires-Dist: pyright>=1.1.414; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov>=7.1.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: python-dotenv>=1.2.3; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.16.9; extra == 'dev'
|
|
38
|
+
Requires-Dist: typeguard>=4.6.0; extra == 'dev'
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: cairosvg>=2.9.1; extra == 'docs'
|
|
41
|
+
Requires-Dist: mkdocs-material<9.8,>=9.7.7; extra == 'docs'
|
|
42
|
+
Requires-Dist: mkdocs>=1.6.1; extra == 'docs'
|
|
43
|
+
Requires-Dist: mkdocstrings[python]>=1.0.6; extra == 'docs'
|
|
44
|
+
Requires-Dist: pillow>=12.3.0; extra == 'docs'
|
|
45
|
+
Provides-Extra: test
|
|
46
|
+
Requires-Dist: syrupy<7,>=6.1.1; extra == 'test'
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# pytest-skill-engineering
|
|
50
|
+
|
|
51
|
+
[](https://pypi.org/project/pytest-skill-engineering/)
|
|
52
|
+
[](https://github.com/sbroenne/pytest-skill-engineering/actions/workflows/ci.yml)
|
|
53
|
+
[](LICENSE)
|
|
54
|
+
|
|
55
|
+
**A test runner for people working with coding agents.**
|
|
56
|
+
|
|
57
|
+
Test whether real GitHub Copilot sessions can use your MCP servers, CLI tools,
|
|
58
|
+
skills, system prompts, and custom agents. Write a user task, execute it through
|
|
59
|
+
pytest, and verify the actual output with ordinary assertions.
|
|
60
|
+
|
|
61
|
+
The framework runs the task and records what happened. Your existing coding agent
|
|
62
|
+
investigates the evidence, reads the source, and helps you improve the interface.
|
|
63
|
+
**Version 1.0 removes AI judging, report dashboards, rankings, and skill refinement.**
|
|
64
|
+
See the [migration guide](docs/migration.md) for this breaking change.
|
|
65
|
+
|
|
66
|
+
## Why this exists
|
|
67
|
+
|
|
68
|
+
Your tool can pass its own tests while Copilot chooses the wrong operation,
|
|
69
|
+
supplies the wrong arguments, or misunderstands its descriptions. That is a
|
|
70
|
+
different question from whether the tool implementation works.
|
|
71
|
+
|
|
72
|
+
Use real task execution to test the AI-facing interface, and independent output
|
|
73
|
+
checks to establish correctness. A completed session or a tool call by itself
|
|
74
|
+
does not prove that the requested task succeeded.
|
|
75
|
+
|
|
76
|
+
## Quick start
|
|
77
|
+
|
|
78
|
+
You need Python 3.11+, [uv](https://docs.astral.sh/uv/), and a GitHub account with
|
|
79
|
+
Copilot access.
|
|
80
|
+
|
|
81
|
+
```powershell
|
|
82
|
+
uv add pytest-skill-engineering
|
|
83
|
+
gh auth login --hostname github.com
|
|
84
|
+
uv run pytest-skill-engineering init
|
|
85
|
+
uv run pytest-skill-engineering doctor
|
|
86
|
+
uv run python -m pytest "tests\test_copilot_eval.py" -v
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`init` creates a Todo MCP starter test, explicit JSON evidence settings, and
|
|
90
|
+
explicit starter-model rates in `pricing.toml`. It refuses conflicting settings
|
|
91
|
+
or an existing starter. Live execution can consume Copilot premium requests.
|
|
92
|
+
|
|
93
|
+
pytest shows ordinary test results and assertion failures. Give your coding
|
|
94
|
+
agent `aitest-reports\results.json` and the relevant source to investigate what
|
|
95
|
+
happened. No dashboard or second AI judgment is generated.
|
|
96
|
+
|
|
97
|
+
## What we learned by testing our own idea
|
|
98
|
+
|
|
99
|
+
We evaluated a companion skill for coding agents using this framework and chose
|
|
100
|
+
not to ship it. The comparison did not demonstrate a benefit; adding general
|
|
101
|
+
test-writing advice was not evidence that users needed another product layer.
|
|
102
|
+
Use the documentation, examples, and native evidence directly.
|
|
103
|
+
|
|
104
|
+
The [case study](docs/use-cases/companion-skill.md) records the actual results,
|
|
105
|
+
failures, limitations, and removal decision. Its
|
|
106
|
+
[historical experiment](examples/skill-dogfood/) remains reproducible with a
|
|
107
|
+
frozen test fixture, not an installable companion skill. Default sample checks
|
|
108
|
+
are offline; live execution is explicit. The [quickstart](examples/quickstart/)
|
|
109
|
+
is the smaller first example.
|
|
110
|
+
|
|
111
|
+
Testing your own domain skills remains a supported framework capability.
|
|
112
|
+
|
|
113
|
+
## A test that checks the result
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from __future__ import annotations
|
|
117
|
+
|
|
118
|
+
import subprocess
|
|
119
|
+
import sys
|
|
120
|
+
|
|
121
|
+
from pytest_skill_engineering.copilot import CopilotEval
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
async def test_addition(copilot_eval, tmp_path):
|
|
125
|
+
agent = CopilotEval(
|
|
126
|
+
name="addition",
|
|
127
|
+
model="gpt-5.6-luna",
|
|
128
|
+
instructions="Write Python code and save the requested file.",
|
|
129
|
+
working_directory=str(tmp_path),
|
|
130
|
+
)
|
|
131
|
+
result = await copilot_eval(agent, "Create calc.py with add(a, b) returning a + b.")
|
|
132
|
+
assert result.success, result.error
|
|
133
|
+
assert (tmp_path / "calc.py").is_file()
|
|
134
|
+
checked = subprocess.run(
|
|
135
|
+
[
|
|
136
|
+
sys.executable,
|
|
137
|
+
"-c",
|
|
138
|
+
"from calc import add; assert add(2, 3) == 5; assert add(-2, 2) == 0",
|
|
139
|
+
],
|
|
140
|
+
cwd=tmp_path,
|
|
141
|
+
capture_output=True,
|
|
142
|
+
text=True,
|
|
143
|
+
timeout=10,
|
|
144
|
+
)
|
|
145
|
+
assert checked.returncode == 0, checked.stderr
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Use your approved isolation when executing generated code. A temporary directory
|
|
149
|
+
is not a security sandbox.
|
|
150
|
+
|
|
151
|
+
## What stays in the framework
|
|
152
|
+
|
|
153
|
+
| Capability | What it provides |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| `CopilotEval` and `copilot_eval` | Real SDK sessions with explicit configuration |
|
|
156
|
+
| MCP, CLI, skills, plugins, custom agents | The interfaces and definitions under test |
|
|
157
|
+
| Execution controls | Time, usage, request, tool, and permission controls; one attempt per execution |
|
|
158
|
+
| Captured evidence | Configuration, calls, arguments, outputs, completion flags, errors, and usage |
|
|
159
|
+
| Ordinary pytest checks | Consumer-owned verification and recorded properties |
|
|
160
|
+
| `ab_run` and repetitions | Isolated working directories and repeated observations |
|
|
161
|
+
| Structured JSON | Captured execution and ordinary pytest outcomes, without rankings or advice |
|
|
162
|
+
| Pricing | Explicit USD estimates and recorded Copilot premium requests |
|
|
163
|
+
|
|
164
|
+
A/B entries share one pytest outcome. Record side-specific checks; do not read
|
|
165
|
+
that shared outcome as independent per-side success or causal improvement.
|
|
166
|
+
Missing prices and incomplete evidence are recorded explicitly.
|
|
167
|
+
|
|
168
|
+
## Let your coding agent investigate
|
|
169
|
+
|
|
170
|
+
Ask your existing coding agent to inspect a failed test, its saved JSON evidence,
|
|
171
|
+
and the source. It can explain the supported cause and help fix it, without
|
|
172
|
+
changing the test's success criteria after seeing the failure.
|
|
173
|
+
|
|
174
|
+
Reading current schema-4.0 evidence needs no authentication or paid call.
|
|
175
|
+
The framework records results; the coding agent interprets them. Subjective
|
|
176
|
+
review is advice, not an automatic pytest verdict.
|
|
177
|
+
|
|
178
|
+
Read the [full documentation](https://sbroenne.github.io/pytest-skill-engineering/).
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT. Inspired by [agent-benchmark](https://github.com/mykhaliev/agent-benchmark).
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# pytest-skill-engineering
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/pytest-skill-engineering/)
|
|
4
|
+
[](https://github.com/sbroenne/pytest-skill-engineering/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
**A test runner for people working with coding agents.**
|
|
8
|
+
|
|
9
|
+
Test whether real GitHub Copilot sessions can use your MCP servers, CLI tools,
|
|
10
|
+
skills, system prompts, and custom agents. Write a user task, execute it through
|
|
11
|
+
pytest, and verify the actual output with ordinary assertions.
|
|
12
|
+
|
|
13
|
+
The framework runs the task and records what happened. Your existing coding agent
|
|
14
|
+
investigates the evidence, reads the source, and helps you improve the interface.
|
|
15
|
+
**Version 1.0 removes AI judging, report dashboards, rankings, and skill refinement.**
|
|
16
|
+
See the [migration guide](docs/migration.md) for this breaking change.
|
|
17
|
+
|
|
18
|
+
## Why this exists
|
|
19
|
+
|
|
20
|
+
Your tool can pass its own tests while Copilot chooses the wrong operation,
|
|
21
|
+
supplies the wrong arguments, or misunderstands its descriptions. That is a
|
|
22
|
+
different question from whether the tool implementation works.
|
|
23
|
+
|
|
24
|
+
Use real task execution to test the AI-facing interface, and independent output
|
|
25
|
+
checks to establish correctness. A completed session or a tool call by itself
|
|
26
|
+
does not prove that the requested task succeeded.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
You need Python 3.11+, [uv](https://docs.astral.sh/uv/), and a GitHub account with
|
|
31
|
+
Copilot access.
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
uv add pytest-skill-engineering
|
|
35
|
+
gh auth login --hostname github.com
|
|
36
|
+
uv run pytest-skill-engineering init
|
|
37
|
+
uv run pytest-skill-engineering doctor
|
|
38
|
+
uv run python -m pytest "tests\test_copilot_eval.py" -v
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`init` creates a Todo MCP starter test, explicit JSON evidence settings, and
|
|
42
|
+
explicit starter-model rates in `pricing.toml`. It refuses conflicting settings
|
|
43
|
+
or an existing starter. Live execution can consume Copilot premium requests.
|
|
44
|
+
|
|
45
|
+
pytest shows ordinary test results and assertion failures. Give your coding
|
|
46
|
+
agent `aitest-reports\results.json` and the relevant source to investigate what
|
|
47
|
+
happened. No dashboard or second AI judgment is generated.
|
|
48
|
+
|
|
49
|
+
## What we learned by testing our own idea
|
|
50
|
+
|
|
51
|
+
We evaluated a companion skill for coding agents using this framework and chose
|
|
52
|
+
not to ship it. The comparison did not demonstrate a benefit; adding general
|
|
53
|
+
test-writing advice was not evidence that users needed another product layer.
|
|
54
|
+
Use the documentation, examples, and native evidence directly.
|
|
55
|
+
|
|
56
|
+
The [case study](docs/use-cases/companion-skill.md) records the actual results,
|
|
57
|
+
failures, limitations, and removal decision. Its
|
|
58
|
+
[historical experiment](examples/skill-dogfood/) remains reproducible with a
|
|
59
|
+
frozen test fixture, not an installable companion skill. Default sample checks
|
|
60
|
+
are offline; live execution is explicit. The [quickstart](examples/quickstart/)
|
|
61
|
+
is the smaller first example.
|
|
62
|
+
|
|
63
|
+
Testing your own domain skills remains a supported framework capability.
|
|
64
|
+
|
|
65
|
+
## A test that checks the result
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from __future__ import annotations
|
|
69
|
+
|
|
70
|
+
import subprocess
|
|
71
|
+
import sys
|
|
72
|
+
|
|
73
|
+
from pytest_skill_engineering.copilot import CopilotEval
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
async def test_addition(copilot_eval, tmp_path):
|
|
77
|
+
agent = CopilotEval(
|
|
78
|
+
name="addition",
|
|
79
|
+
model="gpt-5.6-luna",
|
|
80
|
+
instructions="Write Python code and save the requested file.",
|
|
81
|
+
working_directory=str(tmp_path),
|
|
82
|
+
)
|
|
83
|
+
result = await copilot_eval(agent, "Create calc.py with add(a, b) returning a + b.")
|
|
84
|
+
assert result.success, result.error
|
|
85
|
+
assert (tmp_path / "calc.py").is_file()
|
|
86
|
+
checked = subprocess.run(
|
|
87
|
+
[
|
|
88
|
+
sys.executable,
|
|
89
|
+
"-c",
|
|
90
|
+
"from calc import add; assert add(2, 3) == 5; assert add(-2, 2) == 0",
|
|
91
|
+
],
|
|
92
|
+
cwd=tmp_path,
|
|
93
|
+
capture_output=True,
|
|
94
|
+
text=True,
|
|
95
|
+
timeout=10,
|
|
96
|
+
)
|
|
97
|
+
assert checked.returncode == 0, checked.stderr
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Use your approved isolation when executing generated code. A temporary directory
|
|
101
|
+
is not a security sandbox.
|
|
102
|
+
|
|
103
|
+
## What stays in the framework
|
|
104
|
+
|
|
105
|
+
| Capability | What it provides |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `CopilotEval` and `copilot_eval` | Real SDK sessions with explicit configuration |
|
|
108
|
+
| MCP, CLI, skills, plugins, custom agents | The interfaces and definitions under test |
|
|
109
|
+
| Execution controls | Time, usage, request, tool, and permission controls; one attempt per execution |
|
|
110
|
+
| Captured evidence | Configuration, calls, arguments, outputs, completion flags, errors, and usage |
|
|
111
|
+
| Ordinary pytest checks | Consumer-owned verification and recorded properties |
|
|
112
|
+
| `ab_run` and repetitions | Isolated working directories and repeated observations |
|
|
113
|
+
| Structured JSON | Captured execution and ordinary pytest outcomes, without rankings or advice |
|
|
114
|
+
| Pricing | Explicit USD estimates and recorded Copilot premium requests |
|
|
115
|
+
|
|
116
|
+
A/B entries share one pytest outcome. Record side-specific checks; do not read
|
|
117
|
+
that shared outcome as independent per-side success or causal improvement.
|
|
118
|
+
Missing prices and incomplete evidence are recorded explicitly.
|
|
119
|
+
|
|
120
|
+
## Let your coding agent investigate
|
|
121
|
+
|
|
122
|
+
Ask your existing coding agent to inspect a failed test, its saved JSON evidence,
|
|
123
|
+
and the source. It can explain the supported cause and help fix it, without
|
|
124
|
+
changing the test's success criteria after seeing the failure.
|
|
125
|
+
|
|
126
|
+
Reading current schema-4.0 evidence needs no authentication or paid call.
|
|
127
|
+
The framework records results; the coding agent interprets them. Subjective
|
|
128
|
+
review is advice, not an automatic pytest verdict.
|
|
129
|
+
|
|
130
|
+
Read the [full documentation](https://sbroenne.github.io/pytest-skill-engineering/).
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT. Inspired by [agent-benchmark](https://github.com/mykhaliev/agent-benchmark).
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["hatchling"]
|
|
2
|
+
requires = ["hatchling>=1.32.4"]
|
|
3
3
|
build-backend = "hatchling.build"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytest-skill-engineering"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Reliable Copilot execution and evidence for coding-agent-led testing of MCP servers, CLI tools, skills, and custom agents."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
11
|
requires-python = ">=3.11"
|
|
@@ -26,45 +26,40 @@ classifiers = [
|
|
|
26
26
|
"Topic :: Software Development :: Testing",
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
|
-
"pytest>=9.
|
|
30
|
-
"mcp>=2.
|
|
31
|
-
"pydantic>=2.
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"mdutils>=1.8.1",
|
|
35
|
-
"python-frontmatter>=1.1.0",
|
|
36
|
-
"nh3>=0.3.3",
|
|
37
|
-
"github-copilot-sdk>=1.0.13",
|
|
29
|
+
"pytest>=9.1.1",
|
|
30
|
+
"mcp>=2.2.0",
|
|
31
|
+
"pydantic>=2.13.5",
|
|
32
|
+
"python-frontmatter>=1.3.0",
|
|
33
|
+
"github-copilot-sdk>=1.0.16",
|
|
38
34
|
"httpx>=0.28.1",
|
|
39
|
-
"trio>=0.
|
|
35
|
+
"trio>=0.34.0",
|
|
40
36
|
"tomlkit>=0.15.1",
|
|
41
|
-
"pytest-asyncio>=1.
|
|
42
|
-
"websockets>=
|
|
37
|
+
"pytest-asyncio>=1.4.0",
|
|
38
|
+
"websockets>=17.1",
|
|
43
39
|
]
|
|
44
40
|
|
|
45
41
|
[project.optional-dependencies]
|
|
46
42
|
dev = [
|
|
47
|
-
"pytest-cov>=7.0",
|
|
48
|
-
"python-dotenv>=1.2",
|
|
49
|
-
"ruff>=0.16.
|
|
50
|
-
"pyright>=1.1.
|
|
51
|
-
"pre-commit>=4.
|
|
52
|
-
"typeguard>=4.
|
|
43
|
+
"pytest-cov>=7.1.0",
|
|
44
|
+
"python-dotenv>=1.2.3",
|
|
45
|
+
"ruff>=0.16.9",
|
|
46
|
+
"pyright>=1.1.414",
|
|
47
|
+
"pre-commit>=4.6.2",
|
|
48
|
+
"typeguard>=4.6.0",
|
|
53
49
|
]
|
|
54
50
|
test = [
|
|
55
|
-
"syrupy>=6.
|
|
51
|
+
"syrupy>=6.1.1,<7",
|
|
56
52
|
]
|
|
57
53
|
docs = [
|
|
58
|
-
"mkdocs>=1.6",
|
|
59
|
-
"mkdocs-material>=9.
|
|
60
|
-
"mkdocstrings[python]>=0.
|
|
61
|
-
"pillow>=
|
|
62
|
-
"cairosvg>=2.
|
|
54
|
+
"mkdocs>=1.6.1",
|
|
55
|
+
"mkdocs-material>=9.7.7,<9.8",
|
|
56
|
+
"mkdocstrings[python]>=1.0.6",
|
|
57
|
+
"pillow>=12.3.0",
|
|
58
|
+
"cairosvg>=2.9.1",
|
|
63
59
|
]
|
|
64
60
|
|
|
65
61
|
[project.scripts]
|
|
66
62
|
pytest-skill-engineering = "pytest_skill_engineering.onboarding:main"
|
|
67
|
-
pytest-skill-engineering-report = "pytest_skill_engineering.cli:main"
|
|
68
63
|
|
|
69
64
|
[project.entry-points.pytest11]
|
|
70
65
|
aitest = "pytest_skill_engineering.plugin"
|
|
@@ -83,9 +78,6 @@ packages = ["src/pytest_skill_engineering"]
|
|
|
83
78
|
include = [
|
|
84
79
|
"src/pytest_skill_engineering/**/*.py",
|
|
85
80
|
"src/pytest_skill_engineering/**/*.md",
|
|
86
|
-
"src/pytest_skill_engineering/**/*.html",
|
|
87
|
-
"src/pytest_skill_engineering/**/*.css",
|
|
88
|
-
"src/pytest_skill_engineering/**/*.js",
|
|
89
81
|
]
|
|
90
82
|
|
|
91
83
|
[tool.ruff]
|
|
@@ -106,7 +98,7 @@ quote-style = "double"
|
|
|
106
98
|
indent-style = "space"
|
|
107
99
|
|
|
108
100
|
[tool.pyright]
|
|
109
|
-
include = ["src", "tests"]
|
|
101
|
+
include = ["src", "tests", "examples/skill-dogfood"]
|
|
110
102
|
pythonVersion = "3.11"
|
|
111
103
|
typeCheckingMode = "basic"
|
|
112
104
|
|
|
@@ -125,8 +117,6 @@ filterwarnings = [
|
|
|
125
117
|
# LLM auth is handled by the GitHub Copilot SDK (gh auth login or GITHUB_TOKEN)
|
|
126
118
|
addopts = """
|
|
127
119
|
--strict-markers
|
|
128
|
-
--aitest-summary-model=copilot/gpt-5.6-sol
|
|
129
|
-
--aitest-html=aitest-reports/report.html
|
|
130
120
|
"""
|
|
131
121
|
markers = [
|
|
132
122
|
"integration: marks tests as integration tests (require LLM credentials)",
|
|
@@ -138,7 +128,6 @@ markers = [
|
|
|
138
128
|
"skill: tests with skills",
|
|
139
129
|
"session_test: multi-turn session tests",
|
|
140
130
|
"clarification: clarification detection tests",
|
|
141
|
-
"scoring: LLM scoring / rubric tests",
|
|
142
131
|
"iterations: iteration reliability tests",
|
|
143
132
|
"abtest: A/B server comparison tests",
|
|
144
133
|
"cli: CLI server tests",
|
|
@@ -150,4 +139,8 @@ markers = [
|
|
|
150
139
|
[dependency-groups]
|
|
151
140
|
dev = [
|
|
152
141
|
"pytest-skill-engineering[dev,test,docs]",
|
|
142
|
+
"pytest-skill-engineering-dogfood",
|
|
153
143
|
]
|
|
144
|
+
|
|
145
|
+
[tool.uv.sources]
|
|
146
|
+
pytest-skill-engineering-dogfood = { path = "examples/skill-dogfood", editable = true }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Copilot task execution and evidence for testing AI-facing tools and skills."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
@@ -22,8 +22,6 @@ from pytest_skill_engineering.copilot import ( # noqa: E402
|
|
|
22
22
|
)
|
|
23
23
|
from pytest_skill_engineering.core import ( # noqa: E402
|
|
24
24
|
AITestError,
|
|
25
|
-
BenchmarkComparison,
|
|
26
|
-
CaseBenchmark,
|
|
27
25
|
EngineTimeoutError,
|
|
28
26
|
EvalResult,
|
|
29
27
|
HookDefinition,
|
|
@@ -33,25 +31,16 @@ from pytest_skill_engineering.core import ( # noqa: E402
|
|
|
33
31
|
Plugin,
|
|
34
32
|
PluginMetadata,
|
|
35
33
|
Prompt,
|
|
36
|
-
RefinementResult,
|
|
37
|
-
RefinementSuggestion,
|
|
38
|
-
ScoreResult,
|
|
39
|
-
ScoringDimension,
|
|
40
34
|
ServerStartError,
|
|
41
35
|
Skill,
|
|
42
|
-
SkillBenchmarkResult,
|
|
43
|
-
SkillCaseResult,
|
|
44
36
|
SkillError,
|
|
45
37
|
SkillEvalCase,
|
|
46
|
-
SkillGradingResult,
|
|
47
38
|
SkillInfo,
|
|
48
39
|
SkillMetadata,
|
|
49
40
|
SubagentInvocation,
|
|
50
41
|
ToolCall,
|
|
51
42
|
ToolInfo,
|
|
52
43
|
Turn,
|
|
53
|
-
analyze_skill_failures,
|
|
54
|
-
assert_score,
|
|
55
44
|
export_grading,
|
|
56
45
|
has_skill_evals,
|
|
57
46
|
load_custom_agent,
|
|
@@ -74,27 +63,18 @@ from pytest_skill_engineering.execution import ( # noqa: E402
|
|
|
74
63
|
WaitStrategy,
|
|
75
64
|
)
|
|
76
65
|
|
|
77
|
-
# Hooks (for plugin extensibility)
|
|
78
|
-
from pytest_skill_engineering.hooks import AitestHookSpec # noqa: E402
|
|
79
|
-
from pytest_skill_engineering.plugin import ( # noqa: E402
|
|
80
|
-
get_analysis_prompt,
|
|
81
|
-
get_analysis_prompt_details,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
66
|
# Reporting
|
|
85
67
|
from pytest_skill_engineering.reporting import ( # noqa: E402
|
|
86
68
|
SuiteReport,
|
|
87
69
|
TestReport,
|
|
88
70
|
build_suite_report,
|
|
89
|
-
generate_html,
|
|
90
71
|
generate_json,
|
|
72
|
+
load_suite_report,
|
|
91
73
|
)
|
|
92
74
|
|
|
93
75
|
__all__ = [ # noqa: RUF022
|
|
94
76
|
# Core
|
|
95
77
|
"AITestError",
|
|
96
|
-
"BenchmarkComparison",
|
|
97
|
-
"CaseBenchmark",
|
|
98
78
|
"EngineTimeoutError",
|
|
99
79
|
"EvalResult",
|
|
100
80
|
"HookDefinition",
|
|
@@ -104,22 +84,16 @@ __all__ = [ # noqa: RUF022
|
|
|
104
84
|
"Plugin",
|
|
105
85
|
"PluginMetadata",
|
|
106
86
|
"Prompt",
|
|
107
|
-
"RefinementResult",
|
|
108
|
-
"RefinementSuggestion",
|
|
109
87
|
"ServerStartError",
|
|
110
88
|
"Skill",
|
|
111
|
-
"SkillBenchmarkResult",
|
|
112
|
-
"SkillCaseResult",
|
|
113
89
|
"SkillError",
|
|
114
90
|
"SkillEvalCase",
|
|
115
|
-
"SkillGradingResult",
|
|
116
91
|
"SkillInfo",
|
|
117
92
|
"SkillMetadata",
|
|
118
93
|
"SubagentInvocation",
|
|
119
94
|
"ToolCall",
|
|
120
95
|
"ToolInfo",
|
|
121
96
|
"Turn",
|
|
122
|
-
"analyze_skill_failures",
|
|
123
97
|
"export_grading",
|
|
124
98
|
"has_skill_evals",
|
|
125
99
|
"load_custom_agent",
|
|
@@ -152,16 +126,8 @@ __all__ = [ # noqa: RUF022
|
|
|
152
126
|
"SuiteReport",
|
|
153
127
|
"TestReport",
|
|
154
128
|
"build_suite_report",
|
|
155
|
-
"generate_html",
|
|
156
129
|
"generate_json",
|
|
157
|
-
|
|
158
|
-
"AitestHookSpec",
|
|
159
|
-
"get_analysis_prompt",
|
|
160
|
-
"get_analysis_prompt_details",
|
|
161
|
-
# Scoring
|
|
162
|
-
"ScoreResult",
|
|
163
|
-
"ScoringDimension",
|
|
164
|
-
"assert_score",
|
|
130
|
+
"load_suite_report",
|
|
165
131
|
]
|
|
166
132
|
|
|
167
133
|
from importlib.metadata import version as _get_version # noqa: E402
|