File size: 7,903 Bytes
1244914
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# Forge Code Evaluations

A flexible evaluation framework for running automated tests and benchmarks against Forge Code commands.

## Quick Start

### Setup

Before running evaluations, create a `forgee` symlink to the debug binary:

```bash
# Create symlink in your PATH (e.g., ~/bin or /usr/local/bin)
ln -sf /path/to/code-forge/target/debug/forge ~/forgee

# Or if ~/bin is in your PATH
ln -sf $(pwd)/target/debug/forge ~/bin/forgee
```

**Why is this needed?** Tasks execute in temporary directories, so relative paths like `../../target/debug/forge` won't work. The `forgee` symlink provides a stable absolute path that works from any directory.

### Running Evaluations

```bash
# Run an evaluation
npm run eval ./evals/create_skill/task.yml

# Set custom log level
LOG_LEVEL=debug npm run eval ./evals/create_skill/task.yml
```

## How It Works

The evaluation system executes commands based on task definitions and validates their output. It supports:

- **Parallel execution** with configurable concurrency
- **Timeout handling** for long-running tasks
- **Data-driven testing** using CSV files
- **Output validation** using regex patterns
- **Debug artifacts** stored with timestamps

## Project Structure

```
benchmarks/
β”œβ”€β”€ cli.ts                    # Main CLI entry point
β”œβ”€β”€ command-generator.ts      # Command template rendering
β”œβ”€β”€ task-executor.ts          # Task execution with timeout support
β”œβ”€β”€ model.ts                  # TypeScript types for tasks
β”œβ”€β”€ parse.ts                  # CLI argument parsing
└── evals/                    # Evaluation definitions
    └── create_skill/
        β”œβ”€β”€ task.yml          # Task definition
        β”œβ”€β”€ create_skill_tasks.csv  # Test data
        └── debug/            # Debug outputs (timestamped)
```

## Creating an Evaluation

### 1. Create an Evaluation Directory

```bash
mkdir -p evals/my_eval
```

### 2. Create a `task.yml` File

The task file defines how to run your evaluation:

```yaml
# Optional: Commands to run before evaluation starts
before_run:
  - cargo build
  - npm install

# Required: Command(s) to execute for each test case
# Single command
run: forgee -p '{{prompt}}'

# Or multiple commands (executed sequentially)
run:
  - echo "Step 1: {{task}}"
  - forgee -p '{{prompt}}'
  - echo "Step 2: Complete"

# Execution configuration
parallelism: 10  # Number of tasks to run in parallel (default: 1)
timeout: 60      # Timeout in seconds (optional)
early_exit: true # Stop execution when validations pass (optional)

# Optional: Validations to run on output
validations:
  - name: "Check success message"
    type: regex
    regex: \[[0-9:]*\] Skill create-skill

# Required: Data sources for test cases
sources:
  - csv: my_tasks.csv
```

#### Task File Schema

**`before_run`** (optional): Array of shell commands to execute before running tasks
- Runs sequentially before the main command execution
- Executes in a temporary directory created for the evaluation run
- Useful for building binaries or setting up dependencies

**`run`** (required): Command(s) to execute for each test case
- Can be a single string or an array of strings
- Commands support template placeholders (e.g., `{{variable}}`)
- Multiple commands are executed sequentially
- If any command fails, subsequent commands are skipped

**`parallelism`** (optional): Number of tasks to run concurrently (default: 1)

**`timeout`** (optional): Maximum execution time in seconds per task

**`early_exit`** (optional): Stop command execution when all validations pass

**`validations`** (optional): Array of validation rules
- `name`: Human-readable description
- `type`: Validation type. Supported values:
  - `regex`: Match output against a regular expression pattern
  - `shell`: Execute a shell command with output as stdin
- For `regex` type:
  - `regex`: Regular expression pattern to match in output
- For `shell` type:
  - `command`: Shell command to execute (receives task output via stdin)
  - `exit_code`: Expected exit code (default: 0)

**`sources`** (required): Array of data sources
- Currently supports CSV files: `- csv: filename.csv`
- Future: Command output: `- cmd: command`

### 3. Create Test Data (CSV)

Create a CSV file with columns matching your template variables:

```csv
prompt,expected_output
"Create a backup script","backup.sh"
"Generate API client","api_client.py"
```

The column names (e.g., `prompt`, `expected_output`) become template variables you can use in your command with `{{column_name}}`.

### 4. Run the Evaluation

```bash
npm run eval ./evals/my_eval/task.yml
```

## Template Variables

Commands support Handlebars template syntax. Variables are populated from CSV columns:

```yaml
run:
  command: ./tool --input '{{input_file}}' --format {{format}} --verbose
```

With CSV:
```csv
input_file,format
data1.txt,json
data2.txt,yaml
```

## Output and Debugging

### Debug Artifacts

Each run creates a timestamped debug directory:

```
evals/my_eval/debug/2025-11-23T10-30-45-123Z/
β”œβ”€β”€ task-1.log
β”œβ”€β”€ task-2.log
└── task-3.log
```

Each log file contains the full output (stdout + stderr) from the command execution.

### Task Status

Tasks can have four statuses:

- **`passed`**: Task completed successfully and passed all validations
- **`validation_failed`**: Task completed but failed one or more validations
- **`timeout`**: Task exceeded the timeout limit
- **`failed`**: Task execution failed (non-zero exit code)

### Logging

**Human-readable output (default):**
```bash
npm run eval ./evals/my_eval/task.yml
```

**Machine-readable JSON output:**
```bash
LOG_JSON=1 npm run eval ./evals/my_eval/task.yml | jq .
```

**Debug logging:**
```bash
LOG_LEVEL=debug npm run eval ./evals/my_eval/task.yml
```

## Examples

### Example 1: Simple Sequential Execution

```yaml
run: echo "Processing {{name}}"
sources:
  - csv: names.csv
```

```csv
name
Alice
Bob
Charlie
```

### Example 2: Parallel Execution with Timeout

```yaml
run: ./slow_task --id {{task_id}}
parallelism: 5
timeout: 30
sources:
  - csv: tasks.csv
```

### Example 3: Multiple Commands

```yaml
run:
  - echo "Starting task {{id}}"
  - ./process --input {{file}}
  - echo "Task {{id}} complete"
parallelism: 3
timeout: 120
sources:
  - csv: tasks.csv
```

### Example 4: Shell Command Validation

```yaml
run: echo "{{message}}"
parallelism: 3
validations:
  # Using grep to check if output contains specific text
  - name: "Contains 'test' word"
    type: shell
    command: grep -q "test"
    exit_code: 0
  
  # Count words and ensure it's greater than 2
  - name: "More than 2 words"
    type: shell
    command: test $(wc -w | awk '{print $1}') -gt 2
    exit_code: 0
  
  # Traditional regex validation (for comparison)
  - name: "Contains test or validation"
    type: regex
    regex: "test|validation"
sources:
  - csv: messages.csv
```

### Example 5: Regex Validation

```yaml
run: cargo test {{test_name}}
validations:
  - name: "All tests passed"
    type: regex
    regex: test result:\s+ok
sources:
  - csv: tests.csv
```

## Tips

1. **Use quotes in commands**: When passing CSV values with spaces, wrap them in quotes:
   ```yaml
   command: forge -p '{{prompt}}'
   ```

2. **Build before running**: Use `before_run` to ensure binaries are up-to-date:
   ```yaml
   before_run:
     - cargo build
   ```

3. **Start with low parallelism**: Test with `parallelism: 1` first, then increase:
   ```yaml
   parallelism: 1  # Start here
   ```

4. **Set appropriate timeouts**: Add timeouts to prevent hanging:
   ```yaml
   timeout: 60  # seconds
   ```

5. **Check debug logs**: When tasks fail, check the debug directory for full output:
   ```bash
   cat evals/my_eval/debug/*/task-1.log
   ```

## Exit Codes

The CLI exits with:
- **0**: All tasks passed
- **1**: One or more tasks failed (excluding timeouts and validation failures)