chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
# Adding Custom Tools
|
||||
|
||||
!!! abstract "Adding custom tools to SWE-agent"
|
||||
This tutorial walks you through creating and integrating custom tools into SWE-agent.
|
||||
We'll create a fun `print_cat` command that prints ASCII art of a cat for morale boost!
|
||||
|
||||
Please read our [hello world](hello_world.md) and [command line basics](cl_tutorial.md) tutorials before proceeding.
|
||||
|
||||
## Understanding Tool Structure
|
||||
|
||||
Every SWE-agent tool is organized as a "bundle" - a directory containing:
|
||||
|
||||
1. **`config.yaml`** - Defines the tool's interface and documentation
|
||||
2. **`bin/`** directory - Contains the executable scripts
|
||||
3. **`install.sh`** (optional) - Sets up dependencies
|
||||
4. **`lib/`** (optional) - Contains shared libraries or utilities
|
||||
|
||||
Let's look at the simple `submit` tool structure:
|
||||
|
||||
```
|
||||
tools/submit/
|
||||
├── config.yaml
|
||||
└── bin/
|
||||
└── submit
|
||||
```
|
||||
|
||||
## Step 1: Write the Command Script
|
||||
|
||||
First, let's create our `morale_boost` tool bundle:
|
||||
|
||||
```bash
|
||||
mkdir -p tools/morale_boost/bin
|
||||
```
|
||||
|
||||
Create the executable script that will be called when the agent runs your command:
|
||||
|
||||
```bash title="tools/morale_boost/bin/print_cat"
|
||||
#!/bin/bash
|
||||
|
||||
# print_cat - A morale-boosting ASCII cat printer!
|
||||
|
||||
echo "🐱 Here's a cat to boost your morale! 🐱"
|
||||
echo ""
|
||||
cat << 'EOF'
|
||||
/\_/\
|
||||
( o.o )
|
||||
> ^ <
|
||||
_) (_
|
||||
(_____)
|
||||
EOF
|
||||
echo ""
|
||||
echo "You're doing great! Keep coding! 💪"
|
||||
```
|
||||
|
||||
If you're wondering about the strange `EOF` construct, those are called
|
||||
[heredocs](https://linuxize.com/post/bash-heredoc/) and enable multiline
|
||||
arguments in bash.
|
||||
|
||||
## Step 2: Define the Tool Configuration
|
||||
|
||||
Create the `config.yaml` file that tells SWE-agent about your tool:
|
||||
|
||||
```yaml title="tools/morale_boost/config.yaml"
|
||||
tools:
|
||||
print_cat:
|
||||
signature: "print_cat"
|
||||
docstring: "Prints an ASCII art cat for morale boost. Use when you need encouragement!"
|
||||
arguments: []
|
||||
```
|
||||
|
||||
!!! tip "Tool Configuration Options"
|
||||
|
||||
The `config.yaml` supports various options:
|
||||
|
||||
- **`signature`**: How the command should be called (including arguments)
|
||||
- **`docstring`**: Description that helps the AI understand when to use this tool
|
||||
- **`arguments`**: List of arguments with types, descriptions, and whether they're required
|
||||
|
||||
For a tool with arguments, it would look like this:
|
||||
|
||||
```yaml title="Example with arguments"
|
||||
tools:
|
||||
print_animal:
|
||||
signature: "print_animal <animal_type> [--size=<size>]"
|
||||
docstring: "Prints ASCII art of the specified animal"
|
||||
arguments:
|
||||
- name: animal_type
|
||||
type: string
|
||||
description: "Type of animal to print (cat, dog, elephant)"
|
||||
required: true
|
||||
- name: size
|
||||
type: string
|
||||
description: "Size of the art (small, medium, large)"
|
||||
required: false
|
||||
```
|
||||
|
||||
## Step 3: Tell the agent to use the new tool
|
||||
|
||||
Now you need to tell SWE-agent to use your new tool. Copy `config/default.yaml` to `config/my_custom_config.yaml`
|
||||
and make the following modification
|
||||
|
||||
```yaml title="config/my_custom_config.yaml"
|
||||
agent:
|
||||
templates:
|
||||
instance_template: |-
|
||||
(...)
|
||||
|
||||
Don't forget to use `print_cat` when you need encouragement!
|
||||
|
||||
Your thinking should be thorough and so it's fine if it's very long.
|
||||
bundles:
|
||||
- path: tools/registry
|
||||
- path: tools/edit_anthropic
|
||||
- path: tools/review_on_submit_m
|
||||
- path: tools/morale_boost # Add our custom tool bundle!
|
||||
# everything else stays the same
|
||||
```
|
||||
|
||||
## Step 4: Let's test it
|
||||
|
||||
Now you can test your tool by running SWE-agent with your custom configuration:
|
||||
|
||||
```bash
|
||||
sweagent run \
|
||||
--config config/my_custom_config.yaml \
|
||||
--agent.model.name=gpt-4o \
|
||||
--env.repo.github_url=https://github.com/SWE-agent/test-repo \
|
||||
--problem_statement.text="Add a simple hello world function to the repository. Feel free to use print_cat for morale!"
|
||||
```
|
||||
|
||||
The agent should now have access to your `print_cat` command and may use it during execution!
|
||||
|
||||
## Advanced Tool Features
|
||||
|
||||
### Multiple Commands in One Bundle
|
||||
|
||||
You can define multiple commands in a single tool bundle:
|
||||
|
||||
```yaml title="tools/morale_boost/config.yaml - Extended version"
|
||||
tools:
|
||||
print_cat:
|
||||
signature: "print_cat"
|
||||
docstring: "Prints an ASCII art cat for morale boost"
|
||||
arguments: []
|
||||
print_dog:
|
||||
signature: "print_dog"
|
||||
docstring: "Prints an ASCII art dog for variety"
|
||||
arguments: []
|
||||
motivate:
|
||||
signature: "motivate <message>"
|
||||
docstring: "Prints a motivational message with ASCII art"
|
||||
arguments:
|
||||
- name: message
|
||||
type: string
|
||||
description: "The motivational message to display"
|
||||
required: true
|
||||
```
|
||||
|
||||
Don't forget to create the corresponding scripts in the `bin/` directory!
|
||||
|
||||
### Using Python Libraries
|
||||
|
||||
If you prefer Python, you can create Python-based tools:
|
||||
|
||||
```python title="tools/morale_boost/bin/print_cat"
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
A morale-boosting cat printer in Python!
|
||||
"""
|
||||
|
||||
print("🐱 Here's a cat to boost your morale! 🐱")
|
||||
```
|
||||
|
||||
If your Python tool needs additional dependencies, create an `install.sh` script:
|
||||
|
||||
```bash title="tools/morale_boost/install.sh"
|
||||
#!/bin/bash
|
||||
# This script runs when the tool bundle is installed
|
||||
|
||||
# Example: Install Python packages
|
||||
pip install cowsay
|
||||
pip install colorama
|
||||
|
||||
echo "Morale boost tools installed! Ready to spread joy! 🎉"
|
||||
```
|
||||
|
||||
### Environment Variables and Context
|
||||
|
||||
Your tools can access environment variables and the current working context:
|
||||
|
||||
```bash title="Example using environment variables"
|
||||
#!/bin/bash
|
||||
|
||||
echo "Current working directory: $PWD"
|
||||
echo "Repository root: $ROOT"
|
||||
echo "My custom variable: $MY_CUSTOM_VAR"
|
||||
```
|
||||
|
||||
Adding environment variables in your config file can be a simple way of customizing your tools
|
||||
|
||||
```yaml title="config/my_custom_config.yaml"
|
||||
agent:
|
||||
tools:
|
||||
env_variables:
|
||||
PAGER: cat
|
||||
MY_CUSTOM_VAR: "Hello from config!"
|
||||
DEBUG_MODE: "true"
|
||||
# ... rest of config
|
||||
```
|
||||
|
||||
For sensitive data like API keys, you can propagate environment variables from your host system:
|
||||
|
||||
```yaml title="config/my_custom_config.yaml"
|
||||
agent:
|
||||
tools:
|
||||
propagate_env_variables:
|
||||
- "OPENAI_API_KEY"
|
||||
- "GITHUB_TOKEN"
|
||||
- "MY_SECRET_KEY"
|
||||
# ... rest of config
|
||||
```
|
||||
|
||||
Your tools can then access these variables:
|
||||
|
||||
```bash title="tools/morale_boost/bin/print_cat_with_api"
|
||||
#!/bin/bash
|
||||
|
||||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
echo "🐱 Connected to GitHub! Ready to boost morale across repos!"
|
||||
else
|
||||
echo "🐱 Just a local morale booster today!"
|
||||
fi
|
||||
```
|
||||
|
||||
However, we mostly recommend to use the python bindings of the `registry` bundle for keeping internal
|
||||
state (instead of using environment variables).
|
||||
|
||||
### Using the Registry Bundle
|
||||
|
||||
The registry bundle provides a persistent key-value store that survives across tool calls. This is better than environment variables because
|
||||
you can store complex data structures (lists, dictionaries) as JSON.
|
||||
|
||||
**Setting registry variables in your config:**
|
||||
|
||||
```yaml title="config/my_custom_config.yaml"
|
||||
agent:
|
||||
tools:
|
||||
registry_variables:
|
||||
MY_CUSTOM_SETTING: "hello world"
|
||||
MORALE_MESSAGES:
|
||||
- "You're doing great!"
|
||||
- "Keep up the good work!"
|
||||
- "Almost there!"
|
||||
DEBUG_MODE: true
|
||||
bundles:
|
||||
- path: tools/registry # Always include this first!
|
||||
- path: tools/morale_boost
|
||||
```
|
||||
|
||||
**Accessing registry variables in your Python tools:**
|
||||
|
||||
```python title="tools/morale_boost/bin/print_motivational_cat"
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from registry import registry
|
||||
|
||||
def main():
|
||||
# Get a simple value with a fallback
|
||||
setting = registry.get("MY_CUSTOM_SETTING", "default value")
|
||||
print(f"Setting: {setting}")
|
||||
|
||||
# Get a list of messages
|
||||
messages = registry.get("MORALE_MESSAGES", [])
|
||||
if messages:
|
||||
import random
|
||||
message = random.choice(messages)
|
||||
print(f"🐱 {message}")
|
||||
|
||||
# Set a value (persists across tool calls)
|
||||
registry["LAST_MORALE_BOOST"] = "2024-01-15 10:30:00"
|
||||
|
||||
print("Morale boosted! 🚀")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
**Accessing registry variables in bash tools:**
|
||||
|
||||
```bash title="tools/morale_boost/bin/print_simple_cat"
|
||||
#!/bin/bash
|
||||
|
||||
# Read from registry using the _read_env helper
|
||||
CUSTOM_SETTING=$(_read_env "MY_CUSTOM_SETTING" "default value")
|
||||
DEBUG_MODE=$(_read_env "DEBUG_MODE" "false")
|
||||
|
||||
echo "🐱 Custom setting: $CUSTOM_SETTING"
|
||||
|
||||
if [ "$DEBUG_MODE" = "true" ]; then
|
||||
echo "Debug mode is enabled!"
|
||||
fi
|
||||
```
|
||||
|
||||
The registry is particularly useful for complex tools that need to maintain state across multiple invocations, like the `review_on_submit_m` tool that tracks submission stages.
|
||||
|
||||
## State commands and more
|
||||
|
||||
Take a look at our [tool documentation](../config/tools.md).
|
||||
|
||||
{% include-markdown "../_footer.md" %}
|
||||
@@ -0,0 +1,231 @@
|
||||
# Batch mode
|
||||
|
||||
!!! abstract "Running on many issues at once"
|
||||
You have used `sweagent run`. To become a real power user, we'll convert you to `sweagent run-batch` and you can run on a hundred issues at once.
|
||||
|
||||
* Please make sure you're familiar with [the command line basics](cl_tutorial.md).
|
||||
* The default examples will be executing code in a Docker sandbox, so make sure you have docker installed ([docker troubleshooting](../installation/tips.md)).
|
||||
If you cannot run docker, skim through the examples below and adapt accordingly.
|
||||
|
||||
## A first example: SWE-bench
|
||||
|
||||
So you've decided to run SWE-agent on a lot of issues in parallel. Great, the `run-batch` command is exactly here for that.
|
||||
Let's run on three [SWE-bench](https://www.swebench.com/) issues which will be downloaded automatically.
|
||||
|
||||
```bash
|
||||
sweagent run-batch \
|
||||
--config config/default.yaml \
|
||||
--agent.model.name gpt-4o \
|
||||
--agent.model.per_instance_cost_limit 2.00 \
|
||||
--instances.type swe_bench \
|
||||
--instances.subset lite \
|
||||
--instances.split dev \
|
||||
--instances.slice :3 \
|
||||
--instances.shuffle=True
|
||||
```
|
||||
|
||||
Let's look at the options:
|
||||
|
||||
1. `--instances.type swe_bench`: There's a couple of built-in ways to configure instances. This option selects the SWE-bench dataset.
|
||||
2. `--instances.subset lite`: There's a few datasets provided by the SWE-bench project. Lite is a subset of GitHub issues with a few heuristic filters that makes them more likely to be solvable.
|
||||
3. `--instances.split dev`: Most datasets have a `dev` and a `test` split.
|
||||
4. `--instances.slice :3`: The `--slice` option allows you to select a subset of instances from the dataset. It works just the way to pythons `list[...]` slicing, so you can specify `:10` to take the first 10 instances, `10:20` to take the next 10, `-10:` to take the last 10, or `10:20:2` to take every second instance in that range.
|
||||
5. `--instances.shuffle=True`: Shuffle all instances before slicing. This is a deterministic operation, so the same command will always return the same instances in the same order.
|
||||
|
||||
* There's some things that you should recognize: All of the `--agent` options are available and you can still specify `--config` files.
|
||||
* However, the `--problem_statement`, `--repo`, and `--env` options obviously need to change, because you now want to populate these settings automatically from a source.
|
||||
|
||||
This is where the new option comes in: `--instances`, specifying the **instance source** together with a few options.
|
||||
|
||||
!!! tip "Tooltips"
|
||||
Click on the :material-chevron-right-circle: icon in the right margin of the code snippet to see more information about the line.
|
||||
|
||||
The output should remind you a lot like the output of the [hello world tutorial](hello_world.md), except for the progress bar at the bottom.
|
||||
Kind of slow, isn't it?
|
||||
|
||||
|
||||
!!! tip "All command line options"
|
||||
* See [`RunBatchConfig`](../reference/run_batch_config.md#sweagent.run.run_batch.RunBatchConfig) for an overview of all options.
|
||||
* SWE-bench config: [`SWEBenchInstances`](../reference/batch_instances.md#sweagent.run.batch_instances.SWEBenchInstances).
|
||||
|
||||
!!! tip "Evaluating on SWE-bench"
|
||||
If you are using [`sb-cli`](https://www.swebench.com/sb-cli/), you can automatically evaluate on SWE-bench by adding the `--evaluate=True` flag.
|
||||
This will already submit submissions to `sb-cli` while you are running, so that you should receive results within a minute of finishing your run.
|
||||
|
||||
## Multimodal SWE-bench
|
||||
|
||||
SWE-agent supports the **SWE-bench Multimodal** dataset, which includes GitHub issues with associated images (screenshots, diagrams, UI mockups). To run on multimodal instances:
|
||||
|
||||
```bash
|
||||
sweagent run-batch \
|
||||
--config config/default_mm_with_images.yaml \
|
||||
--agent.model.name claude-sonnet-4-20250514 \
|
||||
--agent.model.per_instance_cost_limit 2.00 \
|
||||
--instances.type swe_bench \
|
||||
--instances.subset multimodal \
|
||||
--instances.split dev \
|
||||
--instances.slice :3 \
|
||||
--instances.shuffle=True
|
||||
```
|
||||
|
||||
Key differences for multimodal runs:
|
||||
|
||||
- **Configuration**: Use `config/default_mm_with_images.yaml` which includes image processing capabilities
|
||||
- **Subset**: Use `--instances.subset multimodal` to access the multimodal dataset
|
||||
- **Token limits**: Consider higher cost limits as images consume more tokens
|
||||
- **Multimodal Tools**: `tools/image_tools` and `tools/web_browser` include useful tools for viewing images and web browsers
|
||||
|
||||
The system automatically:
|
||||
- Downloads images from GitHub issue URLs
|
||||
- Converts them to base64 markdown format
|
||||
- Provides visual context to the AI model
|
||||
|
||||
!!! tip "Multimodal Configuration"
|
||||
See the [multimodal guide](multimodal.md) for detailed configuration options and troubleshooting.
|
||||
|
||||
## Running in parallel
|
||||
|
||||
Let's speed things up and run on 5 instances at once. Only a single line to change:
|
||||
|
||||
```bash hl_lines="4-4"
|
||||
sweagent run-batch \
|
||||
--config config/default.yaml \
|
||||
--agent.model.name gpt-4o \
|
||||
--num_workers 3 \
|
||||
--agent.model.per_instance_cost_limit 2.00 \
|
||||
--instances.type swe_bench \
|
||||
--instances.subset lite \
|
||||
--instances.split dev \
|
||||
--instances.slice :3 \
|
||||
--instances.shuffle=True
|
||||
```
|
||||
|
||||
You'll see output that looks like this (only with 3 workers instead of 30):
|
||||
|
||||
<figure markdown="span">
|
||||
{: style="max-width: 500px; border-radius: 10px;"}
|
||||
<figcaption>SWE-Agent running on 30 SWE-bench instances</figcaption>
|
||||
</figure>
|
||||
|
||||
!!! tip "All command line options"
|
||||
See [`RunBatchConfig`](../reference/run_batch_config.md#sweagent.run.run_batch.RunBatchConfig) for an overview of all options.
|
||||
|
||||
When starting a lot of parallel instances with the docker backend, it might happen that you see some bottleneck effects
|
||||
(e.g., when running on a platform with few CPUs, you might see some timeouts because there's not enough CPUs to handle the startup of all containers in time).
|
||||
In this case, please set `--random_delay_multiplier` to e.g., 1. This means that every worker will wait a random time between `0s` and `1s * #workers` before starting,
|
||||
thereby easing CPU pressure. Default is 0.3.
|
||||
|
||||
## Loading instances from a file
|
||||
|
||||
```bash
|
||||
sweagent run-batch \
|
||||
--config config/default.yaml \
|
||||
--agent.model.name gpt-4o \
|
||||
--instances.type file \
|
||||
--instances.path instances.yaml \
|
||||
--instances.slice :3 \
|
||||
--instances.shuffle=True
|
||||
```
|
||||
|
||||
`--instances.path` supports `.jsonl`, `.json`, and `.yaml` files.
|
||||
|
||||
Here'the simplest example of what such a file can look like
|
||||
|
||||
```yaml title="instances.yaml"
|
||||
- image_name: "python:3.11" # (1)!
|
||||
problem_statement: "A simple test problem"
|
||||
instance_id: "simple_test_problem"
|
||||
- image_name: "python:3.11"
|
||||
problem_statement: "Another test problem"
|
||||
instance_id: "simple_test_problem_2"
|
||||
```
|
||||
|
||||
1. Must be available locally or on dockerhub.
|
||||
|
||||
!!! warning "Recent changes"
|
||||
The `instance_id` key was named `id` until Mar 16, 2025.
|
||||
This was changed to add compatibility with the standard SWE-bench format.
|
||||
However, we temporarily support both names.
|
||||
|
||||
!!! tip "More options"
|
||||
* There's a few more fields that you can populate. See [`SimpleBatchInstances`](../reference/batch_instances.md#sweagent.run.batch_instances.SimpleBatchInstance) for more information.
|
||||
* For all command line options with this instance type, see [`InstancesFromFile`](../reference/batch_instances.md#sweagent.run.batch_instances.InstancesFromFile).
|
||||
|
||||
## Huggingface instances
|
||||
|
||||
If you upload your dataset to Huggingface in a similar style as the example we just saw, you can load it like this:
|
||||
|
||||
```bash
|
||||
sweagent run-batch \
|
||||
...
|
||||
--instances.type huggingface \
|
||||
--instances.dataset_name "your_username/your_dataset" \
|
||||
--instances.split "dev" \
|
||||
--instances.slice :3 \
|
||||
--instances.shuffle=True
|
||||
```
|
||||
|
||||
!!! tip "All instance options"
|
||||
See [`InstancesFromHuggingFace`](../reference/batch_instances.md#sweagent.run.batch_instances.InstancesFromHuggingFace).
|
||||
|
||||
## Expert instances
|
||||
|
||||
If this is not enough for your use case, you can also specify a full set of `Environment`, `ProblemStatement`, and `Repository` config objects:
|
||||
|
||||
```bash
|
||||
sweagent run-batch \
|
||||
...
|
||||
--instances.type expert_file \
|
||||
--instances.path instances.yaml
|
||||
```
|
||||
|
||||
where `instances.yaml` could look like this:
|
||||
|
||||
```yaml title="instances.yaml"
|
||||
- env:
|
||||
deployment:
|
||||
type: docker
|
||||
image: python:3.11
|
||||
repo:
|
||||
type: github
|
||||
github_url: "https://github.com/swe-agent/test-repo"
|
||||
problem_statement:
|
||||
type: text
|
||||
text: "A simple test problem"
|
||||
id: "simple_test_problem"
|
||||
- env:
|
||||
deployment:
|
||||
type: docker
|
||||
image: python:3.11
|
||||
problem_statement:
|
||||
type: text
|
||||
text: "A simple test problem 2"
|
||||
id: "simple_test_problem_2"
|
||||
```
|
||||
|
||||
!!! tip "All instance options"
|
||||
See [`ExpertInstances`](../reference/batch_instances.md#sweagent.run.batch_instances.ExpertInstancesFromFile).
|
||||
|
||||
## Output files and next steps
|
||||
|
||||
All patches generated (all submissions/predictions of the agent) are saved to a `preds.json` file.
|
||||
If you interrupt `sweagent run-batch`, some of these or the file itself might be missing.
|
||||
You can use the `sweagent merge-preds` utility to fix this.
|
||||
|
||||
The `preds.json` file is very similar to the `.jsonl` format that is used for SWE-bench local runs.
|
||||
You can convert between the formats with
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
preds = json.loads(Path("preds.json").read_text())
|
||||
data = [{"instance_id": key, **value} for key, value in preds.items()]
|
||||
jsonl = [json.dumps(d) for d in data]
|
||||
Path("all_preds.jsonl").write_text("\\n".join(jsonl))
|
||||
```
|
||||
|
||||
!!! tip "Next up"
|
||||
|
||||
Take a look at our [competitive runs tutorial](competitive_runs.md)
|
||||
for more information on running on SWE-Bench and similar benchmarks.
|
||||
@@ -0,0 +1,299 @@
|
||||
# Command line basics
|
||||
|
||||
!!! abstract "Command line basics"
|
||||
This tutorial walks you through running SWE-agent from the command line.
|
||||
|
||||
* Please read our [hello world](hello_world.md) tutorial before proceeding.
|
||||
* This tutorial focuses on using SWE-agent as a tool to solve individual issues.
|
||||
Benchmarking SWE-agent is covered [separately](batch_mode.md).
|
||||
Finally, we have a different tutorial for using SWE-agent for [coding challenges](coding_challenges.md).
|
||||
|
||||
!!! tip "Mini-SWE-Agent"
|
||||
|
||||
Looking for a simple, no-fuzz version of SWE-agent that can also help you in your daily work?
|
||||
Check out [Mini-SWE-Agent](https://mini-swe-agent.com/)!
|
||||
|
||||
## A few examples
|
||||
|
||||
Before we start with a more structured explanation of the command line options, here are a few examples that you might find immediately useful:
|
||||
|
||||
```bash title="Fix a github issue"
|
||||
sweagent run \
|
||||
--agent.model.name=gpt-4o \
|
||||
--agent.model.per_instance_cost_limit=2.00 \
|
||||
--env.repo.github_url=https://github.com/SWE-agent/test-repo \
|
||||
--problem_statement.github_url=https://github.com/SWE-agent/test-repo/issues/1
|
||||
```
|
||||
|
||||
```bash title="Work on a github repo with a custom problem statement" hl_lines="4"
|
||||
sweagent run \
|
||||
...
|
||||
--env.repo.github_url=https://github.com/SWE-agent/test-repo \
|
||||
--problem_statement.text="Hey, can you fix all the bugs?"
|
||||
```
|
||||
|
||||
```bash title="Fix a bug in a local repository using a custom docker image" hl_lines="4 5 6"
|
||||
git clone https://github.com/SWE-agent/test-repo.git
|
||||
sweagent run \
|
||||
--agent.model.name=claude-sonnet-4-20250514 \
|
||||
--env.repo.path=test-repo \
|
||||
--problem_statement.path=test-repo/problem_statements/1.md \
|
||||
--env.deployment.image=python:3.12
|
||||
```
|
||||
|
||||
1. Make sure to add anthropic keys (or keys for your model provider) to the environment for this one!
|
||||
2. `--env.deployment.image` points to the [dockerhub image](https://hub.docker.com/_/python) of the same name
|
||||
|
||||
|
||||
For the next example, we will use a cloud-based execution environment instead of using local docker containers.
|
||||
For this, you first need to set up a modal account, install the necessary extra dependencies `pip install 'swe-rex[modal]'`, then run:
|
||||
|
||||
```bash title="Deployment on modal (cloud-based execution)" hl_lines="3"
|
||||
sweagent run \
|
||||
...
|
||||
--env.deployment.type=modal \
|
||||
--env.deployment.image=python:3.12
|
||||
```
|
||||
|
||||
!!! tip "All options"
|
||||
Run `sweagent run --help` to see all available options for `run.py`. This tutorial will only cover a subset of options.
|
||||
|
||||
## Configuration files
|
||||
|
||||
All configuration options can be specified either in one or more `.yaml` files, or as command line arguments. For example, our first command can be written as
|
||||
|
||||
=== "Command line"
|
||||
|
||||
```bash
|
||||
sweagent run --config my_run.yaml
|
||||
```
|
||||
|
||||
=== "Configuration file"
|
||||
|
||||
```yaml title="my_run.yaml"
|
||||
agent:
|
||||
model:
|
||||
name: gpt-4o
|
||||
per_instance_cost_limit: 2.00
|
||||
env:
|
||||
repo:
|
||||
github_url: https://github.com/SWE-agent/test-repo
|
||||
problem_statement:
|
||||
github_url: https://github.com/SWE-agent/test-repo/issues/1
|
||||
```
|
||||
|
||||
But we can also split it up into multiple files and additional command line options:
|
||||
|
||||
=== "Command line"
|
||||
|
||||
```bash
|
||||
# Note that you need --config in front of every config file
|
||||
sweagent run --config agent.yaml --config env.yaml \
|
||||
--problem_statement.text="Hey, can you fix all the bugs?"
|
||||
```
|
||||
|
||||
=== "`agent.yaml`"
|
||||
|
||||
```yaml title="agent.yaml"
|
||||
agent:
|
||||
model:
|
||||
name: gpt-4o
|
||||
per_instance_cost_limit: 2.00
|
||||
```
|
||||
|
||||
=== "`env.yaml`"
|
||||
|
||||
```yaml title="env.yaml"
|
||||
env:
|
||||
repo:
|
||||
github_url: https://github.com/SWE-agent/test-repo
|
||||
```
|
||||
|
||||
!!! warning "Multiple config files"
|
||||
Prior to version SWE-agent 1.1.0, configs were merged with simple dictionary updates,
|
||||
rather than a hierarchical merge, so specifying `agent` (or any key with subkeys) in the
|
||||
second config would completely overwrite all `agent` settings of the first config.
|
||||
This is fixed since SWE-agent 1.1.0.
|
||||
|
||||
The default config file is `config/default.yaml`. Let's take a look at it:
|
||||
|
||||
<details>
|
||||
<summary>Example: default config <code>default.yaml</code></summary>
|
||||
|
||||
```yaml
|
||||
--8<-- "config/default.yaml"
|
||||
```
|
||||
</details>
|
||||
|
||||
As you can see, this is where all the templates are defined!
|
||||
|
||||
This file is also loaded when no other `--config` options are specified.
|
||||
So to make sure that we get the default templates in the above examples with `--config`, we should have added
|
||||
|
||||
```bash
|
||||
--config config/default.yaml
|
||||
```
|
||||
|
||||
in addition to all the other `--config` options for the two examples above.
|
||||
|
||||
## Problem statements and union types <a id="union-types"></a>
|
||||
|
||||
!!! note "Operating in batch mode: Running on SWE-bench and other benchmark sets"
|
||||
If you want to run SWE-agent in batch mode on SWE-bench or another whole evaluation set, see
|
||||
[batch mode](batch_mode.md). This tutorial focuses on using SWE-agent on
|
||||
individual issues.
|
||||
|
||||
We've already seen a few examples of how to specify the problem to solve, namely
|
||||
|
||||
```bash
|
||||
--problem_statement.github_url=https://github.com/SWE-agent/test-repo/issues/1
|
||||
--problem_statement.path=/path/to/problem.md
|
||||
--problem_statement.text="..."
|
||||
```
|
||||
|
||||
Each of these types of problems can have specific configuration options.
|
||||
|
||||
To understand how this works, we'll need to understand **union types**.
|
||||
Running `sweagent run` builds up a configuration object that essentially looks like this:
|
||||
|
||||
```yaml
|
||||
agent: AgentConfig
|
||||
env: EnvironmentConfig
|
||||
problem_statement: TextProblemStatement | GithubIssue | FileProblemStatement # (1)!
|
||||
```
|
||||
|
||||
1. This is a union type, meaning that the problem statement can be one of the three types.
|
||||
|
||||
Each of these configuration objects has its own set of options:
|
||||
|
||||
* [`GithubIssue`](../reference/problem_statements.md#sweagent.agent.problem_statement.GithubIssue)
|
||||
* [`TextProblemStatement`](../reference/problem_statements.md#sweagent.agent.problem_statement.TextProblemStatement)
|
||||
* [`FileProblemStatement`](../reference/problem_statements.md#sweagent.agent.problem_statement.FileProblemStatement)
|
||||
|
||||
So how do we know which configuration object to initialize?
|
||||
It's simple: Each of these types has a different set of required options (e.g., `github_url` is required for `GithubIssue`, but not for `TextProblemStatement`).
|
||||
SWE-agent will automatically select the correct configuration object based on the command line options you provide.
|
||||
|
||||
However, you can also explicitly specify the type of problem statement you want to use by adding a `--problem_statement.type` option.
|
||||
|
||||
!!! tip "Union type errors"
|
||||
If you ever ran a SWE-agent command and got a very long error message about various configuration options not working, it is because for union types.
|
||||
If everything works correctly, we try to initialize every option until we find the one that works based on your inputs (for example stopping at `TextProblemStatement` if you provided a `--problem_statement.text`).
|
||||
However, if none of them work, we throw an error which then tells you why we cannot initialize any of the types (so it will tell you that `github_url` is required for `GithubIssue`, even though you might not even have tried to work on a GitHub issue).
|
||||
|
||||
<details>Example union type errors
|
||||
<summary>Example union type errors</summary>
|
||||
|
||||
This is the output of running
|
||||
|
||||
```bash
|
||||
sweagent run --problem_statement.path="test" --problem_statement.github_url="asdf"
|
||||
```
|
||||
|
||||
```
|
||||
--8<-- "docs/usage/union_type_error.txt"
|
||||
```
|
||||
</details>
|
||||
|
||||
If you want to read more about how this works, check out the [pydantic docs](https://docs.pydantic.dev/latest/concepts/unions/).
|
||||
|
||||
## Specifying the repository
|
||||
|
||||
The repository can be specified in a few different ways:
|
||||
|
||||
```bash
|
||||
--env.repo.github_url=https://github.com/SWE-agent/test-repo
|
||||
--env.repo.path=/path/to/repo
|
||||
```
|
||||
|
||||
Again, those are [union types](#union-types). See here for all the options:
|
||||
|
||||
* [`GithubRepoConfig`](../reference/repo.md#sweagent.environment.repo.GithubRepoConfig): Pull a repository from GitHub.
|
||||
* [`LocalRepoConfig`](../reference/repo.md#sweagent.environment.repo.LocalRepoConfig): Copies a repository from your local filesystem to the docker container.
|
||||
* [`PreExistingRepoConfig`](../reference/repo.md#sweagent.environment.repo.PreExistingRepoConfig): If you want to use a repository that already exists on the docker container.
|
||||
|
||||
## Configuring the environment
|
||||
|
||||
We mainly recommend you to build a docker image with all the dependencies you need and then use that with `--env.deployment.image`.
|
||||
In addition, you can also execute additional commands before starting the agent with `env.post_startup_commands`, which takes a list of commands, e.g.,
|
||||
|
||||
```bash
|
||||
sweagent run \
|
||||
--agent.model.name=claude-3-7-sonnet-latest \
|
||||
--env.post_startup_commands='["pip install flake8"]' \
|
||||
...
|
||||
```
|
||||
|
||||
Note the list syntax that is passed as a string using single ticks `'`. This is particularly important for `zsh` where `[`, `]` have special meaning.
|
||||
|
||||
Here's an example of a custom docker environment (it's also available in the repo as `docker/tiny_test.Dockerfile`):
|
||||
|
||||
<!-- There's a dockerfile annotation, but it somehow breaks annotations -->
|
||||
```bash title="tiny_test.Dockerfile"
|
||||
FROM python:3.11.10-bullseye # (1)!
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive # (2)!
|
||||
ENV TZ=Etc/UTC # (3)!
|
||||
|
||||
WORKDIR /
|
||||
|
||||
# SWE-ReX will always attempt to install its server into your docker container
|
||||
# however, this takes a couple of seconds. If we already provide it in the image,
|
||||
# this is much faster.
|
||||
RUN pip install pipx
|
||||
RUN pipx install swe-rex # (4)!
|
||||
RUN pipx ensurepath # (5)!
|
||||
|
||||
RUN pip install flake8 # (6)!
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
# This is where pipx installs things
|
||||
ENV PATH="$PATH:/root/.local/bin/" # (7)!
|
||||
```
|
||||
|
||||
Click on the :material-chevron-right-circle: icon in the right margin of the code snippet to see more information about the lines.
|
||||
|
||||
1. This is the base image.
|
||||
2. This is to avoid any interactive prompts from the package manager.
|
||||
3. Again, this avoids interactive prompts
|
||||
4. SWE-ReX is our execution backend. We start a small server within the container, which receives
|
||||
commands from the agent and executes them.
|
||||
5. This ensures that the path where pipx installs things is in the `$PATH` variable.
|
||||
6. This is to install flake8, which is used by some of our edit tools.
|
||||
7. Unfortunately, step 5 sometimes still doesn't properly add the SWE-ReX server to the `$PATH` variable.
|
||||
So we do it here again.
|
||||
|
||||
|
||||
## Taking actions
|
||||
|
||||
* You can use `--actions.apply_patch_locally` to have SWE-agent apply successful solution attempts to local files.
|
||||
* Alternatively, when running on a GitHub issue, you can have the agent automatically open a PR if the issue has been solved by supplying the `--actions.open_pr` flag.
|
||||
Please use this feature responsibly (on your own repositories or after careful consideration).
|
||||
|
||||
!!! tip "All action options"
|
||||
See [`RunSingleActionConfig`](../reference/run_single_config.md#sweagent.run.run_single.RunSingleActionConfig) for all action options.
|
||||
|
||||
Alternatively, you can always retrieve the patch that was generated by SWE-agent.
|
||||
Watch out for the following message in the log:
|
||||
|
||||
|
||||
```
|
||||
╭──────────────────────────── 🎉 Submission successful 🎉 ────────────────────────────╮
|
||||
│ SWE-agent has produced a patch that it believes will solve the issue you submitted! │
|
||||
│ Use the code snippet below to inspect or apply it! │
|
||||
╰─────────────────────────────────────────────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
And follow the instructions below it:
|
||||
|
||||
```bash
|
||||
# The patch has been saved to your local filesystem at:
|
||||
PATCH_FILE_PATH='/Users/.../patches/05917d.patch'
|
||||
# Inspect it:
|
||||
cat "${PATCH_FILE_PATH}"
|
||||
# Apply it to a local repository:
|
||||
cd <your local repo root>
|
||||
git apply "${PATCH_FILE_PATH}"
|
||||
```
|
||||
|
||||
{% include-markdown "../_footer.md" %}
|
||||
@@ -0,0 +1,23 @@
|
||||
# SWE-agent command line interface
|
||||
|
||||
All functionality of SWE-agent is available via the command line interface via the `sweagent` command.
|
||||
|
||||
You can run `sweagent --help` to see all subcommands.
|
||||
|
||||
## Running SWE-agent
|
||||
|
||||
* `sweagent run`: Run SWE-agent on a single issue ([tutorial](hello_world.md)).
|
||||
* `sweagent run-batch`: Run SWE-agent on a batch of issues ([tutorial](batch_mode.md)).
|
||||
* `sweagent run-replay`: Replay a trajectory file or a demo file. This means that you take all actions from the trajectory and execute them again in the environment. Useful for debugging your [tools](../config/tools.md) or for building new [demonstrations](../config/demonstrations.md).
|
||||
|
||||
## Inspecting runs
|
||||
|
||||
* `sweagent inspect` or `sweagent i`: Open the command line inspector ([more information](inspector.md)).
|
||||
* `sweagent inspector` or `sweagent I`: Open the web-based inspector ([more information](inspector.md)).
|
||||
* `sweagent quick-stats` or `sweagent qs`: When executed in a directory with trajectories, displays a summary of `exit_status` and more
|
||||
|
||||
## Advanced scripts
|
||||
|
||||
* `sweagent merge-preds`: Merge multiple prediction files into a single file.
|
||||
* `sweagent traj-to-demo`: Convert a trajectory file to an easy to edit demo file ([more information on demonstrations](../config/demonstrations.md)).
|
||||
* `sweagent remove-unfinished`: Remove unfinished trajectories
|
||||
@@ -0,0 +1,157 @@
|
||||
# Using SWE-agent for coding challenges
|
||||
|
||||
!!! abstract "Overview"
|
||||
It is easy to use SWE-agent to do more than just software engineering.
|
||||
For example, you can tell SWE-agent to work on leetcode or humaneval-style problems.
|
||||
|
||||
Required reading:
|
||||
Please first skim [hello world](hello_world.md) and [command line basics](cl_tutorial.md) to get familiar with the basics of SWE-agent.
|
||||
|
||||
|
||||
Let's start with a new problem statement. For this, put the problem you want to solve in a markdown file `problem.md`, for example:
|
||||
|
||||
<details>
|
||||
<summary>Example leetcode challenge</summary>
|
||||
|
||||
This is the <a href="https://leetcode.com/problems/first-missing-positive/">first missing positive</a> challenge.
|
||||
|
||||
```markdown
|
||||
--8<-- "docs/usage/leetcode_example.md"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Second, we need to specify a repository wherein SWE-agent will work.
|
||||
Here, we can simply create an empty folder (outside of the SWE-agent repository), and add a `main.py` file
|
||||
|
||||
```bash
|
||||
mkdir empty
|
||||
git init
|
||||
touch main.py
|
||||
echo "*.pyc" > .gitignore # to avoid binary files in patches
|
||||
```
|
||||
|
||||
and potentially populate it with the problem stub
|
||||
|
||||
```python
|
||||
from typing import List
|
||||
|
||||
|
||||
class Solution:
|
||||
def firstMissingPositive(self, nums: List[int]) -> int:
|
||||
```
|
||||
|
||||
!!! tip
|
||||
If some imports (like `List`) are missing in the problem stub (like they oftentimes do
|
||||
in leetcode) , SWE-agent will figure out how to add them. However, it might take an
|
||||
additional step, so it's best to directly specify them.
|
||||
|
||||
Make sure to commit all changes to the repository:
|
||||
|
||||
```bash
|
||||
git add . && git commit -m "Add problem stub"
|
||||
```
|
||||
|
||||
Now, we can let SWE-agent solve the problem:
|
||||
|
||||
```bash
|
||||
sweagent run \
|
||||
--config config/coding_challenge.yaml \
|
||||
--problem_statement.path=problem.md \
|
||||
--env.repo.path=/path/to/empty \
|
||||
--agent.model.name=gpt-4o \
|
||||
--agent.model.per_instance_cost_limit 3.0 \
|
||||
--actions.apply_patch_locally=True
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Output</summary>
|
||||
|
||||
```
|
||||
--8<-- "docs/usage/coding_challenge_output.log"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
SWE-agent will typically conclude with a message like
|
||||
|
||||
```
|
||||
INFO Trajectory saved to trajectories/fuchur/azure-gpt4__problem__coding_challenge__t-0.00__p-0.95__c-3.00__install-1/26d111.traj
|
||||
INFO Saved predictions to
|
||||
trajectories/fuchur/azure-gpt4__problem__coding_challenge__t-0.00__p-0.95__c-3.00__install-1/all_preds.jsonl
|
||||
╭──────────────────────────── 🎉 Submission successful 🎉 ────────────────────────────╮
|
||||
│ SWE-agent has produced a patch that it believes will solve the issue you submitted! │
|
||||
│ Use the code snippet below to inspect or apply it! │
|
||||
╰─────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
# The patch has been saved to your local filesystem at:
|
||||
PATCH_FILE_PATH='/Users/fuchur/Documents/24/git_sync/SWE-agent/trajectories/fuchur/azure-gpt4__problem__coding_challenge__t-0.00__p-0
|
||||
5__c-3.00__install-1/patches/26d111.patch'
|
||||
# Inspect it:
|
||||
cat "${PATCH_FILE_PATH}"
|
||||
# Apply it to a local repository:
|
||||
cd <your local repo root>
|
||||
git apply "${PATCH_FILE_PATH}"
|
||||
```
|
||||
|
||||
This informs you of the location of the [trajectory](trajectories.md) and of the patch file that contains the solution.
|
||||
|
||||
In our case, this looks like this:
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Patch (solution)</summary>
|
||||
|
||||
```patch
|
||||
diff --git a/main.py b/main.py
|
||||
index 1e7f08f..beabaa7 100644
|
||||
--- a/main.py
|
||||
+++ b/main.py
|
||||
@@ -2,4 +2,37 @@ from typing import List
|
||||
|
||||
|
||||
class Solution:
|
||||
- def firstMissingPositive(self, nums: List[int]) -> int:
|
||||
+ # Implementation of the function to find the smallest missing positive integer
|
||||
+ def firstMissingPositive(self, nums: List[int]) -> int:
|
||||
+ n = len(nums)
|
||||
+ # Mark numbers (num < 0) and (num > n) with a special marker number (n+1)
|
||||
+ # We can ignore those because if missing number is in the range (1, n+1)
|
||||
+ # it must be in the array
|
||||
+ for i in range(n):
|
||||
+ if nums[i] <= 0 or nums[i] > n:
|
||||
+ nums[i] = n + 1
|
||||
+
|
||||
+ # Use index as a hash key and number sign as a presence detector
|
||||
+ # For example, if nums[1] is negative that means that number `1` is present in the array
|
||||
+ for i in range(n):
|
||||
+ num = abs(nums[i])
|
||||
+ if num <= n:
|
||||
+ nums[num - 1] = -abs(nums[num - 1])
|
||||
+
|
||||
+ # Now the index of the first positive number is equal to the smallest missing positive number
|
||||
+ for i in range(n):
|
||||
+ if nums[i] > 0:
|
||||
+ return i + 1
|
||||
+
|
||||
+ # If no positive numbers were found, the smallest missing positive is n+1
|
||||
+ return n + 1
|
||||
+# Adding test cases to verify the implementation of firstMissingPositive
|
||||
+if __name__ == "__main__":
|
||||
+ sol = Solution()
|
||||
+ # Test case 1
|
||||
+ assert sol.firstMissingPositive([1, 2, 0]) == 3, "Test case 1 failed"
|
||||
+ # Test case 2
|
||||
+ assert sol.firstMissingPositive([3, 4, -1, 1]) == 2, "Test case 2 failed"
|
||||
+ # Test case 3
|
||||
+ assert sol.firstMissingPositive([7, 8, 9, 11, 12]) == 1, "Test case 3 failed"
|
||||
+ print("All test cases passed successfully.")
|
||||
```
|
||||
</details>
|
||||
|
||||
Because of the `--apply_patch_locally` flag, the patch has also already been applied to the repository,
|
||||
so you can also retrieve the final solution from there.
|
||||
|
||||
### Improving SWE-agent for coding challenges
|
||||
|
||||
By default, the demonstration trajectory the agent uses while solving a coding challenge is one in which it needs to solve a small bug in a short piece of code (from the HumanEvalFix dataset). Since that process is not too similar to solving a coding challenge, performance would probably substantially improve if the agent was given a demonstration trajectory in which it has to solve an actual programming challenge. To learn how to do that, read [this](../config/demonstrations.md).
|
||||
@@ -0,0 +1,87 @@
|
||||
# Competitive runs
|
||||
|
||||
!!! abstract "Running swe-agent competitively on benchmarks"
|
||||
This page contains information on our competitive runs on SWE-bench, as well as tips and tricks for evaluating on large batches.
|
||||
|
||||
* Please make sure you're familiar with [the command line basics](cl_tutorial.md) and the [batch mode](batch_mode.md)
|
||||
* The default examples will be executing code in a Docker sandbox, so make sure you have docker installed ([docker troubleshooting](../installation/tips.md)).
|
||||
|
||||
|
||||
## Current competitive configurations
|
||||
|
||||
!!! hint "Most recent configs"
|
||||
You can find all benchmark submission configs [here](https://github.com/SWE-agent/SWE-agent/tree/main/config/benchmarks)
|
||||
|
||||
Examples of configurations for SWE-bench submissions:
|
||||
|
||||
* [250225_anthropic_filemap_simple_review.yaml](https://github.com/SWE-agent/SWE-agent/blob/main/config/250225_anthropic_filemap_simple_review.yaml):
|
||||
This is our current default one-attempt config. It uses `claude-3-7-sonnet-20250219`.
|
||||
* [250212_sweagent_heavy_sbl.yaml](https://github.com/SWE-agent/SWE-agent/blob/main/config/250212_sweagent_heavy_sbl.yaml):
|
||||
This config runs 5 attempts with slightly different configurations using `claude-3-7-sonnet-latest`,
|
||||
then uses o1 to discriminate between them.
|
||||
This is a very expensive configuration.
|
||||
If you use it, also make sure to use Claude 3.7 instead of claude 3.5.
|
||||
|
||||
!!! warning "Retry configurations and command line arguments"
|
||||
Note that the structure of the configuration with agents that run multiple attempts is different from the one of the
|
||||
default agent. In particular, supplying options like `--agent.model.name` etc. will cause (potentially confusing)
|
||||
error messages. Take a look at the above configuration file to see the structure!
|
||||
|
||||
You can find the command with which to run each config at the top of the config file.
|
||||
|
||||
In order to run on multiple workers with Claude, you need to use multiple API keys in order to have enough cache break points.
|
||||
For this, please set the following environment variable before running
|
||||
|
||||
```bash
|
||||
# concatenate your keys
|
||||
export CLAUDE_API_KEY_ROTATION="KEY1:::KEY2:::KEY3"
|
||||
```
|
||||
|
||||
See our [notes on Claude](../config/models.md) for more details.
|
||||
|
||||
## Memory consumption
|
||||
|
||||
We run our configuration on a machine with 32GB memory and 8 cores.
|
||||
To avoid out-of-memory (OOM) situations, we recommend setting
|
||||
|
||||
```bash
|
||||
--instances.deployment.docker_args=--memory=10g
|
||||
```
|
||||
|
||||
limiting the maximum amount of memory per worker.
|
||||
|
||||
In our case, this completely avoided any instances of running OOM.
|
||||
|
||||
However, OOM situations can potentially lock you out of the server, so
|
||||
you might want to use a script like the following as a second layer
|
||||
defense to kill any process that hogs too much memory (note that this will affect _any_ script and not just swe-agent):
|
||||
|
||||
<details>
|
||||
<summary>Memory sentinel</summary>
|
||||
|
||||
```python
|
||||
--8<-- "docs/usage/memory_sentinel.py"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
If swe-agent dies or you frequently abort it, you might have leftover docker containers
|
||||
(they are cleaned up by normal termination of swe-agent but can be left over if it is killed).
|
||||
You can use a sentinel script like the following to clean them up periodically
|
||||
(note that this will affect _any_ long running container and not just those from swe-agent):
|
||||
|
||||
<details>
|
||||
<summary>Container sentinel</summary>
|
||||
|
||||
```bash
|
||||
--8<-- "docs/usage/containers_sentinel.sh"
|
||||
```
|
||||
</details>
|
||||
|
||||
## Tradeoffs between resolution rate and cost
|
||||
|
||||
* Running multi-attempt configurations will always be _very_ expensive. Don't use them if cost is of importance.
|
||||
* The simplest setting to keep cost in check is the per instance cost limit or turn limit.
|
||||
Without limiting cost, the average cost will also converge to infinity, as the agent will never stop iterating.
|
||||
With Claude 3.7, a cost-conservative limit would be $1 instance limit or lower and a turn count limit of 50.
|
||||
For our swe-bench submissions we use slightly higher limits (see the configs above).
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
while true; do
|
||||
echo "Checking for long-running containers..."
|
||||
# List all running containers with their uptime
|
||||
docker ps --format "{{.ID}} {{.RunningFor}}" | while read -r id running_for; do
|
||||
# Extract the number and unit from the running time
|
||||
if [[ $running_for =~ ([0-9]+)\ (hour|hours) ]]; then
|
||||
hours=${BASH_REMATCH[1]}
|
||||
if (( hours >= 2 )); then
|
||||
echo "Killing container $id (running for $running_for)..."
|
||||
docker kill "$id"
|
||||
fi
|
||||
elif [[ $running_for =~ ([0-9]+)\ (day|days) ]]; then
|
||||
# If it's running for at least a day, it's definitely over 2 hours
|
||||
echo "Killing container $id (running for $running_for)..."
|
||||
docker kill "$id"
|
||||
fi
|
||||
done
|
||||
echo "Sleeping for 10 minutes..."
|
||||
sleep 600 # Wait 600 seconds (10 minutes) before running again
|
||||
done
|
||||
@@ -0,0 +1,86 @@
|
||||
# Hello world
|
||||
|
||||
!!! abstract "Fix a GitHub issue with SWE-agent"
|
||||
In this tutorial, we will fix a GitHub issue with SWE-agent using the command line interface.
|
||||
|
||||
* Make sure you have [installed](../installation/index.md) SWE-agent and have a [language model](../installation/keys.md) set up.
|
||||
* We will be executing code in a Docker sandbox, so make sure you have docker installed ([docker troubleshooting](../installation/tips.md)).
|
||||
If you cannot run docker, skim this tutorial and see how you can run SWE-agent with cloud-based execution in the [command line basics tutorial](cl_tutorial.md).
|
||||
|
||||
!!! tip "Mini-SWE-Agent"
|
||||
|
||||
Looking for a simple, no-fuzz version of SWE-agent that can also help you in your daily work?
|
||||
Check out [Mini-SWE-Agent](https://mini-swe-agent.com/)!
|
||||
|
||||
After installing SWE-agent, you have the `sweagent` command available. Run `sweagent --help` to see the list of subcommands.
|
||||
The most important ones are
|
||||
|
||||
* `sweagent run`: Run SWE-agent on a single problem statement. This is covered on this page and for slightly more advanced examples in the [command line basics tutorial](cl_tutorial.md).
|
||||
* `sweagent run-batch`: Run SWE-agent on a list of problem statements. This is what you would use for benchmarking, or when
|
||||
working with a larger set of historic issues. Covered in the [batch mode tutorial](batch_mode.md).
|
||||
|
||||
In this tutorial, we will focus on the `run` subcommand.
|
||||
|
||||
Let's start with an absolutely trivial example and solve an issue about a simple syntax error ([`swe-agent/test-repo #1`](https://github.com/SWE-agent/test-repo/issues/1))
|
||||
|
||||
```bash
|
||||
sweagent run \
|
||||
--agent.model.name=claude-sonnet-4-20250514 \
|
||||
--agent.model.per_instance_cost_limit=2.00 \
|
||||
--env.repo.github_url=https://github.com/SWE-agent/test-repo \
|
||||
--problem_statement.github_url=https://github.com/SWE-agent/test-repo/issues/1
|
||||
```
|
||||
|
||||
The example above uses the `Claude Sonnet 4` model from Anthropic. Alternatively, you can for example use `GPT-4o` (from OpenAI)
|
||||
by setting `--agent.model.name=gpt-4o`.
|
||||
In order to use it, you need to add your keys to the environment:
|
||||
|
||||
```bash
|
||||
export ANTHROPIC_API_KEY=<your key>
|
||||
export OPENAI_API_KEY=<your key>
|
||||
```
|
||||
|
||||
alternatively, you can create a `.env` file in your working directory and put your keys in there like so:
|
||||
|
||||
```bash
|
||||
ANTHROPIC_API_KEY=<your key>
|
||||
OPENAI_API_KEY=<your key>
|
||||
```
|
||||
|
||||
We should support all models that you can think of.
|
||||
|
||||
!!! tip "Models and keys"
|
||||
Read more about configuring [models and API keys](../installation/keys.md).
|
||||
|
||||
<details>
|
||||
<summary>Output</summary>
|
||||
|
||||
```
|
||||
--8<-- "docs/usage/hello_world_output.txt"
|
||||
```
|
||||
</details>
|
||||
|
||||
As you can see, the command line options are hierarchical. At the top level, there are three important sections:
|
||||
|
||||
* `problem_statement`: What problem are you trying to solve?
|
||||
* `agent`: How do you want to solve the problem? This includes setting up the LM with `--agent.model`.
|
||||
* `env`: What is the environment in which the problem statement should be solved?
|
||||
This includes setting the repository/folder with the source files with `--env.repo`, as well as docker images and other dependencies.
|
||||
This will also control where the code is executed (in a local container or in the cloud).
|
||||
|
||||
|
||||
Watching the output, you can notice several stages:
|
||||
|
||||
1. Setting up the **deployment**: SWE-agent lets LMs execute actions in sandboxed environments. It can run these environments
|
||||
in docker containers (default), on modal, AWS fargate, or directly on your computer (not recommended).
|
||||
When the deployment starts, you will notice a "starting runtime" message that takes a few seconds. The runtime is
|
||||
what is executing the commands within your deployment.
|
||||
Deployments are managed by a package called [`SWE-ReX`](https://swe-rex.com/latest/).
|
||||
2. Setting up [**tools**](../config/tools.md): The tools that you specified are copied and installed within the environment.
|
||||
3. **System and instance prompts**: The initial instructions are shown to the LM. They are fully [configurable](../config/templates.md).
|
||||
4. **Main loop**: The LM starts to suggest and execute actions.
|
||||
5. **Submission**: The LM calls `submit` and we extract the patch (i.e., the changes to the source code that solve the problem).
|
||||
|
||||
The complete details of the run are saved as a ["trajectory" file](trajectories.md)). They can also be turned into new [demonstrations](../config/demonstrations.md) together with other log and output files.
|
||||
|
||||
Wetted your appetite? Head over to the [command line basics tutorial](cl_tutorial.md) to learn more about the options.
|
||||
@@ -0,0 +1,667 @@
|
||||
👋 INFO This is SWE-agent version 1.0.1 (hash='5206f8371274adb34f4946f8bee92f14615a91e1') with SWE-ReX version 1.2.1 (rex_hash='b30056ae7add48ccddef038f34e2a049889eff64').
|
||||
/opt/miniconda3/envs/swea13/lib/python3.13/site-packages/pydantic/_internal/_config.py:341: UserWarning: Valid config keys have changed in V2:
|
||||
* 'fields' has been removed
|
||||
warnings.warn(message, UserWarning)
|
||||
🔧 INFO Loading default config from /Users/fuchur/Documents/24/git_sync/SWE-agent/config/anthropic_filemap.yaml, because no other config file is specified. Specify --no_config_file to disable this.
|
||||
🔧 INFO Setting problem statement based on github issue url
|
||||
🔧 INFO Loaded environment variables from /Users/fuchur/Documents/24/git_sync/SWE-agent/.env
|
||||
🤖 WARN Claude 3.7 models do not support 128k context by default. Setting max output tokens to 64k. To enable 128k context, please set the completion_kwargs to {'extra_headers': {'anthropic-beta':
|
||||
'output-128k-2025-02-19'}}.
|
||||
🏃 INFO Starting environment
|
||||
🦖 INFO Building image python:3.11 to install a standalone python to /root. This might take a while (but you only have to do it once). To skip this step, set `python_standalone_dir` to None.
|
||||
🦖 DEBUG Found free port 54389
|
||||
🦖 INFO Starting container python3.11-ab0dbfce-00dd-4b4c-bbdc-aa16cbc3590f with image python:3.11 serving on port 54389
|
||||
🦖 DEBUG Command: "docker run --rm -p 54389:8000 --name python3.11-ab0dbfce-00dd-4b4c-bbdc-aa16cbc3590f sha256:9e1c9f1444e6352f8447e2acf9bb8ed31c3844ec059a517d3a8f05584276c535 /bin/sh -c
|
||||
'/root/python3.11/bin/swerex-remote --auth-token 011937af-978b-49fa-9808-48408adcb0a2'"
|
||||
🦖 INFO Starting runtime at 54389
|
||||
🦖 INFO Runtime started in 1.07s
|
||||
🪴 INFO Environment Initialized
|
||||
🪴 DEBUG Resetting repository SWE-agent__test-repo to commit HEAD
|
||||
🏃 INFO Running agent
|
||||
🤠 INFO Setting up agent for instance SWE-agent__test-repo-i1
|
||||
🤠 INFO Trajectory will be saved to
|
||||
/Users/fuchur/Documents/24/git_sync/SWE-agent/trajectories/fuchur/anthropic_filemap__claude-3-7-sonnet-latest__t-0.00__p-1.00__c-2.00___SWE-agent__test-repo-i1/SWE-agent__test-repo-i1/SWE-agent__test-re
|
||||
po-i1.traj
|
||||
🪴 DEBUG No environment variables to set
|
||||
🦖 DEBUG Uploading file from /Users/fuchur/Documents/24/git_sync/SWE-agent/tools/registry to /root/tools/registry
|
||||
🦖 DEBUG Created zip file at /var/folders/g3/1y2_hl1j16scls01cxqm76s80000gn/T/tmp_37eron8/zipped_transfer.zip
|
||||
🦖 DEBUG Uploading file from /Users/fuchur/Documents/24/git_sync/SWE-agent/tools/edit_anthropic to /root/tools/edit_anthropic
|
||||
🦖 DEBUG Created zip file at /var/folders/g3/1y2_hl1j16scls01cxqm76s80000gn/T/tmpbtgk4i0v/zipped_transfer.zip
|
||||
🦖 DEBUG Uploading file from /Users/fuchur/Documents/24/git_sync/SWE-agent/tools/review_on_submit_m to /root/tools/review_on_submit_m
|
||||
🦖 DEBUG Created zip file at /var/folders/g3/1y2_hl1j16scls01cxqm76s80000gn/T/tmpud9n_fx7/zipped_transfer.zip
|
||||
🧰 INFO Resetting tools
|
||||
🪴 DEBUG No environment variables to set
|
||||
🤠 INFO SYSTEM (main)
|
||||
You are a helpful assistant that can interact with a computer to solve tasks.
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
<uploaded_files>
|
||||
/SWE-agent__test-repo
|
||||
</uploaded_files>
|
||||
I've uploaded a python code repository in the directory /SWE-agent__test-repo. Consider the following PR description:
|
||||
|
||||
<pr_description>
|
||||
SyntaxError: invalid syntax
|
||||
I'm running `missing_colon.py` as follows:
|
||||
|
||||
```python
|
||||
division(23, 0)
|
||||
```
|
||||
|
||||
but I get the following error:
|
||||
|
||||
```
|
||||
File "/Users/fuchur/Documents/24/git_sync/swe-agent-test-repo/tests/./missing_colon.py", line 4
|
||||
def division(a: float, b: float) -> float
|
||||
^
|
||||
SyntaxError: invalid syntax
|
||||
```
|
||||
|
||||
</pr_description>
|
||||
|
||||
Can you help me implement the necessary changes to the repository so that the requirements specified in the <pr_description> are met?
|
||||
I've already taken care of all changes to any of the test files described in the <pr_description>. This means you DON'T have to modify the testing logic or any of the tests in any way!
|
||||
Your task is to make the minimal changes to non-tests files in the /SWE-agent__test-repo directory to ensure the <pr_description> is satisfied.
|
||||
Follow these steps to resolve the issue:
|
||||
1. As a first step, it might be a good idea to find and read code relevant to the <pr_description>
|
||||
2. Create a script to reproduce the error and execute it with `python <filename.py>` using the bash tool, to confirm the error
|
||||
3. Edit the sourcecode of the repo to resolve the issue
|
||||
4. Rerun your reproduce script and confirm that the error is fixed!
|
||||
5. Think about edgecases and make sure your fix handles them as well
|
||||
Your thinking should be thorough and so it's fine if it's very long.
|
||||
🤠 INFO ========================= STEP 1 =========================
|
||||
🤖 DEBUG n_cache_control: 1
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-e4e139ba-eeb0-42cc-a764-ce3dd3cfd953', created=1746538400, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="I'll help you implement the necessary changes to fix the SyntaxError in the repository. Let's follow the steps you
|
||||
outlined.\n\n## Step 1: Find and read code relevant to the PR description\n\nFirst, let's explore the repository structure to locate the `missing_colon.py` file mentioned in the PR description.",
|
||||
role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "find /SWE-agent__test-repo -name \\"missing_colon.py\\""}', name='bash'),
|
||||
id='toolu_01YUryV1Xd2yqWF3Gd3ka2ct', type='function')], function_call=None))], usage=Usage(completion_tokens=141, prompt_tokens=1553, total_tokens=1694, completion_tokens_details=None,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=0, text_tokens=None, image_tokens=None), cache_creation_input_tokens=1549, cache_read_input_tokens=0))
|
||||
🤖 DEBUG input_tokens=392, output_tokens=64, instance_cost=0.01, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=392, total_tokens_received=64, total_cost=0.01, total_api_calls=1
|
||||
🤠 INFO 💭 THOUGHT
|
||||
I'll help you implement the necessary changes to fix the SyntaxError in the repository. Let's follow the steps you outlined.
|
||||
|
||||
## Step 1: Find and read code relevant to the PR description
|
||||
|
||||
First, let's explore the repository structure to locate the `missing_colon.py` file mentioned in the PR description.
|
||||
|
||||
🎬 ACTION
|
||||
find /SWE-agent__test-repo -name "missing_colon.py"
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
/SWE-agent__test-repo/tests/missing_colon.py
|
||||
/SWE-agent__test-repo/src/testpkg/missing_colon.py
|
||||
🤠 INFO ========================= STEP 2 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-0ac17933-0d78-4445-b469-a4441fb57403', created=1746538404, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Great! I found two instances of `missing_colon.py`. Let's examine both files to understand what's going on.",
|
||||
role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "view", "path": "/SWE-agent__test-repo/tests/missing_colon.py"}',
|
||||
name='str_replace_editor'), id='toolu_01HGHHFG2PHgdM3HtpfpmqMZ', type='function')], function_call=None))], usage=Usage(completion_tokens=119, prompt_tokens=1752, total_tokens=1871,
|
||||
completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=1549, text_tokens=None, image_tokens=None), cache_creation_input_tokens=197,
|
||||
cache_read_input_tokens=1549))
|
||||
🤖 DEBUG input_tokens=502, output_tokens=25, instance_cost=0.02, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=894, total_tokens_received=89, total_cost=0.02, total_api_calls=2
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Great! I found two instances of `missing_colon.py`. Let's examine both files to understand what's going on.
|
||||
|
||||
🎬 ACTION
|
||||
str_replace_editor view /SWE-agent__test-repo/tests/missing_colon.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
Here's the result of running `cat -n` on /SWE-agent__test-repo/tests/missing_colon.py:
|
||||
1 #!/usr/bin/env python3
|
||||
2
|
||||
3
|
||||
4 def division(a: float, b: float) -> float
|
||||
5 return a/b
|
||||
6
|
||||
7
|
||||
8 if __name__ == "__main__":
|
||||
9 print(division(123, 15))
|
||||
10
|
||||
11
|
||||
🤠 INFO ========================= STEP 3 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-34ea0f17-9082-436b-b832-ea1dcca638c8', created=1746538409, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=0, function=Function(arguments='{"command": "view",
|
||||
"path": "/SWE-agent__test-repo/src/testpkg/missing_colon.py"}', name='str_replace_editor'), id='toolu_01QKQhZWPgtvPcVkgMzHWecB', type='function')], function_call=None))],
|
||||
usage=Usage(completion_tokens=95, prompt_tokens=2006, total_tokens=2101, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=1746,
|
||||
text_tokens=None, image_tokens=None), cache_creation_input_tokens=254, cache_read_input_tokens=1746))
|
||||
🤖 DEBUG input_tokens=666, output_tokens=0, instance_cost=0.02, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=1,560, total_tokens_received=89, total_cost=0.02, total_api_calls=3
|
||||
🤠 INFO 💭 THOUGHT
|
||||
|
||||
|
||||
🎬 ACTION
|
||||
str_replace_editor view /SWE-agent__test-repo/src/testpkg/missing_colon.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
Here's the result of running `cat -n` on /SWE-agent__test-repo/src/testpkg/missing_colon.py:
|
||||
1 #!/usr/bin/env python3
|
||||
2
|
||||
3
|
||||
4 def division(a: float, b: float) -> float
|
||||
5 return a/b
|
||||
6
|
||||
7
|
||||
8 if __name__ == "__main__":
|
||||
9 print(division(123, 15))
|
||||
10
|
||||
11
|
||||
🤠 INFO ========================= STEP 4 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-65910764-3965-4117-a2da-dd14a7e6d711', created=1746538416, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="I can see the issue now. In both files, there's a missing colon (`:`) at the end of the function definition on line 4. In
|
||||
Python, function definitions need to end with a colon before the function body. The error message in the PR description points to this exact issue.\n\n## Step 2: Create a script to reproduce the
|
||||
error\n\nLet's create a simple script to reproduce the error:", role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "create", "path":
|
||||
"/SWE-agent__test-repo/reproduce_error.py", "file_text": "#!/usr/bin/env python3\\n\\nimport sys\\nsys.path.append(\'/SWE-agent__test-repo\')\\nfrom tests.missing_colon import division\\n\\nif __name__
|
||||
== \\"__main__\\":\\n try:\\n result = division(23, 0)\\n print(f\\"Result: {result}\\")\\n except Exception as e:\\n print(f\\"Error: {type(e).__name__}: {e}\\")"}',
|
||||
name='str_replace_editor'), id='toolu_01AsaWoxeJrC44duFwrNejUM', type='function')], function_call=None))], usage=Usage(completion_tokens=295, prompt_tokens=2240, total_tokens=2535,
|
||||
completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=2000, text_tokens=None, image_tokens=None), cache_creation_input_tokens=234,
|
||||
cache_read_input_tokens=2000))
|
||||
🤖 DEBUG input_tokens=809, output_tokens=84, instance_cost=0.03, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=2,369, total_tokens_received=173, total_cost=0.03, total_api_calls=4
|
||||
🤠 INFO 💭 THOUGHT
|
||||
I can see the issue now. In both files, there's a missing colon (`:`) at the end of the function definition on line 4. In Python, function definitions need to end with a colon before the function body.
|
||||
The error message in the PR description points to this exact issue.
|
||||
|
||||
## Step 2: Create a script to reproduce the error
|
||||
|
||||
Let's create a simple script to reproduce the error:
|
||||
|
||||
🎬 ACTION
|
||||
str_replace_editor create /SWE-agent__test-repo/reproduce_error.py --file_text '#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
sys.path.append('"'"'/SWE-agent__test-repo'"'"')
|
||||
from tests.missing_colon import division
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
result = division(23, 0)
|
||||
print(f"Result: {result}")
|
||||
except Exception as e:
|
||||
print(f"Error: {type(e).__name__}: {e}")'
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
File created successfully at: /SWE-agent__test-repo/reproduce_error.py
|
||||
🤠 INFO ========================= STEP 5 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-74734059-3124-4d62-85a2-2f9c0dbafb67', created=1746538419, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Now let's run this script to confirm the error:", role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1,
|
||||
function=Function(arguments='{"command": "cd /SWE-agent__test-repo && python reproduce_error.py"}', name='bash'), id='toolu_01DUDQaTLvo9wMtdoRuLzng2', type='function')], function_call=None))],
|
||||
usage=Usage(completion_tokens=81, prompt_tokens=2570, total_tokens=2651, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=2234,
|
||||
text_tokens=None, image_tokens=None), cache_creation_input_tokens=330, cache_read_input_tokens=2234))
|
||||
🤖 DEBUG input_tokens=1,041, output_tokens=11, instance_cost=0.03, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=3,410, total_tokens_received=184, total_cost=0.03, total_api_calls=5
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Now let's run this script to confirm the error:
|
||||
|
||||
🎬 ACTION
|
||||
cd /SWE-agent__test-repo && python reproduce_error.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
Traceback (most recent call last):
|
||||
File "/SWE-agent__test-repo/reproduce_error.py", line 5, in <module>
|
||||
from tests.missing_colon import division
|
||||
File "/SWE-agent__test-repo/tests/missing_colon.py", line 4
|
||||
def division(a: float, b: float) -> float
|
||||
^
|
||||
SyntaxError: expected ':'
|
||||
🤠 INFO ========================= STEP 6 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-7538e5bc-d5ae-4845-9bd1-aff6388c779e', created=1746538424, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Perfect! We've reproduced the error. The error message confirms that there's a missing colon at the end of the function
|
||||
definition.\n\n## Step 3: Edit the source code to resolve the issue\n\nNow, let's fix both instances of the file. We need to add a colon at the end of the function definition on line 4.\n\nFirst, let's
|
||||
fix the file in the tests directory:", role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "str_replace", "path":
|
||||
"/SWE-agent__test-repo/tests/missing_colon.py", "old_str": "def division(a: float, b: float) -> float\\n return a/b", "new_str": "def division(a: float, b: float) -> float:\\n return a/b"}',
|
||||
name='str_replace_editor'), id='toolu_01XZBkQK2o3Z64j5oAc4uysv', type='function')], function_call=None))], usage=Usage(completion_tokens=255, prompt_tokens=2769, total_tokens=3024,
|
||||
completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=2564, text_tokens=None, image_tokens=None), cache_creation_input_tokens=199,
|
||||
cache_read_input_tokens=2564))
|
||||
🤖 DEBUG input_tokens=1,160, output_tokens=81, instance_cost=0.04, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=4,570, total_tokens_received=265, total_cost=0.04, total_api_calls=6
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Perfect! We've reproduced the error. The error message confirms that there's a missing colon at the end of the function definition.
|
||||
|
||||
## Step 3: Edit the source code to resolve the issue
|
||||
|
||||
Now, let's fix both instances of the file. We need to add a colon at the end of the function definition on line 4.
|
||||
|
||||
First, let's fix the file in the tests directory:
|
||||
|
||||
🎬 ACTION
|
||||
str_replace_editor str_replace /SWE-agent__test-repo/tests/missing_colon.py --old_str 'def division(a: float, b: float) -> float
|
||||
return a/b' --new_str 'def division(a: float, b: float) -> float:
|
||||
return a/b'
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
The file /SWE-agent__test-repo/tests/missing_colon.py has been edited. Here's the result of running `cat -n` on a snippet of /SWE-agent__test-repo/tests/missing_colon.py:
|
||||
1 #!/usr/bin/env python3
|
||||
2
|
||||
3
|
||||
4 def division(a: float, b: float) -> float:
|
||||
5 return a/b
|
||||
6
|
||||
7
|
||||
8 if __name__ == "__main__":
|
||||
Review the changes and make sure they are as expected. Edit the file again if necessary.
|
||||
🤠 INFO ========================= STEP 7 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-a89e5679-cfd2-48f8-988c-b515e960d3ac', created=1746538429, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Now, let's fix the file in the src directory:", role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1,
|
||||
function=Function(arguments='{"command": "str_replace", "path": "/SWE-agent__test-repo/src/testpkg/missing_colon.py", "old_str": "def division(a: float, b: float) -> float\\n return a/b", "new_str":
|
||||
"def division(a: float, b: float) -> float:\\n return a/b"}', name='str_replace_editor'), id='toolu_01FqQxXsasC7qavJozEmcba1', type='function')], function_call=None))],
|
||||
usage=Usage(completion_tokens=185, prompt_tokens=3185, total_tokens=3370, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=2763,
|
||||
text_tokens=None, image_tokens=None), cache_creation_input_tokens=417, cache_read_input_tokens=2763))
|
||||
🤖 DEBUG input_tokens=1,449, output_tokens=12, instance_cost=0.04, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=6,019, total_tokens_received=277, total_cost=0.04, total_api_calls=7
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Now, let's fix the file in the src directory:
|
||||
|
||||
🎬 ACTION
|
||||
str_replace_editor str_replace /SWE-agent__test-repo/src/testpkg/missing_colon.py --old_str 'def division(a: float, b: float) -> float
|
||||
return a/b' --new_str 'def division(a: float, b: float) -> float:
|
||||
return a/b'
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
The file /SWE-agent__test-repo/src/testpkg/missing_colon.py has been edited. Here's the result of running `cat -n` on a snippet of /SWE-agent__test-repo/src/testpkg/missing_colon.py:
|
||||
1 #!/usr/bin/env python3
|
||||
2
|
||||
3
|
||||
4 def division(a: float, b: float) -> float:
|
||||
5 return a/b
|
||||
6
|
||||
7
|
||||
8 if __name__ == "__main__":
|
||||
Review the changes and make sure they are as expected. Edit the file again if necessary.
|
||||
🤠 INFO ========================= STEP 8 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-c0405095-900e-45b4-8ade-3dd0f7b9ae68', created=1746538432, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="## Step 4: Rerun the script to confirm the fix\n\nLet's run our script again to confirm that the error is fixed:",
|
||||
role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "cd /SWE-agent__test-repo && python reproduce_error.py"}', name='bash'),
|
||||
id='toolu_01D6GnG7M5dzoo6DrV2m4kKT', type='function')], function_call=None))], usage=Usage(completion_tokens=99, prompt_tokens=3539, total_tokens=3638, completion_tokens_details=None,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=3180, text_tokens=None, image_tokens=None), cache_creation_input_tokens=355, cache_read_input_tokens=3180))
|
||||
🤖 DEBUG input_tokens=1,674, output_tokens=29, instance_cost=0.05, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=7,693, total_tokens_received=306, total_cost=0.05, total_api_calls=8
|
||||
🤠 INFO 💭 THOUGHT
|
||||
## Step 4: Rerun the script to confirm the fix
|
||||
|
||||
Let's run our script again to confirm that the error is fixed:
|
||||
|
||||
🎬 ACTION
|
||||
cd /SWE-agent__test-repo && python reproduce_error.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
Error: ZeroDivisionError: division by zero
|
||||
🤠 INFO ========================= STEP 9 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-06c071f0-2c38-44e4-845d-10f9f25a58d3', created=1746538442, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Great! The syntax error is fixed. Now we're getting a different error, which is expected because we're trying to divide by
|
||||
zero. This confirms that our fix for the syntax error is working correctly.\n\n## Step 5: Think about edge cases and make sure the fix handles them\n\nLet's modify our script to test with valid inputs
|
||||
to ensure the function works correctly:", role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "str_replace", "path":
|
||||
"/SWE-agent__test-repo/reproduce_error.py", "old_str": "if __name__ == \\"__main__\\":\\n try:\\n result = division(23, 0)\\n print(f\\"Result: {result}\\")\\n except Exception as
|
||||
e:\\n print(f\\"Error: {type(e).__name__}: {e}\\")", "new_str": "if __name__ == \\"__main__\\":\\n # Test with valid inputs\\n try:\\n result = division(23, 5)\\n
|
||||
print(f\\"Result of 23/5: {result}\\")\\n except Exception as e:\\n print(f\\"Error: {type(e).__name__}: {e}\\")\\n \\n # Test with zero division (edge case)\\n try:\\n result
|
||||
= division(23, 0)\\n print(f\\"Result of 23/0: {result}\\")\\n except Exception as e:\\n print(f\\"Error: {type(e).__name__}: {e}\\")\\n \\n # Test with non-numeric inputs
|
||||
(edge case)\\n try:\\n result = division(\\"23\\", 5)\\n print(f\\"Result of \'23\'/5: {result}\\")\\n except Exception as e:\\n print(f\\"Error: {type(e).__name__}:
|
||||
{e}\\")"}', name='str_replace_editor'), id='toolu_01LsPJ5ZroMPv8nybnEePMkg', type='function')], function_call=None))], usage=Usage(completion_tokens=479, prompt_tokens=3665, total_tokens=4144,
|
||||
completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=3535, text_tokens=None, image_tokens=None), cache_creation_input_tokens=126,
|
||||
cache_read_input_tokens=3535))
|
||||
🤖 DEBUG input_tokens=1,736, output_tokens=75, instance_cost=0.06, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=9,429, total_tokens_received=381, total_cost=0.06, total_api_calls=9
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Great! The syntax error is fixed. Now we're getting a different error, which is expected because we're trying to divide by zero. This confirms that our fix for the syntax error is working correctly.
|
||||
|
||||
## Step 5: Think about edge cases and make sure the fix handles them
|
||||
|
||||
Let's modify our script to test with valid inputs to ensure the function works correctly:
|
||||
|
||||
🎬 ACTION
|
||||
str_replace_editor str_replace /SWE-agent__test-repo/reproduce_error.py --old_str 'if __name__ == "__main__":
|
||||
try:
|
||||
result = division(23, 0)
|
||||
print(f"Result: {result}")
|
||||
except Exception as e:
|
||||
print(f"Error: {type(e).__name__}: {e}")' --new_str 'if __name__ == "__main__":
|
||||
# Test with valid inputs
|
||||
try:
|
||||
result = division(23, 5)
|
||||
print(f"Result of 23/5: {result}")
|
||||
except Exception as e:
|
||||
print(f"Error: {type(e).__name__}: {e}")
|
||||
|
||||
# Test with zero division (edge case)
|
||||
try:
|
||||
result = division(23, 0)
|
||||
print(f"Result of 23/0: {result}")
|
||||
except Exception as e:
|
||||
print(f"Error: {type(e).__name__}: {e}")
|
||||
|
||||
# Test with non-numeric inputs (edge case)
|
||||
try:
|
||||
result = division("23", 5)
|
||||
print(f"Result of '"'"'23'"'"'/5: {result}")
|
||||
except Exception as e:
|
||||
print(f"Error: {type(e).__name__}: {e}")'
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
The file /SWE-agent__test-repo/reproduce_error.py has been edited. Here's the result of running `cat -n` on a snippet of /SWE-agent__test-repo/reproduce_error.py:
|
||||
2
|
||||
3 import sys
|
||||
4 sys.path.append('/SWE-agent__test-repo')
|
||||
5 from tests.missing_colon import division
|
||||
6
|
||||
7 if __name__ == "__main__":
|
||||
8 # Test with valid inputs
|
||||
9 try:
|
||||
10 result = division(23, 5)
|
||||
11 print(f"Result of 23/5: {result}")
|
||||
12 except Exception as e:
|
||||
13 print(f"Error: {type(e).__name__}: {e}")
|
||||
14
|
||||
15 # Test with zero division (edge case)
|
||||
16 try:
|
||||
17 result = division(23, 0)
|
||||
18 print(f"Result of 23/0: {result}")
|
||||
19 except Exception as e:
|
||||
20 print(f"Error: {type(e).__name__}: {e}")
|
||||
21
|
||||
22 # Test with non-numeric inputs (edge case)
|
||||
23 try:
|
||||
24 result = division("23", 5)
|
||||
25 print(f"Result of '23'/5: {result}")
|
||||
26 except Exception as e:
|
||||
27 print(f"Error: {type(e).__name__}: {e}")
|
||||
Review the changes and make sure they are as expected. Edit the file again if necessary.
|
||||
🤠 INFO ========================= STEP 10 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-7eeef2cd-5f7f-478a-b04e-5c08fe931681', created=1746538445, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Now let's run the updated script to test our function with different inputs:", role='assistant',
|
||||
tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "cd /SWE-agent__test-repo && python reproduce_error.py"}', name='bash'), id='toolu_01PUxRyfhcoATyPuYb2rGGuv',
|
||||
type='function')], function_call=None))], usage=Usage(completion_tokens=85, prompt_tokens=4557, total_tokens=4642, completion_tokens_details=None,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=3661, text_tokens=None, image_tokens=None), cache_creation_input_tokens=893, cache_read_input_tokens=3661))
|
||||
🤖 DEBUG input_tokens=2,492, output_tokens=15, instance_cost=0.07, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=11,921, total_tokens_received=396, total_cost=0.07, total_api_calls=10
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Now let's run the updated script to test our function with different inputs:
|
||||
|
||||
🎬 ACTION
|
||||
cd /SWE-agent__test-repo && python reproduce_error.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
Result of 23/5: 4.6
|
||||
Error: ZeroDivisionError: division by zero
|
||||
Error: TypeError: unsupported operand type(s) for /: 'str' and 'int'
|
||||
🤠 INFO ========================= STEP 11 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-17f662dd-690b-4812-b979-02b47f31f22b', created=1746538449, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Perfect! Our function is now working correctly:\n1. It successfully performs division with valid inputs (23/5 = 4.6)\n2. It
|
||||
properly raises a ZeroDivisionError when dividing by zero\n3. It raises a TypeError when trying to divide a string by an integer\n\nLet's also run the original file directly to make sure it works:",
|
||||
role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "cd /SWE-agent__test-repo && python tests/missing_colon.py"}', name='bash'),
|
||||
id='toolu_01RHEHw65rQsYv5x41cRoARP', type='function')], function_call=None))], usage=Usage(completion_tokens=152, prompt_tokens=4707, total_tokens=4859, completion_tokens_details=None,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=4554, text_tokens=None, image_tokens=None), cache_creation_input_tokens=150, cache_read_input_tokens=4554))
|
||||
🤖 DEBUG input_tokens=2,571, output_tokens=72, instance_cost=0.07, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=14,492, total_tokens_received=468, total_cost=0.07, total_api_calls=11
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Perfect! Our function is now working correctly:
|
||||
1. It successfully performs division with valid inputs (23/5 = 4.6)
|
||||
2. It properly raises a ZeroDivisionError when dividing by zero
|
||||
3. It raises a TypeError when trying to divide a string by an integer
|
||||
|
||||
Let's also run the original file directly to make sure it works:
|
||||
|
||||
🎬 ACTION
|
||||
cd /SWE-agent__test-repo && python tests/missing_colon.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
8.2
|
||||
🤠 INFO ========================= STEP 12 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-c8c1f2f8-14fb-41a8-9388-2a8b78f1d0a6', created=1746538453, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=0, function=Function(arguments='{"command": "cd
|
||||
/SWE-agent__test-repo && python src/testpkg/missing_colon.py"}', name='bash'), id='toolu_01MiJkjBLRpnuacB4SqBNuC3', type='function')], function_call=None))], usage=Usage(completion_tokens=76,
|
||||
prompt_tokens=4877, total_tokens=4953, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=4704, text_tokens=None, image_tokens=None),
|
||||
cache_creation_input_tokens=170, cache_read_input_tokens=4704))
|
||||
🤖 DEBUG input_tokens=2,673, output_tokens=0, instance_cost=0.07, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=17,165, total_tokens_received=468, total_cost=0.07, total_api_calls=12
|
||||
🤠 INFO 💭 THOUGHT
|
||||
|
||||
|
||||
🎬 ACTION
|
||||
cd /SWE-agent__test-repo && python src/testpkg/missing_colon.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
8.2
|
||||
🤠 INFO ========================= STEP 13 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-36239584-4d33-4901-af1c-0212364d238b', created=1746538459, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='stop', index=0, message=Message(content="Great! Both files are now working correctly and producing the expected output (123/15 = 8.2).\n\n## Summary\n\nThe issue was a
|
||||
simple syntax error in the function definition. In Python, function definitions must end with a colon (`:`) before the function body. The error was present in both
|
||||
`/SWE-agent__test-repo/tests/missing_colon.py` and `/SWE-agent__test-repo/src/testpkg/missing_colon.py`.\n\nThe fix was to add the missing colon at the end of the function definition:\n```python\ndef
|
||||
division(a: float, b: float) -> float: # Added colon here\n return a/b\n```\n\nAfter making this change, the code now runs correctly. We've also tested it with various inputs to ensure it handles
|
||||
different scenarios properly:\n1. Normal division works as expected\n2. Division by zero raises the appropriate ZeroDivisionError\n3. Invalid input types raise the appropriate TypeError\n\nThis fix was
|
||||
minimal and focused only on the syntax error mentioned in the PR description.", role='assistant', tool_calls=None, function_call=None))], usage=Usage(completion_tokens=243, prompt_tokens=4971,
|
||||
total_tokens=5214, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=4874, text_tokens=None, image_tokens=None),
|
||||
cache_creation_input_tokens=94, cache_read_input_tokens=4874))
|
||||
🤖 DEBUG input_tokens=2,705, output_tokens=214, instance_cost=0.08, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=19,870, total_tokens_received=682, total_cost=0.08, total_api_calls=13
|
||||
🤠 WARN Requerying model after FunctionCallingFormatError (1th requery)
|
||||
🤠 WARN Your last output did not use any tool calls!
|
||||
Please make sure your output includes exactly _ONE_ function call!
|
||||
You must invoke the function directly using the function call format.
|
||||
You cannot invoke commands with ```, you have to use the function call format.
|
||||
If you think you have already resolved the issue, please submit your changes by running the `submit` command.
|
||||
If you think you cannot solve the problem, please run `exit_forfeit` (if available) or `submit`.
|
||||
Else, please continue with a new tool call!
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-ffd05c35-ed01-4695-9a20-f81b18e326d1', created=1746538463, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="You're right, I apologize for the oversight. Let me submit the changes since we've successfully fixed the issue.",
|
||||
role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{}', name='submit'), id='toolu_01Uc1pRvAk6bTLFuQQVWZiUF', type='function')], function_call=None))],
|
||||
usage=Usage(completion_tokens=59, prompt_tokens=5332, total_tokens=5391, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=4968,
|
||||
text_tokens=None, image_tokens=None), cache_creation_input_tokens=0, cache_read_input_tokens=4968))
|
||||
🤖 DEBUG input_tokens=3,026, output_tokens=23, instance_cost=0.08, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=22,896, total_tokens_received=705, total_cost=0.08, total_api_calls=14
|
||||
🤠 INFO 💭 THOUGHT
|
||||
You're right, I apologize for the oversight. Let me submit the changes since we've successfully fixed the issue.
|
||||
|
||||
🎬 ACTION
|
||||
submit
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
Thank you for your work on this issue. Please carefully follow the steps below to help review your changes.
|
||||
|
||||
1. If you made any changes to your code after running the reproduction script, please run the reproduction script again.
|
||||
If the reproduction script is failing, please revisit your changes and make sure they are correct.
|
||||
If you have already removed your reproduction script, please ignore this step.
|
||||
2. Remove your reproduction script (if you haven't done so already).
|
||||
3. If you have modified any TEST files, please revert them to the state they had before you started fixing the issue.
|
||||
You can do this with `git checkout -- /path/to/test/file.py`. Use below <diff> to find the files you need to revert.
|
||||
4. Run the submit command again to confirm.
|
||||
|
||||
Here is a list of all of your changes:
|
||||
|
||||
<diff>
|
||||
diff --git a/reproduce_error.py b/reproduce_error.py
|
||||
new file mode 100644
|
||||
index 0000000..0c95db1
|
||||
--- /dev/null
|
||||
+++ b/reproduce_error.py
|
||||
@@ -0,0 +1,27 @@
|
||||
+#!/usr/bin/env python3
|
||||
+
|
||||
+import sys
|
||||
+sys.path.append('/SWE-agent__test-repo')
|
||||
+from tests.missing_colon import division
|
||||
+
|
||||
+if __name__ == "__main__":
|
||||
+ # Test with valid inputs
|
||||
+ try:
|
||||
+ result = division(23, 5)
|
||||
+ print(f"Result of 23/5: {result}")
|
||||
+ except Exception as e:
|
||||
+ print(f"Error: {type(e).__name__}: {e}")
|
||||
+
|
||||
+ # Test with zero division (edge case)
|
||||
+ try:
|
||||
+ result = division(23, 0)
|
||||
+ print(f"Result of 23/0: {result}")
|
||||
+ except Exception as e:
|
||||
+ print(f"Error: {type(e).__name__}: {e}")
|
||||
+
|
||||
+ # Test with non-numeric inputs (edge case)
|
||||
+ try:
|
||||
+ result = division("23", 5)
|
||||
+ print(f"Result of '23'/5: {result}")
|
||||
+ except Exception as e:
|
||||
+ print(f"Error: {type(e).__name__}: {e}")
|
||||
\ No newline at end of file
|
||||
diff --git a/src/testpkg/missing_colon.py b/src/testpkg/missing_colon.py
|
||||
index 20edef5..5857437 100755
|
||||
--- a/src/testpkg/missing_colon.py
|
||||
+++ b/src/testpkg/missing_colon.py
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
-def division(a: float, b: float) -> float
|
||||
+def division(a: float, b: float) -> float:
|
||||
return a/b
|
||||
|
||||
|
||||
diff --git a/tests/missing_colon.py b/tests/missing_colon.py
|
||||
index 20edef5..5857437 100755
|
||||
--- a/tests/missing_colon.py
|
||||
+++ b/tests/missing_colon.py
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
-def division(a: float, b: float) -> float
|
||||
+def division(a: float, b: float) -> float:
|
||||
return a/b
|
||||
|
||||
|
||||
|
||||
</diff>
|
||||
🤠 INFO ========================= STEP 15 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-6879799c-beea-4522-ad69-b8ad3b73abd1', created=1746538467, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content='I need to remove the reproduction script before submitting again:', role='assistant',
|
||||
tool_calls=[ChatCompletionMessageToolCall(index=1, function=Function(arguments='{"command": "rm /SWE-agent__test-repo/reproduce_error.py"}', name='bash'), id='toolu_01XQwhvtX6ivmA2UMay32HfR',
|
||||
type='function')], function_call=None))], usage=Usage(completion_tokens=81, prompt_tokens=5882, total_tokens=5963, completion_tokens_details=None,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=4968, text_tokens=None, image_tokens=None), cache_creation_input_tokens=912, cache_read_input_tokens=4968))
|
||||
🤖 DEBUG input_tokens=3,433, output_tokens=11, instance_cost=0.09, cost=0.01
|
||||
🤖 DEBUG total_tokens_sent=26,329, total_tokens_received=716, total_cost=0.09, total_api_calls=15
|
||||
🤠 INFO 💭 THOUGHT
|
||||
I need to remove the reproduction script before submitting again:
|
||||
|
||||
🎬 ACTION
|
||||
rm /SWE-agent__test-repo/reproduce_error.py
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
Your command ran successfully and did not produce any output.
|
||||
🤠 INFO ========================= STEP 16 =========================
|
||||
🤖 DEBUG n_cache_control: 2
|
||||
🤖 INFO Response: ModelResponse(id='chatcmpl-4f8b36d7-e8ff-43a4-9c1e-2dbf224beeaa', created=1746538471, model='claude-3-7-sonnet-latest', object='chat.completion', system_fingerprint=None,
|
||||
choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content="Now let's submit again:", role='assistant', tool_calls=[ChatCompletionMessageToolCall(index=1,
|
||||
function=Function(arguments='{}', name='submit'), id='toolu_01DvZjwT6EgTcJ7sDDFi9Znz', type='function')], function_call=None))], usage=Usage(completion_tokens=42, prompt_tokens=5984, total_tokens=6026,
|
||||
completion_tokens_details=None, prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=5880, text_tokens=None, image_tokens=None), cache_creation_input_tokens=103,
|
||||
cache_read_input_tokens=5880))
|
||||
🤖 DEBUG input_tokens=3,472, output_tokens=6, instance_cost=0.09, cost=0.00
|
||||
🤖 DEBUG total_tokens_sent=29,801, total_tokens_received=722, total_cost=0.09, total_api_calls=16
|
||||
🤠 INFO 💭 THOUGHT
|
||||
Now let's submit again:
|
||||
|
||||
🎬 ACTION
|
||||
submit
|
||||
🧰 DEBUG Retrieved state from environment: {'working_dir': '/SWE-agent__test-repo'}
|
||||
🤠 INFO Found submission: diff --git a/src/testpkg/missing_colon.py b/src/testpkg/missing_colon.py
|
||||
index 20edef5..5857437 100755
|
||||
--- a/src/testpkg/missing_colon.py
|
||||
+++ b/src/testpkg/missing_colon.py
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
-def division(a: float, b: float) -> float
|
||||
+def division(a: float, b: float) -> float:
|
||||
return a/b
|
||||
|
||||
|
||||
diff --git a/tests/missing_colon.py b/tests/missing_colon.py
|
||||
index 20edef5..5857437 100755
|
||||
--- a/tests/missing_colon.py
|
||||
+++ b/tests/missing_colon.py
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
-def division(a: float, b: float) -> float
|
||||
+def division(a: float, b: float) -> float:
|
||||
return a/b
|
||||
|
||||
|
||||
|
||||
🤠 INFO 🤖 MODEL INPUT
|
||||
OBSERVATION:
|
||||
diff --git a/src/testpkg/missing_colon.py b/src/testpkg/missing_colon.py
|
||||
index 20edef5..5857437 100755
|
||||
--- a/src/testpkg/missing_colon.py
|
||||
+++ b/src/testpkg/missing_colon.py
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
-def division(a: float, b: float) -> float
|
||||
+def division(a: float, b: float) -> float:
|
||||
return a/b
|
||||
|
||||
|
||||
diff --git a/tests/missing_colon.py b/tests/missing_colon.py
|
||||
index 20edef5..5857437 100755
|
||||
--- a/tests/missing_colon.py
|
||||
+++ b/tests/missing_colon.py
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
-def division(a: float, b: float) -> float
|
||||
+def division(a: float, b: float) -> float:
|
||||
return a/b
|
||||
|
||||
|
||||
|
||||
🤠 INFO Trajectory saved to
|
||||
/Users/fuchur/Documents/24/git_sync/SWE-agent/trajectories/fuchur/anthropic_filemap__claude-3-7-sonnet-latest__t-0.00__p-1.00__c-2.00___SWE-agent__test-repo-i1/SWE-agent__test-repo-i1/SWE-agent__test-re
|
||||
po-i1.traj
|
||||
╭──────────────────────────── 🎉 Submission successful 🎉 ────────────────────────────╮
|
||||
│ SWE-agent has produced a patch that it believes will solve the issue you submitted! │
|
||||
│ Use the code snippet below to inspect or apply it! │
|
||||
╰─────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
# The patch has been saved to your local filesystem at:
|
||||
PATCH_FILE_PATH='/Users/fuchur/Documents/24/git_sync/SWE-agent/trajectories/fuchur/anthropic_filemap__claude-3-7-sonnet-latest__t-0.00__p-1.00__c-2.00___SWE-agent__test-repo-i1/SWE-agent__test-repo-i1/SWE-agent__
|
||||
st-repo-i1.patch'
|
||||
# Inspect it:
|
||||
cat "${PATCH_FILE_PATH}"
|
||||
# Apply it to a local repository:
|
||||
cd <your local repo root>
|
||||
git apply "${PATCH_FILE_PATH}"
|
||||
|
||||
🏃 INFO Done
|
||||
🪴 INFO Beginning environment shutdown...
|
||||
🦖 DEBUG Ensuring deployment is stopped because object is deleted
|
||||
@@ -0,0 +1,46 @@
|
||||
# User guides
|
||||
|
||||
This part of the documentation covers more details about configuring and developing SWE-agent.
|
||||
Just want to run it? See [getting started](../index.md) instead!
|
||||
|
||||
<div class="grid cards">
|
||||
<a href="../background/" class="nav-card-link">
|
||||
<div class="nav-card">
|
||||
<div class="nav-card-header">
|
||||
<span class="material-icons nav-card-icon">book</span>
|
||||
<span class="nav-card-title">Background & goals</span>
|
||||
</div>
|
||||
<p class="nav-card-description">Learn more about the project goals and academic research.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="../usage/cli/" class="nav-card-link">
|
||||
<div class="nav-card">
|
||||
<div class="nav-card-header">
|
||||
<span class="material-icons nav-card-icon">book</span>
|
||||
<span class="nav-card-title">Command line interface</span>
|
||||
</div>
|
||||
<p class="nav-card-description">Learn about all the different subcommands of sweagent.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="../config/config/" class="nav-card-link">
|
||||
<div class="nav-card">
|
||||
<div class="nav-card-header">
|
||||
<span class="material-icons nav-card-icon">settings</span>
|
||||
<span class="nav-card-title">Configuration</span>
|
||||
</div>
|
||||
<p class="nav-card-description">How to configure SWE-agent.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="multimodal/" class="nav-card-link">
|
||||
<div class="nav-card">
|
||||
<div class="nav-card-header">
|
||||
<span class="material-icons nav-card-icon">image</span>
|
||||
<span class="nav-card-title">Multimodal Support</span>
|
||||
</div>
|
||||
<p class="nav-card-description">Use SWE-agent with vision-capable AI models for image processing.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,74 @@
|
||||
# Inspecting trajectories
|
||||
|
||||
!!! abstract "Inspecting trajectories"
|
||||
* Trajectories are the main output of SWE-agent. They are the best way to understand what SWE-agent does, especially when running on many problem instances.
|
||||
* We provide two tools for visualizing the [`.traj` files](trajectories.md) from the `trajectories` folder more easily.
|
||||
* Use `swe-agent inspect` (or `sweagent i`) to open the command line inspector.
|
||||
* Use `swe-agent inspector` (or `sweagent I`) to open the web inspector.
|
||||
* Please complete the [hello world](hello_world.md) tutorial before proceeding.
|
||||
|
||||
You should see a folder called `trajectories` in your working directory. Let's go to one of the *experiment directories*:
|
||||
|
||||
```bash
|
||||
cd trajectories/$USER/<some directory> # (1)!
|
||||
```
|
||||
|
||||
1. Don't have a folder here? Make sure to run SWE-agent at least once.
|
||||
|
||||
## Command line inspector
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/808a1a9c-69c2-47c2-bd65-b50a16a03711">
|
||||
|
||||
Run the inspector in the directory containing your `.traj` files:
|
||||
|
||||
```bash
|
||||
sweagent inspect
|
||||
# or
|
||||
sweagent i
|
||||
```
|
||||
|
||||
You will be put into a pager that lets you navigate between trajectories.
|
||||
Here's how to navigate (this is similar to vim keybindings):
|
||||
|
||||
* Use `q` to quit
|
||||
* Switching between trajectories:
|
||||
* `H` and `L` go to the previous/next trajectory
|
||||
* `t` brings up a list of all trajectories. Use type-ahead search to find a specific trajectory (once your search string results in a single match, the trajectory will be opened). Press `<TAB>` to cycle through the list of matches.
|
||||
* Use `h` and `l` to navigate between the steps in the trajectory
|
||||
* Use `j` and `k` to scroll down/up
|
||||
* By default we only show reduced information. You can press `v` to toggle the view.
|
||||
* Press `o` to open the logs
|
||||
* Sometimes you see that you can press `e` to open a file in your `$EDITOR`. For this to work, the `EDITOR` environment variable must be set (e.g., to `nano` or `vim`).
|
||||
|
||||
## Web-based inspector
|
||||
|
||||
|
||||
Run the inspector in this directory (this is where your `*.traj` files are):
|
||||
|
||||
```bash
|
||||
sweagent inspector
|
||||
# or
|
||||
sweagent I
|
||||
```
|
||||
The inspector will then be launched in the browser:
|
||||
|
||||
{: style="width: 49%;"}
|
||||
{: style="width: 49%;"}
|
||||
|
||||
**Additional flags**
|
||||
|
||||
- `--directory`: Directory of trajectories to inspect (Defaults to current directory)
|
||||
- `--port`: Port to host web app (Defaults to `8000`).
|
||||
|
||||
## Benchmark results
|
||||
|
||||
If you are running SWE-agent on a benchmark (see [batch mode](batch_mode.md)), you will see evaluation results as ✅ or ❌.
|
||||
Otherwise, you will see ❓.
|
||||
|
||||
!!! tip
|
||||
* If you do not see evaluation results, make sure that the SWE-bench output
|
||||
is called `results.json` and is in the same directory as the trajectories.
|
||||
* To see gold patches, point `--data_path` to the SWE-bench dataset.
|
||||
|
||||
|
||||
{% include-markdown "../_footer.md" %}
|
||||
@@ -0,0 +1,28 @@
|
||||
Given an unsorted integer array nums.
|
||||
Return the smallest positive integer that is not present in nums.
|
||||
|
||||
You must implement an algorithm that runs in O(n) time and uses O(1) auxiliary space.
|
||||
|
||||
## Example 1:
|
||||
|
||||
> Input: nums = [1,2,0]
|
||||
> Output: 3
|
||||
> Explanation: The numbers in the range [1,2] are all in the array.
|
||||
|
||||
## Example 2:
|
||||
|
||||
> Input: nums = [3,4,-1,1]
|
||||
> Output: 2
|
||||
> Explanation: 1 is in the array but 2 is missing.
|
||||
|
||||
## Example 3:
|
||||
|
||||
> Input: nums = [7,8,9,11,12]
|
||||
> Output: 1
|
||||
> Explanation: The smallest positive integer 1 is missing.
|
||||
|
||||
## Constraints:
|
||||
|
||||
1 <= nums.length <= 105
|
||||
-231 <= nums[i] <= 231 - 1
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Memory Sentinel Script
|
||||
|
||||
This script monitors the system's RAM usage and kills the process with the highest
|
||||
memory consumption if available RAM drops below 5GB.
|
||||
|
||||
Usage:
|
||||
python memory_sentinel.py
|
||||
|
||||
The script runs continuously, checking memory usage every second.
|
||||
|
||||
Script was generated by Claude 3.7 with the following prompt:
|
||||
|
||||
I'm working on a server and I have one script that sometimes consumes so much memory that the entire server becomes unresponsive. This is a hue problem because then I cannot log in to it anymore.
|
||||
|
||||
Could you write a sentinel script in python that does the following:
|
||||
|
||||
Check the total available RAM of the system (disregarding swap)
|
||||
Check the currently used RAM of the system
|
||||
If we have more than 5G left, do nothing
|
||||
Else, find the process with the highest RAM consumption and kill it. Note: Use the SIGKILL command
|
||||
Check every second
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
# Set up logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", filename="memory_sentinel.log", filemode="a"
|
||||
)
|
||||
|
||||
# Memory threshold in GB
|
||||
MEMORY_THRESHOLD_GB = 5
|
||||
# Convert to bytes for comparison
|
||||
MEMORY_THRESHOLD_BYTES = MEMORY_THRESHOLD_GB * 1024 * 1024 * 1024
|
||||
|
||||
|
||||
def get_available_ram():
|
||||
"""Get the available RAM in bytes, excluding swap."""
|
||||
return psutil.virtual_memory().available
|
||||
|
||||
|
||||
def get_total_ram():
|
||||
"""Get the total RAM in bytes, excluding swap."""
|
||||
return psutil.virtual_memory().total
|
||||
|
||||
|
||||
def get_used_ram():
|
||||
"""Get the used RAM in bytes."""
|
||||
return psutil.virtual_memory().used
|
||||
|
||||
|
||||
def get_process_with_highest_memory():
|
||||
"""Find the process with the highest memory consumption."""
|
||||
processes = []
|
||||
for proc in psutil.process_iter(["pid", "name", "memory_info"]):
|
||||
try:
|
||||
processes.append((proc.info["pid"], proc.info["name"], proc.info["memory_info"].rss))
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
||||
pass
|
||||
|
||||
# Sort by memory usage (descending)
|
||||
processes.sort(key=lambda x: x[2], reverse=True)
|
||||
|
||||
if processes:
|
||||
return processes[0]
|
||||
return None
|
||||
|
||||
|
||||
def kill_process(pid):
|
||||
"""Kill a process using SIGKILL."""
|
||||
try:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
return True
|
||||
except OSError as e:
|
||||
logging.error(f"Failed to kill process {pid}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def format_bytes(bytes_value):
|
||||
"""Format bytes to a human-readable string."""
|
||||
for unit in ["B", "KB", "MB", "GB", "TB"]:
|
||||
if bytes_value < 1024.0:
|
||||
return f"{bytes_value:.2f} {unit}"
|
||||
bytes_value /= 1024.0
|
||||
return f"{bytes_value:.2f} PB"
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function that runs the memory monitoring loop."""
|
||||
logging.info("Memory Sentinel started")
|
||||
logging.info(f"Memory threshold set to {MEMORY_THRESHOLD_GB}GB")
|
||||
|
||||
try:
|
||||
while True:
|
||||
available_ram = get_available_ram()
|
||||
total_ram = get_total_ram()
|
||||
used_ram = get_used_ram()
|
||||
|
||||
logging.debug(
|
||||
f"Total RAM: {format_bytes(total_ram)}, "
|
||||
+ f"Used RAM: {format_bytes(used_ram)}, "
|
||||
+ f"Available RAM: {format_bytes(available_ram)}"
|
||||
)
|
||||
|
||||
if available_ram < MEMORY_THRESHOLD_BYTES:
|
||||
logging.warning(
|
||||
f"Available RAM ({format_bytes(available_ram)}) " + f"below threshold of {MEMORY_THRESHOLD_GB}GB"
|
||||
)
|
||||
|
||||
process = get_process_with_highest_memory()
|
||||
if process:
|
||||
pid, name, memory = process
|
||||
logging.warning(f"Killing process {pid} ({name}) " + f"using {format_bytes(memory)}")
|
||||
|
||||
if kill_process(pid):
|
||||
logging.info(f"Successfully killed process {pid} ({name})")
|
||||
else:
|
||||
logging.error(f"Failed to kill process {pid} ({name})")
|
||||
else:
|
||||
logging.warning("No process found to kill")
|
||||
|
||||
# Sleep for 1 second
|
||||
time.sleep(1)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Memory Sentinel stopped by user")
|
||||
except Exception as e:
|
||||
logging.error(f"Unexpected error: {e}")
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,157 @@
|
||||
# Multimodal Support
|
||||
|
||||
SWE-agent supports multimodal AI models that can process both text and images. This enables the agent to work with visual context from GitHub issues, such as screenshots, diagrams, and UI mockups.
|
||||
|
||||
## Overview
|
||||
|
||||
The multimodal implementation automatically:
|
||||
|
||||
- **Detects multimodal instances** from SWE-bench Multimodal datasets
|
||||
- **Downloads images** from GitHub issue URLs
|
||||
- **Converts to base64 markdown** format for AI model consumption
|
||||
- **Handles errors gracefully** with fallback to text-only processing
|
||||
|
||||
## Supported Image Categories
|
||||
|
||||
Currently, SWE-agent processes images from the `problem_statement` category, which includes:
|
||||
|
||||
- Screenshots showing bugs or issues
|
||||
- UI mockups and design specifications
|
||||
- Diagrams explaining the problem
|
||||
- Error screenshots and visual evidence
|
||||
|
||||
!!! note "Design Choice"
|
||||
Only `problem_statement` images are processed to provide essential visual context for understanding the task, while preserving agent autonomy in determining solution approaches. Images from `patch` and `test_patch` categories may contain solution hints and are not processed.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Basic Multimodal Setup
|
||||
|
||||
Use the pre-configured multimodal setup:
|
||||
|
||||
```bash
|
||||
sweagent run-batch \
|
||||
--config config/default_mm_with_images.yaml \
|
||||
--instances.type swe_bench \
|
||||
--instances.subset multimodal \
|
||||
--instances.split dev
|
||||
```
|
||||
|
||||
### Disabling Image Processing
|
||||
|
||||
You can disable image processing globally:
|
||||
|
||||
```yaml
|
||||
# config/your_config.yaml
|
||||
agent:
|
||||
templates:
|
||||
disable_image_processing: true
|
||||
```
|
||||
|
||||
Or for specific instances:
|
||||
|
||||
```python
|
||||
from sweagent.agent.problem_statement import SWEBenchMultimodalProblemStatement
|
||||
|
||||
problem_statement = SWEBenchMultimodalProblemStatement(
|
||||
text="Fix the rendering issue",
|
||||
issue_images=["https://example.com/screenshot.png"],
|
||||
disable_image_processing=True # Skip image processing
|
||||
)
|
||||
```
|
||||
|
||||
## Supported Models
|
||||
|
||||
Multimodal support works with any vision-capable models, including:
|
||||
|
||||
- **Claude Sonnet 4**
|
||||
- **o3** and **o4-mini**
|
||||
- **Gemini 2.5** models
|
||||
|
||||
Example model configuration:
|
||||
|
||||
```yaml
|
||||
# model_configs/claude-sonnet-4-20250514_mm.yaml
|
||||
model:
|
||||
name: claude-sonnet-4-20250514
|
||||
# Vision capabilities automatically detected
|
||||
```
|
||||
|
||||
## Image Processing Details
|
||||
|
||||
### Supported Formats
|
||||
- PNG, JPEG, WebP images
|
||||
- Maximum size: 10MB per image
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
### Automatic Detection
|
||||
|
||||
When loading SWE-bench instances, multimodal support is automatic:
|
||||
|
||||
```json
|
||||
{
|
||||
"instance_id": "example__repo-123",
|
||||
"problem_statement": "Fix the chart rendering bug...",
|
||||
"image_assets": {
|
||||
"problem_statement": ["http://example.com/chart.png"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Direct Usage
|
||||
|
||||
```python
|
||||
from sweagent.agent.problem_statement import SWEBenchMultimodalProblemStatement
|
||||
|
||||
problem_statement = SWEBenchMultimodalProblemStatement(
|
||||
text="Fix the rendering issue shown in the screenshots",
|
||||
issue_images=[
|
||||
"https://example.com/before.png",
|
||||
"https://example.com/after.png"
|
||||
]
|
||||
)
|
||||
|
||||
# This downloads images and converts them to base64 markdown
|
||||
processed_text = problem_statement.get_problem_statement()
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
In order to enable multimodal processing, you need to update the following configuration options:
|
||||
|
||||
### History Processing
|
||||
|
||||
Enable image parsing in your configuration:
|
||||
|
||||
```yaml
|
||||
agent:
|
||||
history_processors:
|
||||
- type: image_parsing # Parse base64 encoded images in observations
|
||||
```
|
||||
|
||||
### Tool Bundles
|
||||
|
||||
Include image and browser tools for visual tasks:
|
||||
|
||||
```yaml
|
||||
agent:
|
||||
tools:
|
||||
bundles:
|
||||
- path: tools/image_tools # includes open_image tool to let models open image files
|
||||
- path: tools/web_browser # includes 17 browser automation tools (click_mouse, open_site, etc.)
|
||||
```
|
||||
|
||||
The `web_browser` bundle provides tools for:
|
||||
- Opening websites (`open_site`)
|
||||
- Taking screenshots (`screenshot_site`)
|
||||
- Interacting with web pages (`click_mouse`, `type_text`, `scroll_on_page`)
|
||||
- Executing JavaScript (`execute_script_on_page`)
|
||||
- And more - see the [configuration guide](../config/config.md#web-browser-tools) for the full list
|
||||
|
||||
### Templates Configuration
|
||||
|
||||
We've enabled multimodal processing when `--instances.type=swe-bench --instances.subset=multimodal` are set.
|
||||
|
||||
To disable this behavior, you must set `--agent.templates.disable_image_processing=true`.
|
||||
@@ -0,0 +1,103 @@
|
||||
# Output files
|
||||
|
||||
The [`trajectories/`](https://github.com/SWE-agent/SWE-agent/tree/main/trajectories) folder is the default location that experiment results (for example invocations of [`sweagent run`](cl_tutorial.md)) will be written to.
|
||||
|
||||
## Trajectories
|
||||
|
||||
The main output file is `<instance_id>.traj`, which is a `.json` formatted file containing the (thought, action, observation) turns generated by SWE-agent towards solving `<instance_id>`.
|
||||
|
||||
Under the `trajectory` key, you can see information for every step of the agent. It looks something like this:
|
||||
|
||||
```json
|
||||
{
|
||||
# This is the output of the LM
|
||||
"response": "We are indeed seeing the same output as the issue. The issue suggests that we should look at line 1474 of the `fields.py`...",
|
||||
# We then parse it into thoughts and actions
|
||||
"thought": "We are indeed seeing the same output as the issue. The issue suggests that we should look at line 1474 of the `fields.py`..."
|
||||
"action": "ls -F\n",
|
||||
# And execute the action, resulting in the output
|
||||
"observation": "AUTHORS.rst\nCHANGELOG.rst\nCODE_OF_CONDUCT.md...",
|
||||
# In addition, after the action was executed, state can be extracted from the environment
|
||||
"state": "{\"open_file\": \"/marshmallow-code__marshmallow/reproduce.py\", \"working_dir\": \"/marshmallow-code__marshmallow\"}\n",
|
||||
# For debugging, we also keep all messages that were shown to the LM
|
||||
"query": [{"role": "system", "content": "You are a helpful assistant ..."}, ...]
|
||||
},
|
||||
```
|
||||
|
||||
!!! warning "Query and message field"
|
||||
Prior to SWE-agent 1.1.0, we had a `message` field which corresponded (approximately) to the input
|
||||
for the LM for the _next_ step. This was replaced with `query`, which shows the exact input
|
||||
at the current step.
|
||||
|
||||
Here's a full example:
|
||||
|
||||
<details>
|
||||
<summary>Example trajectory</summary>
|
||||
|
||||
Note: This trajectory is from SWE-agent v0.7.0. It might look different in newer versions.
|
||||
|
||||
```json
|
||||
--8<-- "trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default__t-0.20__p-0.95__c-2.00__install-1___install_from_source/marshmallow-code__marshmallow-1867.traj"
|
||||
```
|
||||
</details>
|
||||
|
||||
!!! tip "Viewing trajectories"
|
||||
We provide a [trajectory viewer](inspector.md) for an easy viewing of trajectories.
|
||||
If you want to view the json, we recommend [jsoneditoronline](https://jsoneditoronline.org/),
|
||||
because of the way it handles long lines.
|
||||
|
||||
Trajectories can also be turned into custom demonstrations for SWE-agent ([more information](../config/demonstrations.md)).
|
||||
|
||||
## Other output files
|
||||
|
||||
Together with the trajectory, SWE-agent will also generate the following files per instance:
|
||||
|
||||
* `config.yaml`: A yaml file containing the configuration used for the experiment. You can directly repeat the run of this
|
||||
exact instance by running `sweagent run --config config.yaml`.
|
||||
* `*.log`: Log files at different levels
|
||||
|
||||
At a high level, the experiments folder is organized in the following manner:
|
||||
|
||||
```
|
||||
trajectories:
|
||||
user 1:
|
||||
experiment 1:
|
||||
run_batch.config.yaml
|
||||
preds.json
|
||||
run_batch.debug.log
|
||||
run_batch.info.log
|
||||
run_batch.warning.log
|
||||
run_batch_exit_statuses.yaml
|
||||
instance_1:
|
||||
instance_1.traj
|
||||
instance_1.config.yaml
|
||||
instance_1.debug.log
|
||||
instance_1.info.log
|
||||
instance_1.warning.log
|
||||
instance 2:
|
||||
...
|
||||
experiment 2:
|
||||
...
|
||||
user 2:
|
||||
...
|
||||
```
|
||||
|
||||
Where every experiment follows the pattern `trajectories/<user name>/<experiment name>`. The `<user name>` is automatically inferred from your system, and the `experiment name` is inferred from the model names and other settings to the run command.
|
||||
|
||||
|
||||
Here are a few more files that are generated with `sweagent run-batch`:
|
||||
|
||||
* `run_batch.config.yaml`: A yaml file containing the configuration used for the experiment. You can directly repeat the run of this
|
||||
exact experiment by running `sweagent run-batch --config run_batch.config.yaml`.
|
||||
* `preds.json`: All predictions (i.e., patches produced by the agent) from all instances of the experiment.
|
||||
If this file goes out of date, you can regenerate it by running `sweagent merge-preds`.
|
||||
* `run_batch.*.log`: Log files at different levels.
|
||||
* `run_batch_exit_statuses.yaml`: A yaml file containing the exit statuses of all instances in the experiment (for this run of `sweagent run-batch`).
|
||||
|
||||
|
||||
!!! tip
|
||||
* Evaluation is not completed by `sweagent run-batch`, it is a separate step (see [batch mode](batch_mode.md))
|
||||
* `preds.json` can be referenced directly into SWE-bench to run evaluation
|
||||
* Trajectories can be turned into custom demonstrations for SWE-agent ([more information](../config/demonstrations.md)).
|
||||
|
||||
{% include-markdown "../_footer.md" %}
|
||||
@@ -0,0 +1,40 @@
|
||||
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Validation error │
|
||||
│ │
|
||||
│ The following errors are raised by Pydantic, trying to instantiate the configuration based on │
|
||||
│ the merged configuration dictionary (see above). │
|
||||
│ │
|
||||
│ Every new indented block corresponds to a different error from Pydantic. │
|
||||
│ The first line of each block is the attribute that failed validation, the following lines are the error messages. │
|
||||
│ │
|
||||
│ If you see many lines of errors, there are probably different ways to instantiate the same object (a union type). │
|
||||
│ For example, there are different deployments with different options each. Pydantic is then trying │
|
||||
│ one after the other and reporting the failures for each of them. │
|
||||
│ │
|
||||
│ 8 validation errors for RunSingleConfig │
|
||||
│ agent.model │
|
||||
│ Field required }, input_type=dict] │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/missing │
|
||||
│ problem_statement.TextProblemStatement.text │
|
||||
│ Field required │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/missing │
|
||||
│ problem_statement.TextProblemStatement.path │
|
||||
│ Extra inputs are not permitted │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden │
|
||||
│ problem_statement.TextProblemStatement.github_url │
|
||||
│ Extra inputs are not permitted │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden │
|
||||
│ problem_statement.GithubIssue.path │
|
||||
│ Extra inputs are not permitted │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden │
|
||||
│ problem_statement.EmptyProblemStatement.path │
|
||||
│ Extra inputs are not permitted │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden │
|
||||
│ problem_statement.EmptyProblemStatement.github_url │
|
||||
│ Extra inputs are not permitted │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden │
|
||||
│ problem_statement.FileProblemStatement.github_url │
|
||||
│ Extra inputs are not permitted │
|
||||
│ For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden │
|
||||
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# What's next?
|
||||
|
||||
Congratulations, this is currently the last tutorial!
|
||||
|
||||
Here are some ideas for what to check out next: There are two more sections on this website:
|
||||
|
||||
* [User guides](index.md): This covers selected topics in more detail, for example
|
||||
* What are all the different [subcommands](cli.md) of `sweagent`?
|
||||
* How to [configure swe-agent](../config/index.md)?
|
||||
* What's the main [architecture](../background/architecture.md) of SWE-agent?
|
||||
* [API reference](../reference/index.md) for complete lists of all configuration options.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user