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)
|