agent-mini 0.2.0__tar.gz → 0.3.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.
Files changed (64) hide show
  1. {agent_mini-0.2.0 → agent_mini-0.3.0}/.gitignore +1 -0
  2. {agent_mini-0.2.0 → agent_mini-0.3.0}/PKG-INFO +27 -5
  3. {agent_mini-0.2.0 → agent_mini-0.3.0}/README.md +26 -4
  4. agent_mini-0.3.0/evals/README.md +154 -0
  5. agent_mini-0.3.0/evals/fixtures/buggy_stack/pytest.ini +2 -0
  6. agent_mini-0.3.0/evals/fixtures/buggy_stack/src/stack.py +22 -0
  7. agent_mini-0.3.0/evals/fixtures/buggy_stack/tests/test_stack.py +24 -0
  8. agent_mini-0.3.0/evals/fixtures/py_project/pytest.ini +2 -0
  9. agent_mini-0.3.0/evals/fixtures/py_project/src/mymath.py +11 -0
  10. agent_mini-0.3.0/evals/fixtures/py_project/tests/test_mymath.py +16 -0
  11. agent_mini-0.3.0/evals/fixtures/small_repo/README.md +5 -0
  12. agent_mini-0.3.0/evals/fixtures/small_repo/src/config.py +2 -0
  13. agent_mini-0.3.0/evals/fixtures/small_repo/src/server.py +8 -0
  14. agent_mini-0.3.0/evals/run.py +512 -0
  15. agent_mini-0.3.0/evals/tasks/codebase_qa.yaml +14 -0
  16. agent_mini-0.3.0/evals/tasks/error_recovery.yaml +13 -0
  17. agent_mini-0.3.0/evals/tasks/fix_failing_test.yaml +14 -0
  18. agent_mini-0.3.0/evals/tasks/list_directory_basic.yaml +14 -0
  19. agent_mini-0.3.0/evals/tasks/multi_file_edit.yaml +16 -0
  20. agent_mini-0.3.0/evals/tasks/refactor_rename.yaml +15 -0
  21. agent_mini-0.3.0/evals/tasks/search_and_summarize.yaml +14 -0
  22. agent_mini-0.3.0/evals/tasks/shell_pipeline.yaml +14 -0
  23. agent_mini-0.3.0/evals/tasks/write_file_from_scratch.yaml +15 -0
  24. {agent_mini-0.2.0 → agent_mini-0.3.0}/pyproject.toml +1 -1
  25. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/__init__.py +1 -1
  26. agent_mini-0.3.0/src/agent_mini/agent/context.py +112 -0
  27. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/agent/loop.py +35 -31
  28. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/agent/token_estimator.py +11 -4
  29. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/agent/tools.py +66 -3
  30. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/channels/telegram.py +10 -9
  31. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/cli.py +22 -1
  32. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/providers/local.py +4 -1
  33. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/providers/ollama.py +34 -3
  34. agent_mini-0.3.0/tests/test_context.py +120 -0
  35. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_loop.py +24 -0
  36. agent_mini-0.3.0/tests/test_providers.py +86 -0
  37. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_token_estimator.py +4 -0
  38. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_tools.py +41 -0
  39. {agent_mini-0.2.0 → agent_mini-0.3.0}/uv.lock +1 -1
  40. agent_mini-0.2.0/src/agent_mini/agent/context.py +0 -48
  41. agent_mini-0.2.0/tests/test_context.py +0 -66
  42. {agent_mini-0.2.0 → agent_mini-0.3.0}/.github/workflows/ci.yml +0 -0
  43. {agent_mini-0.2.0 → agent_mini-0.3.0}/.github/workflows/publish.yml +0 -0
  44. {agent_mini-0.2.0 → agent_mini-0.3.0}/CONTRIBUTING.md +0 -0
  45. {agent_mini-0.2.0 → agent_mini-0.3.0}/LICENSE +0 -0
  46. {agent_mini-0.2.0 → agent_mini-0.3.0}/SECURITY.md +0 -0
  47. {agent_mini-0.2.0 → agent_mini-0.3.0}/config.example.json +0 -0
  48. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/__main__.py +0 -0
  49. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/agent/__init__.py +0 -0
  50. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/agent/memory.py +0 -0
  51. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/agent/vision.py +0 -0
  52. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/bus.py +0 -0
  53. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/channels/__init__.py +0 -0
  54. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/channels/base.py +0 -0
  55. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/config.py +0 -0
  56. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/providers/__init__.py +0 -0
  57. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/providers/base.py +0 -0
  58. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/providers/openai.py +0 -0
  59. {agent_mini-0.2.0 → agent_mini-0.3.0}/src/agent_mini/sessions.py +0 -0
  60. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/__init__.py +0 -0
  61. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_config.py +0 -0
  62. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_json_repair.py +0 -0
  63. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_memory.py +0 -0
  64. {agent_mini-0.2.0 → agent_mini-0.3.0}/tests/test_phases.py +0 -0
@@ -36,3 +36,4 @@ config.json
36
36
  .ruff_cache/
37
37
 
38
38
  archived
39
+ evals/results
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-mini
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Ultra-lightweight personal AI agent — shell, files, web, memory — powered by local or cloud LLMs
5
5
  Project-URL: Homepage, https://github.com/mohsinkaleem/agent-mini
6
6
  Project-URL: Repository, https://github.com/mohsinkaleem/agent-mini
@@ -46,8 +46,9 @@ A minimal, local-first AI agent you can actually understand and extend.
46
46
  - **Local-first** — Ollama as default, OpenAI if you want cloud, or any OpenAI-compatible server
47
47
  - **Zero frameworks** — pure `httpx` + `asyncio`, no LangChain, no LiteLLM
48
48
  - **Built-in tools** — shell, files, web search, persistent memory
49
+ - **Vision** — drop an image path or URL into any message; works on Ollama, OpenAI, and OpenAI-compatible providers
49
50
  - **Extensible** — drop a Python file in `~/.agent-mini/plugins/` and it's a tool
50
- - **Small-model optimized** — token-aware context pruning, tool call repair, model-tier tuning
51
+ - **Small-model optimized** — tier-scaled system prompt, token-aware context pruning, tool-call repair, and a [task-eval harness](evals/) to measure whether the tuning actually pays off
51
52
 
52
53
  ## Quick Start
53
54
 
@@ -133,7 +134,7 @@ Available out of the box — no API keys needed:
133
134
  | `list_directory` | Browse filesystem |
134
135
  | `search_files` | Grep / ripgrep across files |
135
136
  | `web_search` | DuckDuckGo search (free, no key) |
136
- | `web_fetch` | Fetch any URL as plain text |
137
+ | `web_fetch` | Fetch a public URL as plain text (private/loopback hosts blocked) |
137
138
  | `memory_store` | Save to persistent memory |
138
139
  | `memory_recall` | Fuzzy search memory (TF-IDF) |
139
140
 
@@ -214,7 +215,9 @@ Control tool access:
214
215
  { "tools": { "sandboxLevel": "readonly" } }
215
216
  ```
216
217
 
217
- Dangerous shell commands (`rm -rf`, `sudo`, `mkfs`, etc.) are blocked by default.
218
+ Dangerous shell commands (`rm -rf`, `sudo`, `mkfs`, etc.) are blocked by default. Treat the shell blocklist as **friction, not a boundary** — a determined caller can bypass it, so don't run the agent in an untrusted context and expect the blocklist to save you.
219
+
220
+ `web_fetch` is guarded against basic SSRF: requests to `localhost`, loopback (`::1`), RFC-1918 private ranges, and link-local (including the cloud metadata endpoint `169.254.169.254`) are refused, and the final URL is re-checked after every redirect. DNS rebinding can still bypass — use `sandboxLevel: readonly` if you need a stronger guarantee.
218
221
 
219
222
  ---
220
223
 
@@ -236,11 +239,14 @@ Agent Mini is a **ReAct loop** — the LLM reasons, picks a tool, observes the r
236
239
 
237
240
  Key design choices for small/local models:
238
241
 
242
+ - **Tier-scaled system prompt** — tiny models get a compact rules block and no memory recall; larger tiers get the full descriptive prompt and recent context
243
+ - **Inline tool list** — `<available_tools>` block in the system prompt so small models can see tool names at a glance without inferring from the JSON schema
239
244
  - **Token-aware context** — estimates token usage and prunes old tool results when approaching the model's effective context window
240
- - **Model tier classification** — auto-detects tiny/small/medium/cloud models and adjusts context budgets, iteration limits, and output caps
245
+ - **Model tier classification** — auto-detects tiny/small/medium/cloud (including large open-weight sizes like `:32b`, `:70b`, `8x7b`) and adjusts context budgets, iteration limits, and output caps
241
246
  - **Tool call repair** — fixes malformed JSON from small models (trailing commas, single quotes, unquoted keys)
242
247
  - **Loop detection** — catches repeated identical tool calls and nudges the LLM to try a different approach
243
248
  - **History summarization** — compresses long conversations to stay within context
249
+ - **[Task-eval harness](evals/)** — measures success rate, iterations, tokens, and JSON-repair fire-rate across model tiers so the tuning above is testable, not hand-waved
244
250
 
245
251
  ---
246
252
 
@@ -284,6 +290,7 @@ Key paths:
284
290
  | `agent-mini init` | Interactive setup wizard |
285
291
  | `agent-mini chat` | Interactive chat |
286
292
  | `agent-mini chat -m "..."` | Single message |
293
+ | `agent-mini chat --workspace <dir>` | Override the workspace for a single run (also honours `AGENT_MINI_WORKSPACE`) |
287
294
  | `agent-mini gateway` | Start Telegram bot |
288
295
  | `agent-mini status` | Show config status |
289
296
 
@@ -324,6 +331,21 @@ uv run pytest tests/ -v
324
331
  uv run ruff check src/ tests/
325
332
  ```
326
333
 
334
+ ### Task evals
335
+
336
+ The [`evals/`](evals/) directory contains a small, framework-free task-eval
337
+ harness that runs the agent end-to-end against real fixtures (refactor a
338
+ codebase, fix a failing test, answer a codebase question, etc.). Use it to
339
+ measure whether the small-model optimizations actually pay off:
340
+
341
+ ```bash
342
+ python evals/run.py # run all tasks against config model
343
+ python evals/run.py --task refactor_rename # single task
344
+ python evals/run.py --compare results/*.json # cross-tier comparison table
345
+ ```
346
+
347
+ See [evals/README.md](evals/README.md) for the full workflow.
348
+
327
349
  See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
328
350
 
329
351
  ## License
@@ -11,8 +11,9 @@ A minimal, local-first AI agent you can actually understand and extend.
11
11
  - **Local-first** — Ollama as default, OpenAI if you want cloud, or any OpenAI-compatible server
12
12
  - **Zero frameworks** — pure `httpx` + `asyncio`, no LangChain, no LiteLLM
13
13
  - **Built-in tools** — shell, files, web search, persistent memory
14
+ - **Vision** — drop an image path or URL into any message; works on Ollama, OpenAI, and OpenAI-compatible providers
14
15
  - **Extensible** — drop a Python file in `~/.agent-mini/plugins/` and it's a tool
15
- - **Small-model optimized** — token-aware context pruning, tool call repair, model-tier tuning
16
+ - **Small-model optimized** — tier-scaled system prompt, token-aware context pruning, tool-call repair, and a [task-eval harness](evals/) to measure whether the tuning actually pays off
16
17
 
17
18
  ## Quick Start
18
19
 
@@ -98,7 +99,7 @@ Available out of the box — no API keys needed:
98
99
  | `list_directory` | Browse filesystem |
99
100
  | `search_files` | Grep / ripgrep across files |
100
101
  | `web_search` | DuckDuckGo search (free, no key) |
101
- | `web_fetch` | Fetch any URL as plain text |
102
+ | `web_fetch` | Fetch a public URL as plain text (private/loopback hosts blocked) |
102
103
  | `memory_store` | Save to persistent memory |
103
104
  | `memory_recall` | Fuzzy search memory (TF-IDF) |
104
105
 
@@ -179,7 +180,9 @@ Control tool access:
179
180
  { "tools": { "sandboxLevel": "readonly" } }
180
181
  ```
181
182
 
182
- Dangerous shell commands (`rm -rf`, `sudo`, `mkfs`, etc.) are blocked by default.
183
+ Dangerous shell commands (`rm -rf`, `sudo`, `mkfs`, etc.) are blocked by default. Treat the shell blocklist as **friction, not a boundary** — a determined caller can bypass it, so don't run the agent in an untrusted context and expect the blocklist to save you.
184
+
185
+ `web_fetch` is guarded against basic SSRF: requests to `localhost`, loopback (`::1`), RFC-1918 private ranges, and link-local (including the cloud metadata endpoint `169.254.169.254`) are refused, and the final URL is re-checked after every redirect. DNS rebinding can still bypass — use `sandboxLevel: readonly` if you need a stronger guarantee.
183
186
 
184
187
  ---
185
188
 
@@ -201,11 +204,14 @@ Agent Mini is a **ReAct loop** — the LLM reasons, picks a tool, observes the r
201
204
 
202
205
  Key design choices for small/local models:
203
206
 
207
+ - **Tier-scaled system prompt** — tiny models get a compact rules block and no memory recall; larger tiers get the full descriptive prompt and recent context
208
+ - **Inline tool list** — `<available_tools>` block in the system prompt so small models can see tool names at a glance without inferring from the JSON schema
204
209
  - **Token-aware context** — estimates token usage and prunes old tool results when approaching the model's effective context window
205
- - **Model tier classification** — auto-detects tiny/small/medium/cloud models and adjusts context budgets, iteration limits, and output caps
210
+ - **Model tier classification** — auto-detects tiny/small/medium/cloud (including large open-weight sizes like `:32b`, `:70b`, `8x7b`) and adjusts context budgets, iteration limits, and output caps
206
211
  - **Tool call repair** — fixes malformed JSON from small models (trailing commas, single quotes, unquoted keys)
207
212
  - **Loop detection** — catches repeated identical tool calls and nudges the LLM to try a different approach
208
213
  - **History summarization** — compresses long conversations to stay within context
214
+ - **[Task-eval harness](evals/)** — measures success rate, iterations, tokens, and JSON-repair fire-rate across model tiers so the tuning above is testable, not hand-waved
209
215
 
210
216
  ---
211
217
 
@@ -249,6 +255,7 @@ Key paths:
249
255
  | `agent-mini init` | Interactive setup wizard |
250
256
  | `agent-mini chat` | Interactive chat |
251
257
  | `agent-mini chat -m "..."` | Single message |
258
+ | `agent-mini chat --workspace <dir>` | Override the workspace for a single run (also honours `AGENT_MINI_WORKSPACE`) |
252
259
  | `agent-mini gateway` | Start Telegram bot |
253
260
  | `agent-mini status` | Show config status |
254
261
 
@@ -289,6 +296,21 @@ uv run pytest tests/ -v
289
296
  uv run ruff check src/ tests/
290
297
  ```
291
298
 
299
+ ### Task evals
300
+
301
+ The [`evals/`](evals/) directory contains a small, framework-free task-eval
302
+ harness that runs the agent end-to-end against real fixtures (refactor a
303
+ codebase, fix a failing test, answer a codebase question, etc.). Use it to
304
+ measure whether the small-model optimizations actually pay off:
305
+
306
+ ```bash
307
+ python evals/run.py # run all tasks against config model
308
+ python evals/run.py --task refactor_rename # single task
309
+ python evals/run.py --compare results/*.json # cross-tier comparison table
310
+ ```
311
+
312
+ See [evals/README.md](evals/README.md) for the full workflow.
313
+
292
314
  See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
293
315
 
294
316
  ## License
@@ -0,0 +1,154 @@
1
+ # Agent Mini — Task Evals
2
+
3
+ A tiny, framework-free harness that measures whether the agent can complete
4
+ **real-world tasks** end-to-end, not just pass unit tests. This is where the
5
+ "small-model optimized" claim gets tested for real.
6
+
7
+ Zero new dependencies. Uses only the standard library + `agent-mini` itself.
8
+
9
+ ---
10
+
11
+ ## Quick start
12
+
13
+ ```bash
14
+ # 1. Have Ollama (or any provider) already running with a model
15
+ ollama pull llama3.1:8b
16
+
17
+ # 2. Point agent-mini at it (only needed once)
18
+ agent-mini init
19
+
20
+ # 3. Run the whole suite
21
+ python evals/run.py
22
+
23
+ # 4. Run against a specific model
24
+ python evals/run.py --model llama3.2:3b
25
+
26
+ # 5. Run a single task
27
+ python evals/run.py --task refactor_rename
28
+
29
+ # 6. Compare tiers (the thesis test)
30
+ python evals/run.py --model llama3.2:3b --out results/tiny.json
31
+ python evals/run.py --model llama3.1:8b --out results/small.json
32
+ python evals/run.py --model qwen2.5:14b --out results/medium.json
33
+ python evals/run.py --compare results/*.json
34
+ ```
35
+
36
+ Results are printed as a table and written to `results/<model>_<timestamp>.json`
37
+ (one line per task, so you can `jq` / `grep` them).
38
+
39
+ ---
40
+
41
+ ## Latest results — qwen3.5 tiers (Ollama, 2026-07-28)
42
+
43
+ Local M-series Mac, `think: false`, default agent config (`maxIterations: 20`).
44
+
45
+ | Task | qwen3.5:4b | qwen3.5:9b | qwen3.5:27b |
46
+ |----------------------------|--------------|--------------|---------------|
47
+ | codebase_qa | PASS · 18.0s | PASS · 23.8s | PASS · 81.5s |
48
+ | error_recovery | PASS · 8.7s | PASS · 19.5s | PASS · 50.3s |
49
+ | fix_failing_test | PASS · 17.9s | PASS · 24.9s | PASS · 85.3s |
50
+ | list_directory_basic | FAIL · 8.3s | PASS · 14.0s | PASS · 47.5s |
51
+ | multi_file_edit | PASS · 9.5s | PASS · 18.3s | PASS · 78.4s |
52
+ | refactor_rename | FAIL · 10.1s | FAIL · 61.0s | PASS · 184.9s |
53
+ | search_and_summarize | PASS · 6.2s | PASS · 23.2s | PASS · 32.0s |
54
+ | shell_pipeline | FAIL · 12.6s | PASS · 32.2s | FAIL · 120.0s (timeout) |
55
+ | write_file_from_scratch | FAIL · 11.1s | FAIL · 15.7s | PASS · 34.7s |
56
+ | **Pass rate** | **5/9** | **7/9** | **8/9** |
57
+
58
+ Notes:
59
+
60
+ - `qwen3.5:9b` is the sweet spot on this suite
61
+ `shell_pipeline` and finishing every task well under the timeout.
62
+ - `write_file_from_scratch` also fails everywhere: models emit a `print`
63
+ / `__main__` block despite the prompt forbidding it. Good candidate for
64
+ a small-model instruction-tuning improvement.
65
+ ---
66
+
67
+ ## Layout
68
+
69
+ ```
70
+ evals/
71
+ ├── README.md # this file
72
+ ├── run.py # ~200 lines: copy fixture → run agent headless → score
73
+ ├── tasks/*.yaml # task fixtures — prompt + programmatic check
74
+ └── fixtures/ # tiny sample repos used by tasks
75
+ ```
76
+
77
+ Each task is a self-contained YAML file:
78
+
79
+ ```yaml
80
+ id: refactor_rename
81
+ category: refactor
82
+ setup: fixtures/py_project
83
+ prompt: |
84
+ Rename the function `calc` to `compute` across all .py files in this
85
+ workspace and make sure the tests still pass.
86
+ timeout_seconds: 180
87
+ checks:
88
+ - shell: "! grep -rq 'def calc(' ."
89
+ description: "No `def calc` remains"
90
+ - shell: "grep -rq 'def compute(' ."
91
+ description: "`def compute` appears somewhere"
92
+ - shell: "python -m pytest -q"
93
+ description: "Tests still pass"
94
+ ```
95
+
96
+ Add a task: drop a YAML file in `tasks/` and (optionally) a matching
97
+ fixture directory in `fixtures/`. The runner picks it up on next run.
98
+
99
+ ---
100
+
101
+ ## Task categories (the surface we actually care about)
102
+
103
+ | Category | Exercises | Task ID |
104
+ |----------|-----------|---------|
105
+ | File ops | `write_file`, `code_edit`, multi-file rename | `refactor_rename` |
106
+ | Codebase Q&A | `search_files` → `read_file` → summarize | `codebase_qa` |
107
+ | Multi-step | write, run, verify a fix | `fix_failing_test` |
108
+ | Error recovery | retry a different way after failure | `error_recovery` |
109
+ | Memory | store fact turn 1, recall turn 3 (uses `--multi-turn`) | `memory_recall` |
110
+ | Search | grep + read | `search_and_summarize` |
111
+
112
+ ---
113
+
114
+ ## Metrics (per model)
115
+
116
+ The runner tabulates:
117
+
118
+ | Metric | Why it matters |
119
+ |--------|----------------|
120
+ | Success rate | Core efficacy. |
121
+ | Median iterations | Loop efficiency. Wandering = bad. |
122
+ | JSON-repair fire rate | Is small-model tool-call repair earning its keep? |
123
+ | Summarize trigger rate | Is context management engaging when needed? |
124
+ | Loop-detection hits | Are small models stalling? |
125
+ | Total tokens / wall time | Cost. |
126
+
127
+ The **thesis test**: run the same suite across `tiny` / `small` / `medium` /
128
+ `cloud` tiers. If tuned `3B` ≈ untuned `8B`, the optimization is proven. If
129
+ not, it's theater — and this harness is exactly what surfaces that.
130
+
131
+ ---
132
+
133
+ ## Design constraints
134
+
135
+ - **No new dependencies.** stdlib only (`subprocess`, `shutil`, `tempfile`,
136
+ `json`, `re`, `argparse`). YAML is parsed by a tiny in-file loader — the
137
+ task schema is intentionally flat enough not to need PyYAML.
138
+ - **No mocking.** Real provider, real tools, real filesystem. Fixtures are
139
+ copied to a fresh `tempfile.mkdtemp()` per task, so runs don't leak.
140
+ - **Zero framework bloat.** ~200 LOC in `run.py`. Read it in five minutes.
141
+ - **CI-friendly.** Gate as nightly against a live model; keep unit tests as
142
+ the fast job. Model latency should not block PRs.
143
+
144
+ ## Adding a task
145
+
146
+ 1. Create `evals/fixtures/my_fixture/` with a minimal set of files.
147
+ 2. Create `evals/tasks/my_task.yaml`:
148
+ - `id`: matches the file stem.
149
+ - `setup`: path to the fixture (relative to `evals/`).
150
+ - `prompt`: what to ask the agent.
151
+ - `checks`: shell one-liners that must exit `0`.
152
+ 3. Verify: `python evals/run.py --task my_task`.
153
+
154
+ Each bug we fix should get a new task. The corpus grows organically.
@@ -0,0 +1,2 @@
1
+ [pytest]
2
+ testpaths = tests
@@ -0,0 +1,22 @@
1
+ """A buggy stack implementation. The `pop` method is off-by-one — the eval
2
+ asks the agent to find and fix the bug so the tests pass."""
3
+
4
+
5
+ class Stack:
6
+ def __init__(self):
7
+ self._items = []
8
+
9
+ def push(self, x):
10
+ self._items.append(x)
11
+
12
+ def pop(self):
13
+ if not self._items:
14
+ raise IndexError("pop from empty stack")
15
+ # BUG: returns the wrong end of the list
16
+ return self._items.pop(0)
17
+
18
+ def peek(self):
19
+ return self._items[-1]
20
+
21
+ def __len__(self):
22
+ return len(self._items)
@@ -0,0 +1,24 @@
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
5
+
6
+ from stack import Stack # noqa: E402
7
+
8
+
9
+ def test_push_pop_is_lifo():
10
+ s = Stack()
11
+ s.push(1)
12
+ s.push(2)
13
+ s.push(3)
14
+ assert s.pop() == 3
15
+ assert s.pop() == 2
16
+ assert s.pop() == 1
17
+
18
+
19
+ def test_peek_does_not_mutate():
20
+ s = Stack()
21
+ s.push("a")
22
+ s.push("b")
23
+ assert s.peek() == "b"
24
+ assert len(s) == 2
@@ -0,0 +1,2 @@
1
+ [pytest]
2
+ testpaths = tests
@@ -0,0 +1,11 @@
1
+ """A tiny arithmetic helper — used by the eval fixture."""
2
+
3
+
4
+ def calc(a: int, b: int) -> int:
5
+ """Add two ints. The eval will ask the agent to rename this."""
6
+ return a + b
7
+
8
+
9
+ def double_calc(x: int) -> int:
10
+ """Uses `calc` — the rename must update the call site too."""
11
+ return calc(x, x)
@@ -0,0 +1,16 @@
1
+ """Tests for mymath — must still pass after the rename."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
7
+
8
+ from mymath import calc, double_calc # noqa: E402
9
+
10
+
11
+ def test_calc_adds():
12
+ assert calc(2, 3) == 5
13
+
14
+
15
+ def test_double_uses_calc():
16
+ assert double_calc(4) == 8
@@ -0,0 +1,5 @@
1
+ # Wonderland Widget
2
+
3
+ A small internal library shared by three teams. The project's port is **9137**.
4
+
5
+ Owner: alice@example.org
@@ -0,0 +1,2 @@
1
+ SERVICE_NAME = "wonderland-widget"
2
+ VERSION = "0.4.2"
@@ -0,0 +1,8 @@
1
+ """Wonderland widget server."""
2
+
3
+ PORT = 9137
4
+ HOST = "0.0.0.0"
5
+
6
+
7
+ def start_server():
8
+ print(f"Serving on {HOST}:{PORT}")