evalsi-harness 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.
- evalsi_harness-0.1.0/.gitignore +30 -0
- evalsi_harness-0.1.0/PKG-INFO +41 -0
- evalsi_harness-0.1.0/README.md +26 -0
- evalsi_harness-0.1.0/pyproject.toml +34 -0
- evalsi_harness-0.1.0/src/evalsi_harness/__init__.py +39 -0
- evalsi_harness-0.1.0/src/evalsi_harness/_version.py +1 -0
- evalsi_harness-0.1.0/src/evalsi_harness/benchmarks/__init__.py +1 -0
- evalsi_harness-0.1.0/src/evalsi_harness/benchmarks/fixtures.py +111 -0
- evalsi_harness-0.1.0/src/evalsi_harness/benchmarks/harbor.py +698 -0
- evalsi_harness-0.1.0/src/evalsi_harness/cassette.py +181 -0
- evalsi_harness-0.1.0/src/evalsi_harness/checker.py +122 -0
- evalsi_harness-0.1.0/src/evalsi_harness/connectors.py +565 -0
- evalsi_harness-0.1.0/src/evalsi_harness/environment.py +225 -0
- evalsi_harness-0.1.0/src/evalsi_harness/events.py +61 -0
- evalsi_harness-0.1.0/src/evalsi_harness/formats.py +188 -0
- evalsi_harness-0.1.0/src/evalsi_harness/gym.py +190 -0
- evalsi_harness-0.1.0/src/evalsi_harness/harness.py +468 -0
- evalsi_harness-0.1.0/src/evalsi_harness/loop.py +237 -0
- evalsi_harness-0.1.0/src/evalsi_harness/mcp.py +232 -0
- evalsi_harness-0.1.0/src/evalsi_harness/models.py +282 -0
- evalsi_harness-0.1.0/src/evalsi_harness/otel.py +165 -0
- evalsi_harness-0.1.0/src/evalsi_harness/py.typed +0 -0
- evalsi_harness-0.1.0/src/evalsi_harness/runner.py +141 -0
- evalsi_harness-0.1.0/src/evalsi_harness/service.py +264 -0
- evalsi_harness-0.1.0/src/evalsi_harness/task.py +235 -0
- evalsi_harness-0.1.0/src/evalsi_harness/testing.py +293 -0
- evalsi_harness-0.1.0/src/evalsi_harness/tools.py +261 -0
- evalsi_harness-0.1.0/src/evalsi_harness/trust.py +64 -0
- evalsi_harness-0.1.0/src/evalsi_harness/user_sim.py +83 -0
- evalsi_harness-0.1.0/tests/__init__.py +0 -0
- evalsi_harness-0.1.0/tests/conftest.py +26 -0
- evalsi_harness-0.1.0/tests/fixtures/dsh-0.2.1-alpha.2-fix-calc.jsonl +11 -0
- evalsi_harness-0.1.0/tests/fixtures/dsh-0.2.1-alpha.2-no-credential.jsonl +6 -0
- evalsi_harness-0.1.0/tests/fixtures/dsh-0.2.1-alpha.2-tool-error.jsonl +11 -0
- evalsi_harness-0.1.0/tests/harness_support.py +59 -0
- evalsi_harness-0.1.0/tests/test_benchmarks_harbor.py +184 -0
- evalsi_harness-0.1.0/tests/test_formats.py +102 -0
- evalsi_harness-0.1.0/tests/test_gym.py +88 -0
- evalsi_harness-0.1.0/tests/test_harness_agent.py +484 -0
- evalsi_harness-0.1.0/tests/test_harness_connectors.py +264 -0
- evalsi_harness-0.1.0/tests/test_harness_parts.py +442 -0
- evalsi_harness-0.1.0/tests/test_harness_run.py +107 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Go
|
|
2
|
+
/evalsid
|
|
3
|
+
/bin/
|
|
4
|
+
# `go build ./cmd/...` without -o drops a binary in the working directory
|
|
5
|
+
/evalsi-guest
|
|
6
|
+
/evalsi-operator
|
|
7
|
+
/evalsi-collector
|
|
8
|
+
|
|
9
|
+
# Python
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
.venv/
|
|
13
|
+
*.egg-info/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
|
|
20
|
+
# Editors and OS
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
.DS_Store
|
|
24
|
+
|
|
25
|
+
# Server data directories (examples use .evalsi and .evalsi-auth-demo)
|
|
26
|
+
.evalsi*/
|
|
27
|
+
examples/demo/terminal-bench-2/
|
|
28
|
+
examples/demo/_local-*.yaml
|
|
29
|
+
|
|
30
|
+
node_modules/
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: evalsi-harness
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The light built-in agent harness for Evals.si: tool loop, MCP tools, sandboxes, user simulator, record and replay.
|
|
5
|
+
Project-URL: Homepage, https://abhishek-rnjn.github.io/Evals.si/
|
|
6
|
+
Project-URL: Documentation, https://abhishek-rnjn.github.io/Evals.si/
|
|
7
|
+
Project-URL: Repository, https://github.com/Abhishek-Rnjn/Evals.si
|
|
8
|
+
Project-URL: Issues, https://github.com/Abhishek-Rnjn/Evals.si/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/Abhishek-Rnjn/Evals.si/blob/main/CHANGELOG.md
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Requires-Dist: evalsi[server]==0.1.0
|
|
13
|
+
Requires-Dist: httpx>=0.27
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# evalsi-harness
|
|
17
|
+
|
|
18
|
+
The light built-in agent harness for [Evals.si](https://github.com/Abhishek-Rnjn/Evals.si).
|
|
19
|
+
It drives an agent through a task in an Evals.si sandbox and grades the end state.
|
|
20
|
+
|
|
21
|
+
It runs either of these:
|
|
22
|
+
- the built-in tool-calling agent on any OpenAI-compatible or Anthropic model;
|
|
23
|
+
- a bring-your-own agent over A2A, MCP, OpenAI Responses or HTTP, or as a CLI run inside the sandbox.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install evalsi-harness
|
|
27
|
+
evalsi run -f agent-run.yaml
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
What it provides:
|
|
31
|
+
- **Sandbox tools:** `bash`, `read_file` and `write_file`, plus an escalation request the harness policy decides on.
|
|
32
|
+
- **Other tools:** MCP tools over streamable HTTP or stdio; mocked tools; deterministic fault injection.
|
|
33
|
+
- **Budgets:** steps, tokens, spend and wall-clock time.
|
|
34
|
+
- **Simulated user:** an LLM user for multi-turn tasks.
|
|
35
|
+
- **Record and replay:** model calls and tool I/O are captured, replay can branch from step N, and sandbox commands are re-executed so the environment is rebuilt.
|
|
36
|
+
- **Environment checkers:** exit code, JSON, JUnit or a Python function.
|
|
37
|
+
- **OTel spans:** every step becomes a span.
|
|
38
|
+
- **The agent's diff:** recorded for the `code-quality` evaluator when the workdir is a git repository.
|
|
39
|
+
- **Benchmark importers:** `harbor://` (Terminal-Bench 2 and other Harbor datasets) and `terminal-bench://` (Terminal-Bench 1) task directories, with their Dockerfiles translated into environments.
|
|
40
|
+
|
|
41
|
+
See [docs/guides/agent-runs.md](../../docs/guides/agent-runs.md).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# evalsi-harness
|
|
2
|
+
|
|
3
|
+
The light built-in agent harness for [Evals.si](https://github.com/Abhishek-Rnjn/Evals.si).
|
|
4
|
+
It drives an agent through a task in an Evals.si sandbox and grades the end state.
|
|
5
|
+
|
|
6
|
+
It runs either of these:
|
|
7
|
+
- the built-in tool-calling agent on any OpenAI-compatible or Anthropic model;
|
|
8
|
+
- a bring-your-own agent over A2A, MCP, OpenAI Responses or HTTP, or as a CLI run inside the sandbox.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install evalsi-harness
|
|
12
|
+
evalsi run -f agent-run.yaml
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
What it provides:
|
|
16
|
+
- **Sandbox tools:** `bash`, `read_file` and `write_file`, plus an escalation request the harness policy decides on.
|
|
17
|
+
- **Other tools:** MCP tools over streamable HTTP or stdio; mocked tools; deterministic fault injection.
|
|
18
|
+
- **Budgets:** steps, tokens, spend and wall-clock time.
|
|
19
|
+
- **Simulated user:** an LLM user for multi-turn tasks.
|
|
20
|
+
- **Record and replay:** model calls and tool I/O are captured, replay can branch from step N, and sandbox commands are re-executed so the environment is rebuilt.
|
|
21
|
+
- **Environment checkers:** exit code, JSON, JUnit or a Python function.
|
|
22
|
+
- **OTel spans:** every step becomes a span.
|
|
23
|
+
- **The agent's diff:** recorded for the `code-quality` evaluator when the workdir is a git repository.
|
|
24
|
+
- **Benchmark importers:** `harbor://` (Terminal-Bench 2 and other Harbor datasets) and `terminal-bench://` (Terminal-Bench 1) task directories, with their Dockerfiles translated into environments.
|
|
25
|
+
|
|
26
|
+
See [docs/guides/agent-runs.md](../../docs/guides/agent-runs.md).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "evalsi-harness"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "The light built-in agent harness for Evals.si: tool loop, MCP tools, sandboxes, user simulator, record and replay."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
dependencies = [
|
|
9
|
+
# The harness speaks evalsi's protocol: the same release only. The
|
|
10
|
+
# release workflow sets this with the version.
|
|
11
|
+
"evalsi[server]==0.1.0",
|
|
12
|
+
"httpx>=0.27",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.entry-points."evalsi.importers"]
|
|
16
|
+
harbor = "evalsi_harness.benchmarks.harbor:load_harbor"
|
|
17
|
+
terminal-bench = "evalsi_harness.benchmarks.harbor:load_terminal_bench"
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
Homepage = "https://abhishek-rnjn.github.io/Evals.si/"
|
|
21
|
+
Documentation = "https://abhishek-rnjn.github.io/Evals.si/"
|
|
22
|
+
Repository = "https://github.com/Abhishek-Rnjn/Evals.si"
|
|
23
|
+
Issues = "https://github.com/Abhishek-Rnjn/Evals.si/issues"
|
|
24
|
+
Changelog = "https://github.com/Abhishek-Rnjn/Evals.si/blob/main/CHANGELOG.md"
|
|
25
|
+
|
|
26
|
+
[build-system]
|
|
27
|
+
requires = ["hatchling>=1.25"]
|
|
28
|
+
build-backend = "hatchling.build"
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["src/evalsi_harness"]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.version]
|
|
34
|
+
path = "src/evalsi_harness/_version.py"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""evalsi-harness: the light built-in agent harness for Evals.si (design §11).
|
|
2
|
+
|
|
3
|
+
It drives an agent through a task in an Evals.si sandbox: the built-in
|
|
4
|
+
tool-calling agent on any OpenAI-compatible or Anthropic model, or a
|
|
5
|
+
bring-your-own agent (A2A, MCP, OpenAI Responses, HTTP, or a CLI run in the
|
|
6
|
+
sandbox). It provides sandbox and MCP tools, budgets, a simulated user,
|
|
7
|
+
mocked and faulty tools, record and replay, sandbox policy events and OTel
|
|
8
|
+
spans, and grades the end state with the environment's checker.
|
|
9
|
+
|
|
10
|
+
Most users never import it: ``evalsi run`` and the server's worker call
|
|
11
|
+
:func:`run_task` for every record of an agent run.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from evalsi_harness._version import __version__
|
|
15
|
+
from evalsi_harness.events import FinalEvent, PolicyEvent, StepEvent
|
|
16
|
+
from evalsi_harness.harness import BuiltinHarness, Harness, HarnessContext, HarnessManifest
|
|
17
|
+
from evalsi_harness.runner import TaskOutcome, load_harness, run_task
|
|
18
|
+
from evalsi_harness.task import EnvironmentConfig, Task, TaskError
|
|
19
|
+
from evalsi_harness.tools import FunctionTool, Tool, ToolResult
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"BuiltinHarness",
|
|
23
|
+
"EnvironmentConfig",
|
|
24
|
+
"FinalEvent",
|
|
25
|
+
"FunctionTool",
|
|
26
|
+
"Harness",
|
|
27
|
+
"HarnessContext",
|
|
28
|
+
"HarnessManifest",
|
|
29
|
+
"PolicyEvent",
|
|
30
|
+
"StepEvent",
|
|
31
|
+
"Task",
|
|
32
|
+
"TaskError",
|
|
33
|
+
"TaskOutcome",
|
|
34
|
+
"Tool",
|
|
35
|
+
"ToolResult",
|
|
36
|
+
"__version__",
|
|
37
|
+
"load_harness",
|
|
38
|
+
"run_task",
|
|
39
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Benchmark task formats as Evals.si agent tasks."""
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Tiny Harbor and Terminal-Bench 1 tasks, for tests and smoke runs: each
|
|
2
|
+
asks for /app/hello.txt on alpine:3.22, copies a binary file in, and grades
|
|
3
|
+
offline (no package installs), so they run in any sandbox that can pull the
|
|
4
|
+
image.
|
|
5
|
+
|
|
6
|
+
python -m evalsi_harness.benchmarks.fixtures <dir>
|
|
7
|
+
|
|
8
|
+
writes ``<dir>/harbor/hello`` and ``<dir>/terminal-bench/hello``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
INSTRUCTION = 'Create a file called /app/hello.txt with "Hello, world!" as the content.'
|
|
16
|
+
BLOB = bytes(range(256)) * 4
|
|
17
|
+
|
|
18
|
+
DOCKERFILE = """\
|
|
19
|
+
FROM alpine:3.22
|
|
20
|
+
ARG GREETING_FILE=greeting.txt
|
|
21
|
+
ENV GREETING="Hello, world!"
|
|
22
|
+
WORKDIR /app
|
|
23
|
+
COPY blob.bin /opt/data/
|
|
24
|
+
RUN printf '%s' "$GREETING" > /opt/data/${GREETING_FILE} \\
|
|
25
|
+
&& echo ready > state.txt
|
|
26
|
+
CMD ["sh"]
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Checks the agent's file, and that the image setup (ENV, ARG, RUN in the
|
|
30
|
+
# WORKDIR) and the binary copy came through intact.
|
|
31
|
+
CHECK = """\
|
|
32
|
+
test "$(cat /app/hello.txt)" = "$(cat /opt/data/greeting.txt)" && \\
|
|
33
|
+
test "$(cat /app/state.txt)" = ready && \\
|
|
34
|
+
cmp -s /opt/data/blob.bin /tests/blob.bin"""
|
|
35
|
+
|
|
36
|
+
TASK_TOML = """\
|
|
37
|
+
schema_version = "1.1"
|
|
38
|
+
|
|
39
|
+
[task]
|
|
40
|
+
name = "evalsi/hello"
|
|
41
|
+
|
|
42
|
+
[metadata]
|
|
43
|
+
difficulty = "easy"
|
|
44
|
+
|
|
45
|
+
[verifier]
|
|
46
|
+
timeout_sec = 60.0
|
|
47
|
+
|
|
48
|
+
[agent]
|
|
49
|
+
timeout_sec = 120.0
|
|
50
|
+
|
|
51
|
+
[environment]
|
|
52
|
+
network_mode = "no-network"
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
HARBOR_TEST = f"""#!/bin/sh
|
|
56
|
+
if {CHECK}; then
|
|
57
|
+
echo 1 > /logs/verifier/reward.txt
|
|
58
|
+
else
|
|
59
|
+
echo 0 > /logs/verifier/reward.txt
|
|
60
|
+
fi
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
TASK_YAML = f"""\
|
|
64
|
+
instruction: |-
|
|
65
|
+
{INSTRUCTION}
|
|
66
|
+
difficulty: easy
|
|
67
|
+
category: file-operations
|
|
68
|
+
parser_name: pytest
|
|
69
|
+
max_agent_timeout_sec: 120.0
|
|
70
|
+
max_test_timeout_sec: 60.0
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
# A pytest-shaped report without pytest, so the task needs no network.
|
|
74
|
+
RUN_TESTS = f"""#!/bin/sh
|
|
75
|
+
echo "============================= test session starts =============================="
|
|
76
|
+
if {CHECK}; then hello=PASSED; else hello=FAILED; fi
|
|
77
|
+
echo "=========================== short test summary info ============================"
|
|
78
|
+
echo "PASSED tests/test_outputs.py::test_setup"
|
|
79
|
+
echo "$hello tests/test_outputs.py::test_hello_file"
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def write(directory: str | Path) -> Path:
|
|
84
|
+
root = Path(directory)
|
|
85
|
+
h = root / "harbor" / "hello"
|
|
86
|
+
(h / "environment").mkdir(parents=True, exist_ok=True)
|
|
87
|
+
(h / "tests").mkdir(exist_ok=True)
|
|
88
|
+
(h / "solution").mkdir(exist_ok=True)
|
|
89
|
+
(h / "task.toml").write_text(TASK_TOML)
|
|
90
|
+
(h / "instruction.md").write_text(INSTRUCTION + "\n")
|
|
91
|
+
(h / "environment" / "Dockerfile").write_text(DOCKERFILE)
|
|
92
|
+
(h / "environment" / "blob.bin").write_bytes(BLOB)
|
|
93
|
+
(h / "tests" / "test.sh").write_text(HARBOR_TEST)
|
|
94
|
+
(h / "tests" / "blob.bin").write_bytes(BLOB)
|
|
95
|
+
(h / "solution" / "solve.sh").write_text("#!/bin/sh\nprintf 'Hello, world!' > /app/hello.txt\n")
|
|
96
|
+
|
|
97
|
+
t = root / "terminal-bench" / "hello"
|
|
98
|
+
(t / "tests").mkdir(parents=True, exist_ok=True)
|
|
99
|
+
(t / "task.yaml").write_text(TASK_YAML)
|
|
100
|
+
(t / "Dockerfile").write_text(DOCKERFILE)
|
|
101
|
+
(t / "blob.bin").write_bytes(BLOB)
|
|
102
|
+
(t / "run-tests.sh").write_text(RUN_TESTS)
|
|
103
|
+
(t / "tests" / "blob.bin").write_bytes(BLOB)
|
|
104
|
+
(t / "solution.sh").write_text("#!/bin/sh\nprintf 'Hello, world!' > /app/hello.txt\n")
|
|
105
|
+
return root
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if __name__ == "__main__": # pragma: no cover
|
|
109
|
+
import sys
|
|
110
|
+
|
|
111
|
+
write(sys.argv[1] if len(sys.argv) > 1 else "benchmark-fixtures")
|