## File: README.md

# The minimal AI software engineering agent

📣 [mini-swe-agent now powers Ramp SWE-Bench](https://labs.ramp.com/swebench)
📣 [mini-swe-agent beats Claude Code and Codex on DeepSWE](https://deepswe.datacurve.ai/blog#evaluation-harness)
📣 [Run mini-swe-agent on our new & extremely challenging benchmark, ProgramBench](https://mini-swe-agent.com/latest/usage/programbench/)
📣 [New tutorial on building minimal AI agents](https://minimal-agent.com/)

[](https://mini-swe-agent.com/latest/)
[](https://join.slack.com/t/swe-bench/shared_invite/zt-36pj9bu5s-o3_yXPZbaH2wVnxnss1EkQ)
[](https://pypi.org/project/mini-swe-agent/)

> [!WARNING]
> This is **mini-swe-agent v2**. Read the [migration guide](https://mini-swe-agent.com/latest/advanced/v2_migration/). For the previous version, check out the [v1 branch](https://github.com/SWE-agent/mini-swe-agent/tree/v1).

In 2024, we built [SWE-bench](https://github.com/swe-bench/SWE-bench) & [SWE-agent](https://github.com/swe-agent/swe-agent) and helped kickstart the coding agent revolution.

We now ask: **What if our agent was 100x simpler, and still worked nearly as well?**

`mini` is

- **Widely adopted**: Used by Meta, NVIDIA, Essential AI, IBM, Nebius, Anyscale, Princeton University, Stanford University, and many more.
- **Minimal**: Just some 100 lines of python for the [agent class](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/agents/default.py) (and a bit more for the [environment](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/environments/local.py),
[model](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/models/litellm_model.py), and [run script](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/hello_world.py)) — no fancy dependencies!
- **Performant:** Scores >74% on the [SWE-bench verified benchmark](https://www.swebench.com/); starts much faster than Claude Code
- **Deployable:** Supports **local environments**, **docker/podman**, **singularity/apptainer**, **bublewrap**, **contree**, and more
- **Compatible:** Supports all models via **litellm**, **openrouter**, **portkey**, and more. Support for `/completion` and `/response` endpoints, interleaved thinking etc.
- Built by the Princeton & Stanford team behind [SWE-bench](https://swebench.com), [SWE-agent](https://swe-agent.com), and more
- **Tested:** [](https://codecov.io/gh/SWE-agent/mini-swe-agent)



More motivation (for research)

[SWE-agent](https://swe-agent.com/latest/) jump-started the development of AI agents in 2024. Back then, we placed a lot of emphasis on tools and special interfaces for the agent.
However, one year later, as LMs have become more capable, a lot of this is not needed at all to build a useful agent!
In fact, the `mini` agent

- **Does not have any tools other than bash** — it doesn't even need to use the tool-calling interface of the LMs.
  This means that you can run it with literally any model. When running in sandboxed environments you also don't need to take care
  of installing a single package — all it needs is bash.
- **Has a completely linear history** — every step of the agent just appends to the messages and that's it.
  So there's no difference between the trajectory and the messages that you pass on to the LM.
  Great for debugging & fine-tuning.
- **Executes actions with `subprocess.run`** — every action is completely independent (as opposed to keeping a stateful shell session running).
  This makes it trivial to execute the actions in sandboxes (literally just switch out `subprocess.run` with `docker exec`) and to
  scale up effortlessly. Seriously, this is [a big deal](https://mini-swe-agent.com/latest/faq/#why-no-shell-session), trust me.

This makes it perfect as a baseline system and for a system that puts the language model (rather than
the agent scaffold) in the middle of our attention.
You can see the result on the [SWE-bench (bash only)](https://www.swebench.com/) leaderboard, that evaluates the performance of different LMs with `mini`.




More motivation (as a tool)

Some agents are overfitted research artifacts. Others are UI-heavy frontend monsters.

The `mini` agent wants to be a hackable tool, not a black box.

- **Simple** enough to understand at a glance
- **Convenient** enough to use in daily workflows
- **Flexible** to extend

Unlike other agents (including our own [swe-agent](https://swe-agent.com/latest/)), it is radically simpler, because it:

- **Does not have any tools other than bash** — it doesn't even need to use the tool-calling interface of the LMs.
  Instead of implementing custom tools for every specific thing the agent might want to do, the focus is fully on the LM utilizing the shell to its full potential.
  Want it to do something specific like opening a PR?
  Just tell the LM to figure it out rather than spending time to implement it in the agent.
- **Executes actions with `subprocess.run`** — every action is completely independent (as opposed to keeping a stateful shell session running).
  This is [a big deal](https://mini-swe-agent.com/latest/faq/#why-no-shell-session) for the stability of the agent, trust me.
- **Has a completely linear history** — every step of the agent just appends to the messages that are passed to the LM in the next step and that's it.
  This is great for debugging and understanding what the LM is prompted with.




Should I use SWE-agent or mini-SWE-agent?

You should consider `mini-swe-agent` your default choice.
In particular, you should use `mini-swe-agent` if

- You want a quick command line tool that works locally
- You want an agent with a very simple control flow
- You want even faster, simpler & more stable sandboxing & benchmark evaluations
- You are doing FT or RL and don't want to overfit to a specific agent scaffold

You should use `swe-agent` if

- You want to experiment with different sets of tools, each with their own interface
- You want to experiment with different history processors

What you get with both

- Excellent performance on SWE-Bench
- A trajectory browser





| [**CLI**](https://mini-swe-agent.com/latest/usage/mini/) (`mini`) | [**Batch inference**](https://mini-swe-agent.com/latest/usage/swebench/) |
| --- | --- |
|  |  |
| [**Trajectory browser**](https://mini-swe-agent.com/latest/usage/inspector/) | [**Python bindings**](https://mini-swe-agent.com/latest/advanced/cookbook/) |
|  | ```python
agent = DefaultAgent(
    LitellmModel(model_name=...),
    LocalEnvironment(),
)
agent.run("Write a sudoku game")
``` |



## Let's get started!

**Option 1:** If you just want to try out the CLI (package installed in anonymous virtual environment)

```bash
pip install uv && uvx mini-swe-agent
# or
pip install pipx && pipx ensurepath && pipx run mini-swe-agent
```

**Option 2:** Install CLI & python bindings in current environment

```bash
pip install mini-swe-agent
mini  # run the CLI
```

**Option 3:** Install from source (developer setup)

```bash
git clone https://github.com/SWE-agent/mini-swe-agent.git
cd mini-swe-agent && pip install -e .
mini  # run the CLI
```

Read more in our [documentation](https://mini-swe-agent.com/latest/):

* [Quick start guide](https://mini-swe-agent.com/latest/quickstart/)
* [Using the `mini` CLI](https://mini-swe-agent.com/latest/usage/mini/)
* [Global configuration](https://mini-swe-agent.com/latest/advanced/global_configuration/)
* [Yaml configuration files](https://mini-swe-agent.com/latest/advanced/yaml_configuration/)
* [Power up with the cookbook](https://mini-swe-agent.com/latest/advanced/cookbook/)
* [FAQ](https://mini-swe-agent.com/latest/faq/)
* [Contribute!](https://mini-swe-agent.com/latest/contributing/)

## Attribution

If you found this work helpful, please consider citing the [SWE-agent paper](https://arxiv.org/abs/2405.15793) in your work:

```bibtex
@inproceedings{yang2024sweagent,
  title={{SWE}-agent: Agent-Computer Interfaces Enable Automated Software Engineering},
  author={John Yang and Carlos E Jimenez and Alexander Wettig and Kilian Lieret and Shunyu Yao and Karthik R Narasimhan and Ofir Press},
  booktitle={The Thirty-eighth Annual Conference on Neural Information Processing Systems},
  year={2024},
  url={https://arxiv.org/abs/2405.15793}
}
```

Our other projects:

---

## File: docs/advanced/control_flow.md

# Agent control flow

!!! note "Understanding AI agent basics"

    We also recently created a long tutorial on understanding the basics of building an AI agent: [View it here](https://minimal-agent.com).

!!! abstract "Understanding the default agent"

    * This guide shows the control flow of the default agent.
    * After this, you're ready to [remix & extend mini](cookbook.md)

The following diagram shows the control flow of the mini agent:

```mermaid
flowchart TD
    subgraph run["**`Agent.run(task)`**"]
        direction TB
        A["**`Initialize messages`**"] --> B
        B["**`Agent.step`**"] --> C{"**`Exception?`**"}
        C -->|Yes| D["**`Agent.add_messages`**(also re-raises exceptions that don't inherit from InterruptAgentFlow)"]
        C -->|No| E{"**`messages[-1].role == exit?`**"}
        D --> E
        E -->|No| B
        E -->|Yes| F["**`Return result`**"]
    end

    subgraph step["**`Agent.step()`**Single iteration"]
        direction TB
        S1["**`Agent.query`**"] --> S2["**`Agent.execute_actions`**"]
    end

    subgraph query["**`Agent.query()`**Also checks for cost limits"]
        direction TB
        Q3["**`Model.query`**"] --> Q4["**`Agent.add_messages`**"]
    end

    subgraph execute_actions["**`Agent.execute_actions(message)`**"]
        direction TB
        E2["**`Environment.execute`**Also raises the Submitted exception if we're done"] --> E3["**`Model.format_observation_messages`**"]
        E3 --> E4["**`Agent.add_messages`**"]
    end

    B -.-> step
    S1 -.-> query
    S2 -.-> execute_actions
```

And here is the code that implements it:

??? note "Default agent class"

    - [Read on GitHub](https://github.com/swe-agent/mini-swe-agent/blob/main/src/minisweagent/agents/default.py)
    - [API reference](../reference/agents/default.md)

    ```python
    --8<-- "src/minisweagent/agents/default.py"
    ```

Essentially, `DefaultAgent.run` calls `DefaultAgent.step` in a loop until the agent has finished its task.

The `step` method is the core of the agent:

```python
def step(self) -> list[dict]:
    return self.execute_actions(self.query())
```

It does the following:

1. Queries the model for a response based on the current messages (`DefaultAgent.query`, calling `Model.query`)
2. Executes all actions in the response (`DefaultAgent.execute_actions`, calling `Environment.execute` for each action)
3. Formats the observation messages via `Model.format_observation_messages`
4. Adds the observations to the messages

Here's `query`:

```python
def query(self) -> dict:
    # ... limit checks ...
    message = self.model.query(self.messages)
    self.add_messages(message)
    return message
```

And `execute_actions`:

```python
def execute_actions(self, message: dict) -> list[dict]:
    outputs = [self.env.execute(action) for action in message.get...
    return self.add_messages(*self.model.format_observation_messages(...))
```

The interesting bit is how we handle error conditions and the finish condition:
This uses exceptions that inherit from `InterruptAgentFlow`. All these exceptions carry messages that get added to the trajectory.

- `Submitted` is raised when the agent has finished its task. For example, the environment checks if the command output starts with a magic string:

    ```python
    # In Environment.execute
    def _check_finished(self, output: dict):
        lines = output.get("output", "").lstrip().splitlines(keepends=True)
        if lines and lines[0].strip() == "COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT":
            raise Submitted({"role": "exit", "content": ..., "extra": {...}})
    ```

- `LimitsExceeded` is raised when we hit a cost or step limit
- `FormatError` is raised when the output from the LM is not in the expected format
- `TimeoutError` is raised when the action took too long to execute
- `UserInterruption` is raised when the user interrupts the agent

The `DefaultAgent.run` method catches these exceptions and handles them by adding the corresponding messages to the messages list. The loop continues until a message with `role="exit"` is added.

```python
while True:
    try:
        self.step()
    except InterruptAgentFlow as e:
        self.add_messages(*e.messages)
    if self.messages[-1].get("role") == "exit":
        break
```

Using exceptions for the control flow is a lot easier than passing around flags and states, especially when extending or subclassing the agent.

{% include-markdown "_footer.md" %}

---

## File: docs/advanced/cookbook.md

# Cookbook

!!! abstract "Remixing & extending mini"

    * This guide shows how to mix the different components of the `mini` agent to create your own custom version.
    * You might want to first take a look at the [control flow of the default agent](control_flow.md) first


!!! note "Development setup"

    Make sure to follow the dev setup instructions in [quickstart.md](../quickstart.md).

We provide several different entry points to the agent,
for example [hello world](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/hello_world.py),
or the [default when calling `mini`](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/mini.py).

Want to cook up your custom version and the config is not enough?
Just follow the recipe below:

1. What's the control flow you need? Pick an [agent class](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/agents) (e.g., [simplest example](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/agents/default.py), [with human in the loop](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/agents/interactive.py))
2. How should actions be executed? Pick an [environment class](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/environments) (e.g., [local](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/environments/local.py), or [docker](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/environments/docker.py))
3. How is the LM queried? Pick a [model class](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/models) (e.g., [litellm](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/models/litellm_model.py))
4. How to invoke the agent? Bind them all together in a [run script](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run), possibly reading from a [config](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/config) (e.g., [hello world](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/hello_world.py), or [`mini` entry point](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/mini.py))

We aim to keep all of these components very simple, but offer lots of choice between them -- enough to cover a broad range of
things that you might want to do.

You can override the default entry point by setting the `MSWEA_DEFAULT_RUN` environment variable to the import path of your run script.

## Hello world

See [Python bindings](../usage/python_bindings.md) for the most basic example.

## Mix & match

### Models

=== "Hello world (use automatic model selection)"

    ```python
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.models import get_model
    from minisweagent.environments.local import LocalEnvironment

    model_name = "anthropic/claude-sonnet-4-5-20250929"

    agent = DefaultAgent(
        get_model(input_model_name=model_name),
        LocalEnvironment(),
    )
    agent.run(task)
    ```

=== "Hello world (Litellm)"

    ```python
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.models.litellm_model import LitellmModel
    from minisweagent.environments.local import LocalEnvironment

    model_name = "gpt-4o"

    agent = DefaultAgent(
        LitellmModel(model_name=model_name),
        LocalEnvironment(),
    )
    agent.run(task)
    ```

### Environments

=== "Hello world with local execution"

    ```python
    from minisweagent.environments.local import LocalEnvironment

    agent = DefaultAgent(
        LitellmModel(model_name=model_name),
        LocalEnvironment(),
    )
    ```

=== "Hello world with docker execution"

    ```python
    from minisweagent.environments.docker import DockerEnvironment

    agent = DefaultAgent(
        LitellmModel(model_name=model_name),
        DockerEnvironment(),
    )
    ```

### Agents

=== "Default agent"

    ```python
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.models import get_model
    from minisweagent.environments.local import LocalEnvironment

    agent = DefaultAgent(
        get_model(input_model_name=model_name),
        LocalEnvironment(),
    )
    ```

=== "Human in the loop"

    ```python
    from minisweagent.agents.interactive import InteractiveAgent
    from minisweagent.models import get_model
    from minisweagent.environments.local import LocalEnvironment

    agent = InteractiveAgent(
        get_model(input_model_name=model_name),
        LocalEnvironment(),
    )
    ```

## Advanced

### Customizing execution

An agent that uses python function for some actions:


=== "Subclassing the agent"

    ```python
    from minisweagent.agents.default import DefaultAgent
    import shlex

    def python_function(*args) -> dict:
        ...
        return {"output": "..."}

    class AgentWithPythonFunctions(DefaultAgent):
        def execute_actions(self, message: dict) -> list[dict]:
            for action in message.get("extra", {}).get("actions", []):
                command = action.get("command", "")
                if command.startswith("python_function"):
                    args = shlex.split(command.removeprefix("python_function").strip())
                    return self.add_messages(self.model.format_observation_messages(
                        message, [python_function(*args)], self.get_template_vars()
                    ))
            # everything else works as usual
            return super().execute_actions(message)
    ```


=== "Subclassing the environment"

    ```python
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.environments.local import LocalEnvironment
    import shlex

    def python_function(*args) -> dict:
        ...
        return {"output": "..."}

    class EnvironmentWithPythonFunctions(LocalEnvironment):
        def execute(self, action: dict, cwd: str = "") -> dict:
            command = action.get("command", "")
            if command.startswith("python_function"):
                args = shlex.split(command.removeprefix("python_function").strip())
                return python_function(*args)
            # all other commands are executed as usual
            return super().execute(action, cwd)

    agent = DefaultAgent(
        LitellmModel(model_name=model_name),
        EnvironmentWithPythonFunctions(),
    )
    ```

An agent that exits when the `submit` command is issued:

=== "Subclassing the agent"

    ```python
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.exceptions import Submitted

    class AgentQuitsOnSubmit(DefaultAgent):
        def execute_actions(self, message: dict) -> list[dict]:
            for action in message.get("extra", {}).get("actions", []):
                if action.get("command", "") == "submit":
                    # The `Submitted` exception will be caught by the agent and
                    # the final output will be printed.
                    raise Submitted({
                        "role": "exit",
                        "content": "The agent has finished its task.",
                        "extra": {"exit_status": "Submitted", "submission": ""},
                    })
            return super().execute_actions(message)
    ```

=== "Subclassing the environment"

    ```python
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.environments.local import LocalEnvironment
    from minisweagent.exceptions import Submitted

    class EnvironmentQuitsOnSubmit(LocalEnvironment):
        def execute(self, action: dict, cwd: str = "") -> dict:
            if action.get("command", "") == "submit":
                raise Submitted({
                    "role": "exit",
                    "content": "The agent has finished its task.",
                    "extra": {"exit_status": "Submitted", "submission": ""},
                })
            return super().execute(action, cwd)

    agent = DefaultAgent(
        LitellmModel(model_name=model_name),
        EnvironmentQuitsOnSubmit(),
    )
    ```


An agent that validates actions before execution (also an example of how to use an extended config class):

=== "Subclassing the agent"

    ```python
    import re
    from minisweagent.agents.default import DefaultAgent, AgentConfig
    from minisweagent.exceptions import FormatError
    from pydantic import BaseModel

    class ValidatingAgentConfig(AgentConfig):
        forbidden_patterns: list[str] = [
            r"rm -rf /",
            r"sudo.*passwd",
            r"mkfs\.",
        ]

    class ValidatingAgent(DefaultAgent):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs, config_class=ValidatingAgentConfig)

        def execute_actions(self, message: dict) -> list[dict]:
            for action in message.get("extra", {}).get("actions", []):
                command = action.get("command", "")
                for pattern in self.config.forbidden_patterns:
                    if re.search(pattern, command, re.IGNORECASE):
                        raise FormatError(self.model.format_message(
                            role="user", content="Action blocked: forbidden pattern detected"
                        ))
            return super().execute_actions(message)
    ```

=== "Subclassing the environment"

    ```python
    import re
    from minisweagent.agents.default import DefaultAgent
    from minisweagent.environments.local import LocalEnvironment, LocalEnvironmentConfig
    from minisweagent.models.litellm_model import LitellmModel

    class EnvironmentWithForbiddenPatternsConfig(LocalEnvironmentConfig):
        forbidden_patterns: list[str] = [
            r"rm -rf /",
            r"sudo.*passwd",
            r"mkfs\.",
        ]

    class EnvironmentWithForbiddenPatterns(LocalEnvironment):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs, config_class=EnvironmentWithForbiddenPatternsConfig)

        def execute(self, action: dict, cwd: str = "") -> dict:
            command = action.get("command", "")
            for pattern in self.config.forbidden_patterns:
                if re.search(pattern, command, re.IGNORECASE):
                    return {"output": "Action blocked: forbidden pattern detected", "returncode": 1}
            return super().execute(action, cwd)

    agent = DefaultAgent(
        LitellmModel(model_name=model_name),
        EnvironmentWithForbiddenPatterns(),
    )
    ```

### Running mini-swe-agent on Ray

[This blog post](https://www.anyscale.com/blog/massively-parallel-agentic-simulations-with-ray)
describes how to parallelize mini-swe-agent runs with Ray.

{% include-markdown "_footer.md" %}

---

## File: docs/advanced/environments.md

# Environment classes

!!! abstract "Environment classes"

    * Environments are what is executing the code generated by the LM/agent.
    * We offer different classes for either executing code directly on the host machine, or in a container (e.g., Docker, Singularity, etc.).

We support various environments for executing code through different backends.

If you run the [`mini`](../usage/mini.md) CLI, you will run in the `local` environment by default.

However, particularly for evaluating on SWE-bench, you want to run in isolated environments, so we offer multiple "backends" that you can use.

You can specify the environment class with the `--environment-class` flag or the
`environment.environment_class` key in the [agent config file](yaml_configuration.md).

* **`local`** ([`LocalEnvironment`](../reference/environments/local.md)). Executes commands directly on the host machine using `subprocess.run`. No isolation. Directly works in your current python environment.

* **`docker`** ([`DockerEnvironment`](../reference/environments/docker.md)). Executes commands with `docker exec`.

* **`singularity`** ([`SingularityEnvironment`](../reference/environments/singularity.md)) - Executes commands in Singularity/Apptainer containers. Good alternative to Docker in HPC environments where Docker is not available.

On top, there are a few more specialized environment classes that you can use:

* **`swerex_docker`** ([`SwerexDockerEnvironment`](../reference/environments/swerex_docker.md)) - Docker execution through [SWE-ReX](https://github.com/swe-agent/swe-rex)

* **`swerex_modal`** ([`SwerexModalEnvironment`](../reference/environments/swerex_modal.md)) - [Modal](https://modal.com) cloud execution through [SWE-ReX](https://github.com/swe-agent/swe-rex). Useful for training coding agents at scale with remote execution.

* **`bubblewrap`** ([`BubblewrapEnvironment`](../reference/environments/bubblewrap.md)) - **Linux only**. Uses [bubblewrap](https://github.com/containers/bubblewrap) for lightweight, unprivileged sandboxing. Experimental.

* **`contree`** ([`ContreeEnvironment`](../reference/environments/contree.md)) - Uses [ConTree](https://contree.dev/) for safe code execution sandboxing. Platform that built for agents and supports Git-like execution.

---

## File: docs/advanced/global_configuration.md

# Global configuration

!!! abstract "Configuring mini"

    * This guide shows how to configure the `mini` agent's global settings (API keys, default model, etc.).
      Basically anything that is set as environment variables or similar.
    * You should already be familiar with the [quickstart guide](../quickstart.md).
    * For more agent specific settings, see the [yaml configuration file guide](yaml_configuration.md).

!!! tip "Setting up models"

    Setting up models is also covered in the [quickstart guide](../quickstart.md).

## Setting global configuration

All global configuration can be either set as environment variables, or in the `.env` file (the exact location is printed when you run `mini`).
Environment variables take precedence over variables set in the `.env` file.

We provide several helper functions to update the global configuration.

For example, to set the default model and API keys, you can run:

```bash
mini-extra config setup
```

or to update specific settings:

```
mini-extra config set KEY VALUE
# e.g.,
mini-extra config set MSWEA_MODEL_NAME "anthropic/claude-sonnet-4-5-20250929"
mini-extra config set ANTHROPIC_API_KEY "sk-..."
```

or to unset a key:

```bash
mini-extra config unset KEY
# e.g.,
mini-extra config unset ANTHROPIC_API_KEY
```

You can also edit the `.env` file directly and we provide a helper function for that:

```bash
mini-extra config edit
```

To set environment variables (recommended for temporary experimentation or API keys):

```bash
export KEY="value"
# windows:
setx KEY "value"
```

## Models, keys, costs

!!! tip "See also"

    Read the [quickstart guide](../quickstart.md) first—it already covers most of this.

```bash
# Default model name
# (default: not set)
MSWEA_MODEL_NAME="anthropic/claude-sonnet-4-5-20250929"
```

To ignore errors from cost tracking checks (for example for free models), set:

```bash
# CAREFUL: This can lead to unmanaged spending!
MSWEA_COST_TRACKING="ignore_errors"
```

To register extra models to litellm (see [local models](../models/local_models.md) for more details), you can either specify the path in the agent file, or set

```bash
LITELLM_MODEL_REGISTRY_PATH="/path/to/your/model/registry.json"
```

Global cost limits:

```bash
# Global limit on number of model calls (0 = no limit)
# (default: 0)
MSWEA_GLOBAL_CALL_LIMIT="100"

# Global cost limit in dollars (0 = no limit)
# (default: 0)
MSWEA_GLOBAL_COST_LIMIT="10.00"

# Number of retry attempts for model API calls
# (default: 10)
MSWEA_MODEL_RETRY_STOP_AFTER_ATTEMPT="10"
```

## Default config files

```bash
# Set a custom directory for agent config files in addition to the builtin ones
# This allows to specify them by names
MSWEA_CONFIG_DIR="/path/to/your/own/config/dir"

# Config path for mini run script
# (default: package_dir / "config" / "mini.yaml")
MSWEA_MINI_CONFIG_PATH="/path/to/your/own/config"

# Custom style path for trajectory inspector
# (default: package_dir / "config" / "inspector.tcss")
MSWEA_INSPECTOR_STYLE_PATH="/path/to/your/inspector/style.tcss"
```

### Settings for environments

```bash
# Path/name to the singularity/apptainer executable
# (default: "singularity")
MSWEA_SINGULARITY_EXECUTABLE="singularity"

# Path/name to the docker executable
# (default: "docker")
MSWEA_DOCKER_EXECUTABLE="docker"

# Path/name to the bubblewrap executable
# (default: "bwrap")
MSWEA_BUBBLEWRAP_EXECUTABLE="bwrap"
```

## Default run files

```bash
# Default run script entry point for the main CLI
# (default: "minisweagent.run.mini")
MSWEA_DEFAULT_RUN="minisweagent.run.mini"
```

{% include-markdown "_footer.md" %}

---

## File: docs/advanced/v2_migration.md

# v2.0 Migration Guide

!!! danger "Breaking Changes"

    **mini-swe-agent v2.0** brings major improvements but requires migration.
    To stay with v1.x, pin your dependency: `mini-swe-agent~=1.0`.
    See the [v1 documentation](https://mini-swe-agent.com/v1/) or the [v1 branch on GitHub](https://github.com/SWE-agent/mini-swe-agent/tree/v1).

## What's new

- **Tool calls**: Native tool calling API support (now the default)
- **Multimodal input**: Support for images and other content types

## What do I need to change?

> I only use the mini CLI with default configs

No changes needed.

> I use custom configs

You might need to move some config keys. See [Config changes](#config-changes).

> I parse/analyze trajectories

Some metadata fields moved to `extra`. See [Trajectory format](#trajectory-format).

> I use the python bindings or built custom subclasses

You will need to refactor. An agent can refactor your code based on the instructions below.

## Config changes

If you only changed `system_template` and `instance_template`, no changes needed.

**Move from `agent` to `model`:**

- `observation_template` (renamed from `action_observation_template`)
- `format_error_template`
- `action_regex` (only for text-based parsing)

**Removed:**

- `timeout_template`

**Code block format changed:**

Default action regex changed from `` ```bash `` to `` ```mswea_bash_command `` to avoid conflicts with bash examples in prompts.

**Completion signal changed:**

From `echo MINI_SWE_AGENT_FINAL_OUTPUT` to `echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT`.

**New structure:**

```yaml
agent:
  system_template: "..."
  instance_template: "..."
  step_limit: 0
  cost_limit: 3.
environment:
  cwd: "..."
  timeout: 30
model:
  model_name: "..."
  observation_template: "..."
  format_error_template: "..."
```

**CLI now supports multiple configs and key-value overrides:**

```bash
mini -c mini.yaml -c model.model_kwargs.temperature=0.5
mini -c swebench.yaml -c agent.step_limit=100
mini -c mini.yaml -c /path/to/model.yaml
```

!!! warning
    If you use `-c`, you will not load the full default config, so make sure to always specify your config file in addition to any overrides/updates.

## Tool calling

v2.0 uses native tool calling by default (instead of regex-based text parsing).

**What's the difference?**

- Tool calling (default): Model uses native tool calling API to invoke a "bash" tool
- Text-based (legacy): Model outputs commands in markdown code blocks (or similar), regex extracts them

**How to use it:**

Tool calling is the default. The CLI uses `mini.yaml` and `swebench.yaml` which are configured for tool calling.

```bash
# Default (tool calling)
mini
python -m minisweagent.run.benchmarks.swebench
mini-extra swebench

# Text-based parsing
mini-extra swebench -c swebench_backticks.yaml
mini -c mini_textbased.yaml
```

**For custom configs:**

```yaml
model:
  model_class: litellm  # tool calling (default)
  model_name: anthropic/claude-sonnet-4-5-20250929

# or for text-based:
model:
  model_class: litellm_textbased
  action_regex: "```mswea_bash_command\\s*\\n(.*?)\\n```"
```

## Trajectory format

- In v1, all messages in the trajectory's `messages` field were "hand-formatted", i.e., had a `content: str` and `role: str` field.
- **In v2, we use the model's native output as the basis for the message and only add the `extra` field to it**.

If you use a model that uses the standard `/completion` endpoint, then you will still always have a `content: str` and `role: str` field.
However, if you use the [`/response`](https://platform.openai.com/docs/api-reference/responses) endpoint, then things might look different.

In other words: the exact message structure depends on the model you use.

* Advantage: Any model message structure is supported
* Disadvantage: If you parse trajectories, you might need to adapt to the message structure of the model you use.

## Removed & renamed

**Removed features:**

- **"Visual" UI**: The `-v` flag for the alternate, textual based `mini -v` CLI is no longer supported. This was a tough decision to make, but in the end the visual mode didn't see the adoption we wanted and is significantly more complex to maintain than the default interface.
- **Rotating API keys**: `ANTHROPIC_API_KEYS` with `::` separator no longer supported. Use single `ANTHROPIC_API_KEY`.
- **`github_issue` run script**: The dedicated `github_issue.py` run script was removed. Use the `mini` CLI instead.
- **`MSWEA_MODEL_API_KEY` environment variable**: No longer used to override API keys.

**Removed model classes:**

- **`anthropic` model class**: Removed. Use `litellm` model class for Anthropic models (make sure that cache control is enabled).

**Renamed model classes:**

| v1 name | v2 name |
|---------|---------|
| `litellm_response_api` | `litellm_response` |
| `portkey_response_api` | `portkey_response` |

**New model classes:**

| Name | Description |
|------|-------------|
| `litellm_textbased` | Text-based parsing (regex) instead of tool calls |
| `openrouter_textbased` | Text-based parsing for OpenRouter |
| `openrouter_response` | OpenRouter with response API |

**New environment:**

- **`swerex_modal`**: Run environments on Modal (requires `pip install mini-swe-agent[modal]`)

## Architecture changes

1. **Responsibility shift**: Models now parse actions and format observations. This enables switching between tool calls and text parsing by changing model classes. The Agent class is now a simpler coordinator.

2. **Stateless models**: Cost tracking moved to Agent. The `cost` and `n_calls` attributes were removed from the Model protocol.

3. **Pydantic configs**: `AgentConfig` (and other configs) changed from `dataclass` to Pydantic `BaseModel`. This requires `pydantic >= 2.0`.

4. **New protocol methods**: All classes implement `get_template_vars()` and `serialize()` instead of requiring specific attributes.

### Protocol changes

If you want to write a custom Model, Environment or Agent compatible with `mini-swe-agent`, you don't need to subclass anything.
Rather, mini-swe-agent fully uses duck typing with [protocols](https://typing.python.org/en/latest/spec/protocol.html)
(tl;dr: as long as you implement the required methods, you can use any class as a Model, Environment or Agent).
Config options like `--config-class` also take full import classes, so you can put your classes wherever you want.

**Model protocol:**

```python
# Removed attributes
cost: float      # moved to Agent
n_calls: int     # moved to Agent

# New methods
def format_message(self, **kwargs) -> dict: ...
def format_observation_messages(self, message: dict, outputs: list[dict], template_vars: dict | None = None) -> list[dict]: ...
def serialize(self) -> dict: ...
```

**Environment protocol:**

```python
# Changed signature
def execute(self, action: dict, cwd: str = "") -> dict[str, Any]: ...  # was: (command: str) -> dict[str, str]

# New method
def serialize(self) -> dict: ...
```

**Agent protocol:**

```python
# Removed attributes (you don't need to implement these anymore, but you can)
model: Model
env: Environment
messages: list[dict]

# Changed return type
def run(self, task: str, **kwargs) -> dict: ...  # was: tuple[str, str]

# New method
def save(self, path: Path | None, *extra_dicts) -> dict: ...
```

### Exception changes

All flow control exceptions now inherit from `InterruptAgentFlow` and moved to `minisweagent.exceptions`:

```python
InterruptAgentFlow (base)
├── Submitted (task completed)
├── LimitsExceeded (cost/step limit)
├── FormatError (invalid model output)
└── UserInterruption (user cancelled)  # new
```

**Removed exception classes:**

- `NonTerminatingException` - use `InterruptAgentFlow` base class
- `TerminatingException` - use `InterruptAgentFlow` base class
- `ExecutionTimeoutError` - removed (no longer used)

```python
# Old
from minisweagent.agents.default import Submitted, FormatError

# New
from minisweagent.exceptions import Submitted, FormatError
```

### Agent.run() return value

```python
# Old (v1)
submission, exit_status = agent.run(task)  # tuple[str, str]

# New (v2)
result = agent.run(task)  # dict
submission = result["submission"]
exit_status = result["exit_status"]
```

The `run()` method returns the `extra` dict from the final exit message. For full trajectory data, use `agent.save(path)` or `agent.serialize()`.

---

## File: docs/advanced/yaml_configuration.md

# Yaml config files

!!! abstract "Agent configuration files"

    * You can configure the agent's behavior using YAML configuration files. This guide shows how to do that.
    * You should already be familiar with the [quickstart guide](../quickstart.md).
    * For global environment settings (API keys, default model, etc., basically anything that can be set as environment variables), see [global configuration](global_configuration.md).
    * Want more? See [python bindings](cookbook.md) for subclassing & developing your own agent.

## Overall structure

Configuration files look like this:

??? note "Configuration file"

    ```yaml
    --8<-- "src/minisweagent/config/mini.yaml"
    ```

We use the following top-level keys:

- `agent`: Agent configuration (prompt templates, cost limits etc.)
- `environment`: Environment configuration (if you want to run in a docker container, etc.)
- `model`: Model configuration (model name, reasoning strength, etc.)
- `run`: Run configuration (output file, etc.)

## Agent configuration

Different agent classes might have slightly different configuration options.
You can find the full list of options in the [API reference](../reference/agents/default.md).

To use a different agent class, you can set the `agent_class` key to the name of the agent class you want to use
or even to an import path (to use your own custom agent class even if it is not yet part of the mini-SWE-agent package).

### Prompt templates

We use [Jinja2](https://jinja.palletsprojects.com/) to render templates (e.g., the instance template).

TL;DR: You include variables with double (!) curly braces, e.g. `{{task}}` to include the task that was given to the agent.

However, you can also do fairly complicated logic like this directly from your template:

??? note "Example: Dealing with long observations"

    The following snippets shortens long observations and displays a warning if the output is too long.

    ```jinja
    <returncode>{{output.returncode}}</returncode>
    {% if output.output | length < 10000 -%}
        <output>
            {{ output.output -}}
        </output>
    {%- else -%}
        <warning>
            The output of your last command was too long.
            Please try a different command that produces less output.
            If you're looking at a file you can try use head, tail or sed to view a smaller number of lines selectively.
            If you're using grep or find and it produced too much output, you can use a more selective search pattern.
            If you really need to see something from the full command's output, you can redirect output to a file and then search in that file.
        </warning>

        {%- set elided_chars = output.output | length - 10000 -%}

        <output_head>
            {{ output.output[:5000] }}
        </output_head>

        <elided_chars>
            {{ elided_chars }} characters elided
        </elided_chars>

        <output_tail>
            {{ output.output[-5000:] }}
        </output_tail>
    {%- endif -%}
    ```

In all builtin agents, you can use the following variables:

- Environment variables (`LocalEnvironment` only, see discussion [here](https://github.com/SWE-agent/mini-swe-agent/pull/425))
- Agent config variables (i.e., anything that was set in the `agent` section of the config file, e.g., `step_limit`, `cost_limit`, etc.)
- Environment config variables (i.e., anything that was set in the `environment` section of the config file, e.g., `cwd`, `timeout`, etc.)
- Variables passed to the `run` method of the agent (by default that's only `task`, but you can pass other variables if you want to)
- Output of the last action execution (i.e., `output` from the `execute_action` method)

### Using tool calls

Make sure to use the appropriate model class and matching configuration.

### Custom Action Parsing from Text

mini-SWE-agent can parse actions from markdown code blocks (` ```mswea_bash_command ... ``` `) or from tool calls.
You can customize this behavior by setting the `action_regex` field to support different formats like XML.

!!! warning "Important"

    If you set a custom action_regex (e.g. `<action>(.*?)</action>`), you must use the same output format across all prompt templates (system_template, instance_template, format_error_template, etc.), ensuring the LLM wraps commands accordingly. See the example below for a complete configuration.


??? example "Using XML format instead of markdown"

    This example uses the same structure as the default mini.yaml config, but with `<action>` tags instead of markdown code blocks:

    ```yaml
    --8<-- "src/minisweagent/config/benchmarks/swebench_xml.yaml"
    ```

    You can also directly load this config by specifying `--config swebench_xml`.


??? example "Default markdown format"

    This is the default configuration (already the default, you don't need to specify this):


    ```yaml
    model:
      action_regex: ```mswea_bash_command\s*\n(.*?)\n```
    agent:
      system_template: |
        Your response must contain exactly ONE bash code block.

        ```mswea_bash_command
        your_command_here
        ```
    ```

!!! warning "Linebreaks & escaping"

    When specifying `action_regex` from the `yaml` config file, make sure you understand how escaping in yaml files works.
    For example, when you use the `|` primitive, your regex might have a linbreak at the end which is probably not what you want.
    The best way is to keep your regex on a single line and NOT use any quotation marks around it. You do NOT need to escape any characters in the regex. Example: `action_regex: (.*?)`

## Model configuration

See [this guide](../models/quickstart.md) for more details on model configuration.

## Environment configuration

See [this guide](../advanced/environments.md) for more details on environment configuration.

## Run configuration

See the information in "Usage".

{% include-markdown "_footer.md" %}

---

## File: docs/models/local_models.md

!!! abstract "Local models"

    * This guide shows how to set up local models.
    * You should already be familiar with the [quickstart guide](../quickstart.md).
    * You should also quickly skim the [global configuration guide](../advanced/global_configuration.md) to understand
      the global configuration and [yaml configuration files guide](../advanced/yaml_configuration.md).


!!! tip "Examples"

    * [Issue #303](https://github.com/SWE-agent/mini-swe-agent/issues/303) has several examples of how to use local models.
    * We also welcome concrete examples of how to use local models per pull request into this guide.

## Using litellm

Currently, models are supported via [`litellm`](https://www.litellm.ai/) by default.

There are typically two steps to using local models:

1. Editing the agent config file to add settings like `custom_llm_provider` and `api_base`.
2. Either ignoring errors from cost tracking or updating the model registry to include your local model.

### Setting API base/provider

If you use local models, you most likely need to add some extra keywords to the `litellm` call.
This is done with the `model_kwargs` dictionary which is directly passed to `litellm.completion`.

In other words, this is how we invoke litellm:

```python
litellm.completion(
    model=model_name,
    messages=messages,
    **model_kwargs
)
```

You can set `model_kwargs` in an agent config file like the following one:

??? note "Default configuration file"

    ```yaml
    --8<-- "src/minisweagent/config/mini.yaml"
    ```

In the last section, you can add

```yaml
model:
  model_name: "my-local-model"
  model_kwargs:
    custom_llm_provider: "openai"
    api_base: "https://..."
    ...
  ...
```

!!! tip "Updating the default `mini` configuration file"

    You can set the `MSWEA_MINI_CONFIG_PATH` setting to set path to the default `mini` configuration file.
    This will allow you to override the default configuration file with your own.
    See the [global configuration guide](../advanced/global_configuration.md) for more details.

If this is not enough, our model class should be simple to modify:

??? note "Complete model class"

    - [Read on GitHub](https://github.com/swe-agent/mini-swe-agent/blob/main/src/minisweagent/models/litellm_model.py)
    - [API reference](../reference/models/litellm.md)

    ```python
    --8<-- "src/minisweagent/models/litellm_model.py"
    ```

The other part that you most likely need to figure out are costs.
There are two ways to do this with `litellm`:

1. You set up a litellm proxy server (which gives you a lot of control over all the LM calls)
2. You update the model registry (next section)

### Cost tracking

If you run with the above, you will most likely get an error about missing cost information.

If you do not need cost tracking, you can ignore these errors, ideally by editing your agent config file to add:

```yaml
model:
  cost_tracking: "ignore_errors"
  ...
...
```

Alternatively, you can set the global setting:

```bash
export MSWEA_COST_TRACKING="ignore_errors"
```

However, note that this is a global setting, and will affect all models!

However, the best way to handle the cost issue is to add a model registry to litellm to include your local model.

LiteLLM gets its cost and model metadata from [this file](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json). You can override or add data from this file if it's outdated or missing your desired model by including a custom registry file.

The model registry JSON file should follow LiteLLM's format:

```json
{
  "my-custom-model": {
    "max_tokens": 4096,
    "input_cost_per_token": 0.0001,
    "output_cost_per_token": 0.0002,
    "litellm_provider": "openai",
    "mode": "chat"
  },
  "my-local-model": {
    "max_tokens": 8192,
    "input_cost_per_token": 0.0,
    "output_cost_per_token": 0.0,
    "litellm_provider": "ollama",
    "mode": "chat"
  }
}
```

!!! warning "Model names"

    Model names are case sensitive. Please make sure you have an exact match.

!!! warning "Model provider"

    If you use the `custom_llm_provider` or have a provider prefixed to the model name (e.g., `openai/...`),
    then this must also match `litellm_provider` in the config!

There are two ways of setting the path to the model registry:

1. Set `LITELLM_MODEL_REGISTRY_PATH` (e.g., `mini-extra config set LITELLM_MODEL_REGISTRY_PATH /path/to/model_registry.json`)
2. Set `litellm_model_registry` in the agent config file

```yaml
model:
  litellm_model_registry: "/path/to/model_registry.json"
  ...
...
```

## Concrete examples

### Generating SWE-bench trajectories with vLLM

This example shows how to generate SWE-bench trajectories using [vLLM](https://docs.vllm.ai/en/latest/) as the local inference engine.

First, launch a vLLM server with your chosen model. For example:

```bash
vllm serve ricdomolm/mini-coder-1.7b &
```

By default, the server will be available at `http://localhost:8000`.

Second, edit the mini-swe-agent SWE-bench config file located in `src/minisweagent/config/benchmarks/swebench.yaml` to include your local vLLM model:

```yaml
model:
  model_name: "hosted_vllm/ricdomolm/mini-coder-1.7b"  # or hosted_vllm/path/to/local/model
  model_kwargs:
    api_base: "http://localhost:8000/v1"  # adjust if using a non-default port/address
```

If you need a custom registry, as detailed above, create a `registry.json` file:

```bash
cat > registry.json <<'EOF'
{
  "ricdomolm/mini-coder-1.7b": {
    "max_tokens": 40960,
    "input_cost_per_token": 0.0,
    "output_cost_per_token": 0.0,
    "litellm_provider": "hosted_vllm",
    "mode": "chat"
  }
}
EOF
```

Now you’re ready to generate trajectories! Let's solve the `django__django-11099` instance of SWE-bench Verified:

```bash
LITELLM_MODEL_REGISTRY_PATH=registry.json mini-extra swebench \
    --output test/ --subset verified --split test --filter '^(django__django-11099)$'
```

You should now see the generated trajectory in the `test/` directory.

--8<-- "docs/_footer.md"

---

## File: docs/models/quickstart.md

# Model setup quickstart

!!! tip "Setup"

    * In most cases, you can simply run `mini-extra config setup` to set up your default model and API keys.
      This should be run the first time you run `mini`.
    * By default we support all models using [`litellm`](https://github.com/BerriAI/litellm).
    * We also offer support for models via [Openrouter](https://openrouter.ai/) and [Portkey](https://portkey.ai/).

## Setting API keys

There are several ways to set your API keys:

* **Recommended**: Run our setup script: `mini-extra config setup`. This should also run automatically the first time you run `mini`.
* Use `mini-extra config set ANTHROPIC_API_KEY <your-api-key>` to put the key in the `mini` [config file](../advanced/global_configuration.md).
* Export your key as an environment variable: `export ANTHROPIC_API_KEY=<your-api-key>` (this is not persistent if you restart your shell, unless you add it to your shell config, like `~/.bashrc` or `~/.zshrc`).
* If you run several agents in parallel, see our note about rotating anthropic keys [here](../advanced/global_configuration.md).

??? note "All the API key names"

    We use [`litellm`](https://github.com/BerriAI/litellm) to support most models.
    Here's a list of all the API key names available in `litellm`:

    ```
    ALEPH_ALPHA_API_KEY
    ALEPHALPHA_API_KEY
    ANTHROPIC_API_KEY
    ANYSCALE_API_KEY
    AZURE_AI_API_KEY
    AZURE_API_KEY
    AZURE_OPENAI_API_KEY
    BASETEN_API_KEY
    CEREBRAS_API_KEY
    CLARIFAI_API_KEY
    CLOUDFLARE_API_KEY
    CO_API_KEY
    CODESTRAL_API_KEY
    COHERE_API_KEY
    DATABRICKS_API_KEY
    DEEPINFRA_API_KEY
    DEEPSEEK_API_KEY
    FEATHERLESS_AI_API_KEY
    FIREWORKS_AI_API_KEY
    FIREWORKS_API_KEY
    FIREWORKSAI_API_KEY
    GEMINI_API_KEY
    GROQ_API_KEY
    HUGGINGFACE_API_KEY
    INFINITY_API_KEY
    MARITALK_API_KEY
    MISTRAL_API_KEY
    NEBIUS_API_KEY
    NLP_CLOUD_API_KEY
    NOVITA_API_KEY
    NVIDIA_NIM_API_KEY
    OLLAMA_API_KEY
    OPENAI_API_KEY
    OPENAI_LIKE_API_KEY
    OPENROUTER_API_KEY
    OR_API_KEY
    PALM_API_KEY
    PERPLEXITYAI_API_KEY
    PREDIBASE_API_KEY
    PROVIDER_API_KEY
    REPLICATE_API_KEY
    TOGETHERAI_API_KEY
    VOLCENGINE_API_KEY
    VOYAGE_API_KEY
    WATSONX_API_KEY
    WX_API_KEY
    XAI_API_KEY
    XINFERENCE_API_KEY
    ```

    In addition, Portkey models use the `PORTKEY_API_KEY` environment variable.

## Selecting a model

!!! note "Model names and providers."

    We support most models using [`litellm`](https://github.com/BerriAI/litellm).
    You can find a list of their supported models [here](https://docs.litellm.ai/docs/providers).
    Please always include the provider in the model name, e.g., `anthropic/claude-...`.

* **Recommended**: `mini-extra config setup` (should be run the first time you run `mini`) can set the default model for you
* All command line interfaces allow you to set the model name with `-m` or `--model`.
* In addition, you can set the default model with `mini-extra config set MSWEA_MODEL_NAME <model-name>`, by editing the global [config file](../advanced/global_configuration.md) (shortcut: `mini-extra config edit`), or by setting the `MSWEA_MODEL_NAME` environment variable.
* You can also set your model in a config file (key `model_name` under `model`).
* If you want to use local models, please check this [guide](local_models.md).

!!! note "Popular models"

    Here's a few examples of popular models:

    ```
    anthropic/claude-opus-4-6-20260205
    openai/gpt-5.4
    openai/gpt-5.4-mini
    gemini/gemini-2.5-pro
    deepseek/deepseek-chat
    ```

    ??? note "List of all supported models"

        Here's a list of all model names supported by `litellm` as of Aug 29th 2025.
        For even more recent models, check the [`model_prices_and_context_window.json` file from litellm](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json).

        ```
        --8<-- "docs/data/all_models.txt"
        ```

To find the corresponding API key, check the previous section.

## Extra model settings

To configure reasoning efforts or similar settings, you need to edit the [agent config file](../advanced/yaml_configuration.md).
In newer versions, the location of the config file is printed when you run `mini` ("agent config" in the output).

Here's a few general examples:

=== "Temperature"

    `litellm` allows to set model-specific settings with the `model_kwargs` key:

    ```yaml
    model:
      model_name: "anthropic/claude-sonnet-4-5-20250929"
        model_kwargs:
          temperature: 0.0
    ```

    Note that temperature isn't supported by all models.

=== "GPT-5 reasoning effort (Chat Completions API)"

    `litellm` allows to set model-specific settings with the `model_kwargs` key:

    ```yaml
    model:
      model_name: "openai/gpt-5-mini"
      model_kwargs:
        drop_params: true
        reasoning_effort: "high"
        verbosity: "medium"
    ```

    Here, `drop_params` is used to drop any parameters that are not supported by the model.

=== "GPT-5 with Responses API"

    For OpenAI models that support the Responses API, you can use the `litellm_response_toolcall` model class:

    ```yaml
    model:
      model_class: "litellm_response_toolcall"
      model_name: "openai/gpt-5-mini"
      model_kwargs:
        drop_params: true
        reasoning:
          effort: "high"
    ```

=== "OpenRouter"

    This example explicitly sets the model class to `openrouter` (see the next section for more details).
    It also explicitly sets the providers to disable switching between them (this is useful if you need
    very consistent cost behavior, e.g., for benchmarking, but it's not recommended if you're just interested
    in getting low latency and good prices).

    ```yaml
    model:
        model_name: "moonshotai/kimi-k2-0905"
        model_class: "openrouter"
        model_kwargs:
            temperature: 0.0
            provider:
              allow_fallbacks: false
              only: ["Moonshot AI"]
    ```

=== "Local models"

    Using `litellm` with local models:

    ```yaml
    model:
      model_name: "my-local-model"
      model_kwargs:
        custom_llm_provider: "openai"
        api_base: "https://..."
        ...
    ```

    See [this guide](local_models.md) for more details on local models.
    In particular, you need to configure token costs for local models.

Here are more examples of how to configure specific models:

=== "Gemini 3 (Openrouter)"

    ```yaml
    model:
        model_name: "google/gemini-3-pro-preview"
        model_class: openrouter
        model_kwargs:
            temperature: 0.0
    ```

=== "GPT 5.1 medium (Portkey)"

    ```yaml
    model:
        model_name: "@openai/gpt-5.1"
        model_class: portkey
        model_kwargs:
            reasoning_effort: "medium"
            verbosity: "medium"
    ```

=== "Claude Haiku 4.5"

    ```yaml
    model:
        model_name: "anthropic/claude-haiku-4-5-20251001"
        model_kwargs:
            temperature: 0.0
    ```

=== "GPT 5 mini (Portkey)"

    ```yaml
    model:
        model_name: "@openai/gpt-5-mini"
        model_class: portkey
    ```

=== "Deepseek"

    ```yaml
    model:
        model_name: "deepseek/deepseek-reasoner"
        model_kwargs:
            temperature: 0.0
    ```

=== "Minimax (Openrouter)"

    ```yaml
    model:
        model_name: "minimax/minimax-m2"
        model_class: openrouter
        model_kwargs:
            temperature: 0.0
    ```

## Model classes

We support the various models through different backends.
By default (if you only specify the model name), we pick the best backend for you.
This will almost always default to `litellm` (with Anthropic models being a special case as they need to have explicit cache breakpoint handling).

However, there are a few other backends that you can use and specify with the `--model-class` flag or the
`model.model_class` key in the agent config file (see previous section).

For example:

=== "Openrouter model"

    ```bash
    mini -m "moonshotai/kimi-k2-0905" --model-class openrouter
    ```

    **Alternatively:** In the agent config file:

    ```yaml
    model:
        model_name: "moonshotai/kimi-k2-0905"
        model_class: openrouter
    ```

=== "Portkey model"

    ```bash
    mini -m "claude-sonnet-4-5-20250929" --model-class portkey
    ```

    **Alternatively:** In the agent config file:
    ```yaml
    model:
        model_name: "claude-sonnet-4-5-20250929"
        model_class: portkey
    ```


* **`litellm`** ([`LitellmModel`](../reference/models/litellm.md)) - **Default and recommended**. Supports most models through [litellm](https://github.com/BerriAI/litellm). Works with OpenAI, Anthropic, Google, and many other providers. Anthropic models automatically get cache control settings when the model name contains "anthropic", "claude", "sonnet", or "opus".

* **`litellm_response`** ([`LitellmResponseModel`](../reference/models/litellm_response_toolcall.md)) - Specialized version of `LitellmModel` that uses OpenAI's Responses API with native tool calling. Useful for models like GPT-5 and required for models like GPT-5-codex. Maintains conversation state across turns.

* **`openrouter`** ([`OpenRouterModel`](../reference/models/openrouter.md)) - Direct integration with [OpenRouter](https://openrouter.ai/) API for accessing various models through a single endpoint.

* **`portkey`** ([`PortkeyModel`](../reference/models/portkey.md)) - Integration with [Portkey](https://portkey.ai/) for accessing various models with enhanced observability, caching, and routing features. Note that this still uses `litellm` to calculate costs.

On top, there's a few more exotic model classes that you can use:

* **`deterministic`** ([`DeterministicModel`](../reference/models/test_models.md)) - Returns predefined responses for testing and development purposes.
* **`minisweagent.models.extra.roulette.RouletteModel` and `minisweagent.models.extra.roulette.InterleavingModel`** ([`RouletteModel`](../reference/models/extra.md) and [`InterleavingModel`](../reference/models/extra.md)) - Randomly selects or interleaves multiple configured models for each query. See [this blog post](https://www.swebench.com/SWE-bench/blog/2025/08/19/mini-roulette/) for more details.

As with the last two, you can also specify any import path to your own custom model class (even if it is not yet part of the mini-SWE-agent package).

--8<-- "docs/_footer.md"

---

## File: docs/models/troubleshooting.md

# Model trouble shooting

This section has examples of common error messages and how to fix them.

## Litellm

`litellm` is the default model class and is used to support most models.

### Invalid API key

```json
AuthenticationError: litellm.AuthenticationError: geminiException - {
  "error": {
    "code": 400,
    "message": "API key not valid. Please pass a valid API key.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "API_KEY_INVALID",
        "domain": "googleapis.com",
        "metadata": {
          "service": "generativelanguage.googleapis.com"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.LocalizedMessage",
        "locale": "en-US",
        "message": "API key not valid. Please pass a valid API key."
      }
    ]
  }
}
 You can permanently set your API key with `mini-extra config set KEY VALUE`.
```

Double check your API key and make sure it is correct.
You can take a look at all your API keys with `mini-extra config edit`.

### "Weird" authentication error

If you fail to authenticate but don't see the previous error message,
it might be that you forgot to include the provider in the model name.

For example, this:

```
  File "/Users/.../.virtualenvs/openai/lib/python3.12/site-packages/google/auth/_default.py", line 685, in default
    raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)
google.auth.exceptions.DefaultCredentialsError: Your default credentials were not found. To set up Application Default Credentials, see
https://cloud.google.com/docs/authentication/external/set-up-adc for more information.
```

happens if you forgot to prefix your gemini model with `gemini/`.

### Error during cost calculation

```
Exception: This model isn't mapped yet. model=together_ai/qwen/qwen3-coder-480b-a35b-instruct-fp8, custom_llm_provider=together_ai.
Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json.
```

`litellm` doesn't know about the cost of your model.
Take a look at the model registry section of the [local models](local_models.md) guide to add it.

Another common mistake is to not include any or the correct provider in the model name (e.g., `gemini-2.0-flash` instead of `gemini/gemini-2.0-flash`).

## Temperature not supported

Some models (like `o1`, `o3`, `GPT-5` etc.) do not support temperature. The default config no longer specifies a temperature value, so this should work out of the box now.

## Portkey

### Error during cost calculation

We use `litellm` to calculate costs for Portkey models because Portkey doesn't seem to provide per-request cost information without
very inconvenient APIs.

This can lead to errors likethis:

```
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/minisweagent/models/portkey_model.py", line 85, in query
    cost = litellm.cost_calculator.completion_cost(response)
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/litellm/cost_calculator.py", line 973, in completion_cost
    raise e
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/litellm/cost_calculator.py", line 966, in completion_cost
    raise e
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/litellm/cost_calculator.py", line 928, in completion_cost
    ) = cost_per_token(
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/litellm/cost_calculator.py", line 218, in cost_per_token
    _, custom_llm_provider, _, _ = litellm.get_llm_provider(model=model)
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/litellm/litellm_core_utils/get_llm_provider_logic.py", line 395, in get_llm_provider
    raise e
  File "/opt/miniconda3/envs/clash/lib/python3.10/site-packages/litellm/litellm_core_utils/get_llm_provider_logic.py", line 372, in get_llm_provider
    raise litellm.exceptions.BadRequestError(  # type: ignore
litellm.exceptions.BadRequestError: litellm.BadRequestError: LLM Provider NOT provided. Pass in the LLM provider you are trying to call. You passed model=grok-code-fast-1
 Pass model as E.g. For 'Huggingface' inference endpoints pass in `completion(model='huggingface/starcoder',..)` Learn more: https://docs.litellm.ai/docs/providers
```

In this case, the issue is simply that the portkey model name doesn't match the litellm model name (and very specifically here
doesn't include the provider).

To fix this, you can manually set the litellm model name to the portkey model name with the `litellm_model_name_override` key.
For example:

```yaml
model:
  model_name: "grok-code-fast-1"  # the portkey model name
  model_class: "portkey"  # make sure to use the portkey model class
  litellm_model_name_override: "xai/grok-code-fast-1"  # the litellm model name for cost information
  ...
```

--8<-- "docs/_footer.md"