| 1 | # v2.0 Migration Guide
|
| 2 |
|
| 3 | !!! danger "Breaking Changes"
|
| 4 |
|
| 5 | **mini-swe-agent v2.0** brings major improvements but requires migration.
|
| 6 | To stay with v1.x, pin your dependency: `mini-swe-agent~=1.0`.
|
| 7 | 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).
|
| 8 |
|
| 9 | ## What's new
|
| 10 |
|
| 11 | - **Tool calls**: Native tool calling API support (now the default)
|
| 12 | - **Multimodal input**: Support for images and other content types
|
| 13 |
|
| 14 | ## What do I need to change?
|
| 15 |
|
| 16 | > I only use the mini CLI with default configs
|
| 17 |
|
| 18 | No changes needed.
|
| 19 |
|
| 20 | > I use custom configs
|
| 21 |
|
| 22 | You might need to move some config keys. See [Config changes](#config-changes).
|
| 23 |
|
| 24 | > I parse/analyze trajectories
|
| 25 |
|
| 26 | Some metadata fields moved to `extra`. See [Trajectory format](#trajectory-format).
|
| 27 |
|
| 28 | > I use the python bindings or built custom subclasses
|
| 29 |
|
| 30 | You will need to refactor. An agent can refactor your code based on the instructions below.
|
| 31 |
|
| 32 | ## Config changes
|
| 33 |
|
| 34 | If you only changed `system_template` and `instance_template`, no changes needed.
|
| 35 |
|
| 36 | **Move from `agent` to `model`:**
|
| 37 |
|
| 38 | - `observation_template` (renamed from `action_observation_template`)
|
| 39 | - `format_error_template`
|
| 40 | - `action_regex` (only for text-based parsing)
|
| 41 |
|
| 42 | **Removed:**
|
| 43 |
|
| 44 | - `timeout_template`
|
| 45 |
|
| 46 | **Code block format changed:**
|
| 47 |
|
| 48 | Default action regex changed from `` ```bash `` to `` ```mswea_bash_command `` to avoid conflicts with bash examples in prompts.
|
| 49 |
|
| 50 | **Completion signal changed:**
|
| 51 |
|
| 52 | From `echo MINI_SWE_AGENT_FINAL_OUTPUT` to `echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT`.
|
| 53 |
|
| 54 | **New structure:**
|
| 55 |
|
| 56 | ```yaml
|
| 57 | agent:
|
| 58 | system_template: "..."
|
| 59 | instance_template: "..."
|
| 60 | step_limit: 0
|
| 61 | cost_limit: 3.
|
| 62 | environment:
|
| 63 | cwd: "..."
|
| 64 | timeout: 30
|
| 65 | model:
|
| 66 | model_name: "..."
|
| 67 | observation_template: "..."
|
| 68 | format_error_template: "..."
|
| 69 | ```
|
| 70 |
|
| 71 | **CLI now supports multiple configs and key-value overrides:**
|
| 72 |
|
| 73 | ```bash
|
| 74 | mini -c mini.yaml -c model.model_kwargs.temperature=0.5
|
| 75 | mini -c swebench.yaml -c agent.step_limit=100
|
| 76 | mini -c mini.yaml -c /path/to/model.yaml
|
| 77 | ```
|
| 78 |
|
| 79 | !!! warning
|
| 80 | 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.
|
| 81 |
|
| 82 | ## Tool calling
|
| 83 |
|
| 84 | v2.0 uses native tool calling by default (instead of regex-based text parsing).
|
| 85 |
|
| 86 | **What's the difference?**
|
| 87 |
|
| 88 | - Tool calling (default): Model uses native tool calling API to invoke a "bash" tool
|
| 89 | - Text-based (legacy): Model outputs commands in markdown code blocks (or similar), regex extracts them
|
| 90 |
|
| 91 | **How to use it:**
|
| 92 |
|
| 93 | Tool calling is the default. The CLI uses `mini.yaml` and `swebench.yaml` which are configured for tool calling.
|
| 94 |
|
| 95 | ```bash
|
| 96 | # Default (tool calling)
|
| 97 | mini
|
| 98 | python -m minisweagent.run.benchmarks.swebench
|
| 99 | mini-extra swebench
|
| 100 |
|
| 101 | # Text-based parsing
|
| 102 | mini-extra swebench -c swebench_backticks.yaml
|
| 103 | mini -c mini_textbased.yaml
|
| 104 | ```
|
| 105 |
|
| 106 | **For custom configs:**
|
| 107 |
|
| 108 | ```yaml
|
| 109 | model:
|
| 110 | model_class: litellm # tool calling (default)
|
| 111 | model_name: anthropic/claude-sonnet-4-5-20250929
|
| 112 |
|
| 113 | # or for text-based:
|
| 114 | model:
|
| 115 | model_class: litellm_textbased
|
| 116 | action_regex: "```mswea_bash_command\\s*\\n(.*?)\\n```"
|
| 117 | ```
|
| 118 |
|
| 119 | ## Trajectory format
|
| 120 |
|
| 121 | - In v1, all messages in the trajectory's `messages` field were "hand-formatted", i.e., had a `content: str` and `role: str` field.
|
| 122 | - **In v2, we use the model's native output as the basis for the message and only add the `extra` field to it**.
|
| 123 |
|
| 124 | If you use a model that uses the standard `/completion` endpoint, then you will still always have a `content: str` and `role: str` field.
|
| 125 | However, if you use the [`/response`](https://platform.openai.com/docs/api-reference/responses) endpoint, then things might look different.
|
| 126 |
|
| 127 | In other words: the exact message structure depends on the model you use.
|
| 128 |
|
| 129 | * Advantage: Any model message structure is supported
|
| 130 | * Disadvantage: If you parse trajectories, you might need to adapt to the message structure of the model you use.
|
| 131 |
|
| 132 | ## Removed & renamed
|
| 133 |
|
| 134 | **Removed features:**
|
| 135 |
|
| 136 | - **"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.
|
| 137 | - **Rotating API keys**: `ANTHROPIC_API_KEYS` with `::` separator no longer supported. Use single `ANTHROPIC_API_KEY`.
|
| 138 | - **`github_issue` run script**: The dedicated `github_issue.py` run script was removed. Use the `mini` CLI instead.
|
| 139 | - **`MSWEA_MODEL_API_KEY` environment variable**: No longer used to override API keys.
|
| 140 |
|
| 141 | **Removed model classes:**
|
| 142 |
|
| 143 | - **`anthropic` model class**: Removed. Use `litellm` model class for Anthropic models (make sure that cache control is enabled).
|
| 144 |
|
| 145 | **Renamed model classes:**
|
| 146 |
|
| 147 | | v1 name | v2 name |
|
| 148 | |---------|---------|
|
| 149 | | `litellm_response_api` | `litellm_response` |
|
| 150 | | `portkey_response_api` | `portkey_response` |
|
| 151 |
|
| 152 | **New model classes:**
|
| 153 |
|
| 154 | | Name | Description |
|
| 155 | |------|-------------|
|
| 156 | | `litellm_textbased` | Text-based parsing (regex) instead of tool calls |
|
| 157 | | `openrouter_textbased` | Text-based parsing for OpenRouter |
|
| 158 | | `openrouter_response` | OpenRouter with response API |
|
| 159 |
|
| 160 | **New environment:**
|
| 161 |
|
| 162 | - **`swerex_modal`**: Run environments on Modal (requires `pip install mini-swe-agent[modal]`)
|
| 163 |
|
| 164 | ## Architecture changes
|
| 165 |
|
| 166 | 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.
|
| 167 |
|
| 168 | 2. **Stateless models**: Cost tracking moved to Agent. The `cost` and `n_calls` attributes were removed from the Model protocol.
|
| 169 |
|
| 170 | 3. **Pydantic configs**: `AgentConfig` (and other configs) changed from `dataclass` to Pydantic `BaseModel`. This requires `pydantic >= 2.0`.
|
| 171 |
|
| 172 | 4. **New protocol methods**: All classes implement `get_template_vars()` and `serialize()` instead of requiring specific attributes.
|
| 173 |
|
| 174 | ### Protocol changes
|
| 175 |
|
| 176 | If you want to write a custom Model, Environment or Agent compatible with `mini-swe-agent`, you don't need to subclass anything.
|
| 177 | Rather, mini-swe-agent fully uses duck typing with [protocols](https://typing.python.org/en/latest/spec/protocol.html)
|
| 178 | (tl;dr: as long as you implement the required methods, you can use any class as a Model, Environment or Agent).
|
| 179 | Config options like `--config-class` also take full import classes, so you can put your classes wherever you want.
|
| 180 |
|
| 181 | **Model protocol:**
|
| 182 |
|
| 183 | ```python
|
| 184 | # Removed attributes
|
| 185 | cost: float # moved to Agent
|
| 186 | n_calls: int # moved to Agent
|
| 187 |
|
| 188 | # New methods
|
| 189 | def format_message(self, **kwargs) -> dict: ...
|
| 190 | def format_observation_messages(self, message: dict, outputs: list[dict], template_vars: dict | None = None) -> list[dict]: ...
|
| 191 | def serialize(self) -> dict: ...
|
| 192 | ```
|
| 193 |
|
| 194 | **Environment protocol:**
|
| 195 |
|
| 196 | ```python
|
| 197 | # Changed signature
|
| 198 | def execute(self, action: dict, cwd: str = "") -> dict[str, Any]: ... # was: (command: str) -> dict[str, str]
|
| 199 |
|
| 200 | # New method
|
| 201 | def serialize(self) -> dict: ...
|
| 202 | ```
|
| 203 |
|
| 204 | **Agent protocol:**
|
| 205 |
|
| 206 | ```python
|
| 207 | # Removed attributes (you don't need to implement these anymore, but you can)
|
| 208 | model: Model
|
| 209 | env: Environment
|
| 210 | messages: list[dict]
|
| 211 |
|
| 212 | # Changed return type
|
| 213 | def run(self, task: str, **kwargs) -> dict: ... # was: tuple[str, str]
|
| 214 |
|
| 215 | # New method
|
| 216 | def save(self, path: Path | None, *extra_dicts) -> dict: ...
|
| 217 | ```
|
| 218 |
|
| 219 | ### Exception changes
|
| 220 |
|
| 221 | All flow control exceptions now inherit from `InterruptAgentFlow` and moved to `minisweagent.exceptions`:
|
| 222 |
|
| 223 | ```python
|
| 224 | InterruptAgentFlow (base)
|
| 225 | ├── Submitted (task completed)
|
| 226 | ├── LimitsExceeded (cost/step limit)
|
| 227 | ├── FormatError (invalid model output)
|
| 228 | └── UserInterruption (user cancelled) # new
|
| 229 | ```
|
| 230 |
|
| 231 | **Removed exception classes:**
|
| 232 |
|
| 233 | - `NonTerminatingException` - use `InterruptAgentFlow` base class
|
| 234 | - `TerminatingException` - use `InterruptAgentFlow` base class
|
| 235 | - `ExecutionTimeoutError` - removed (no longer used)
|
| 236 |
|
| 237 | ```python
|
| 238 | # Old
|
| 239 | from minisweagent.agents.default import Submitted, FormatError
|
| 240 |
|
| 241 | # New
|
| 242 | from minisweagent.exceptions import Submitted, FormatError
|
| 243 | ```
|
| 244 |
|
| 245 | ### Agent.run() return value
|
| 246 |
|
| 247 | ```python
|
| 248 | # Old (v1)
|
| 249 | submission, exit_status = agent.run(task) # tuple[str, str]
|
| 250 |
|
| 251 | # New (v2)
|
| 252 | result = agent.run(task) # dict
|
| 253 | submission = result["submission"]
|
| 254 | exit_status = result["exit_status"]
|
| 255 | ```
|
| 256 |
|
| 257 | The `run()` method returns the `extra` dict from the final exit message. For full trajectory data, use `agent.save(path)` or `agent.serialize()`.
|
| 258 |
|