| 1 | # Cookbook
|
| 2 |
|
| 3 | !!! abstract "Remixing & extending mini"
|
| 4 |
|
| 5 | * This guide shows how to mix the different components of the `mini` agent to create your own custom version.
|
| 6 | * You might want to first take a look at the [control flow of the default agent](control_flow.md) first
|
| 7 |
|
| 8 |
|
| 9 | !!! note "Development setup"
|
| 10 |
|
| 11 | Make sure to follow the dev setup instructions in [quickstart.md](../quickstart.md).
|
| 12 |
|
| 13 | We provide several different entry points to the agent,
|
| 14 | for example [hello world](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/hello_world.py),
|
| 15 | or the [default when calling `mini`](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/mini.py).
|
| 16 |
|
| 17 | Want to cook up your custom version and the config is not enough?
|
| 18 | Just follow the recipe below:
|
| 19 |
|
| 20 | 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))
|
| 21 | 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))
|
| 22 | 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))
|
| 23 | 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))
|
| 24 |
|
| 25 | We aim to keep all of these components very simple, but offer lots of choice between them -- enough to cover a broad range of
|
| 26 | things that you might want to do.
|
| 27 |
|
| 28 | You can override the default entry point by setting the `MSWEA_DEFAULT_RUN` environment variable to the import path of your run script.
|
| 29 |
|
| 30 | ## Hello world
|
| 31 |
|
| 32 | See [Python bindings](../usage/python_bindings.md) for the most basic example.
|
| 33 |
|
| 34 | ## Mix & match
|
| 35 |
|
| 36 | ### Models
|
| 37 |
|
| 38 | === "Hello world (use automatic model selection)"
|
| 39 |
|
| 40 | ```python
|
| 41 | from minisweagent.agents.default import DefaultAgent
|
| 42 | from minisweagent.models import get_model
|
| 43 | from minisweagent.environments.local import LocalEnvironment
|
| 44 |
|
| 45 | model_name = "anthropic/claude-sonnet-4-5-20250929"
|
| 46 |
|
| 47 | agent = DefaultAgent(
|
| 48 | get_model(input_model_name=model_name),
|
| 49 | LocalEnvironment(),
|
| 50 | )
|
| 51 | agent.run(task)
|
| 52 | ```
|
| 53 |
|
| 54 | === "Hello world (Litellm)"
|
| 55 |
|
| 56 | ```python
|
| 57 | from minisweagent.agents.default import DefaultAgent
|
| 58 | from minisweagent.models.litellm_model import LitellmModel
|
| 59 | from minisweagent.environments.local import LocalEnvironment
|
| 60 |
|
| 61 | model_name = "gpt-4o"
|
| 62 |
|
| 63 | agent = DefaultAgent(
|
| 64 | LitellmModel(model_name=model_name),
|
| 65 | LocalEnvironment(),
|
| 66 | )
|
| 67 | agent.run(task)
|
| 68 | ```
|
| 69 |
|
| 70 | ### Environments
|
| 71 |
|
| 72 | === "Hello world with local execution"
|
| 73 |
|
| 74 | ```python
|
| 75 | from minisweagent.environments.local import LocalEnvironment
|
| 76 |
|
| 77 | agent = DefaultAgent(
|
| 78 | LitellmModel(model_name=model_name),
|
| 79 | LocalEnvironment(),
|
| 80 | )
|
| 81 | ```
|
| 82 |
|
| 83 | === "Hello world with docker execution"
|
| 84 |
|
| 85 | ```python
|
| 86 | from minisweagent.environments.docker import DockerEnvironment
|
| 87 |
|
| 88 | agent = DefaultAgent(
|
| 89 | LitellmModel(model_name=model_name),
|
| 90 | DockerEnvironment(),
|
| 91 | )
|
| 92 | ```
|
| 93 |
|
| 94 | ### Agents
|
| 95 |
|
| 96 | === "Default agent"
|
| 97 |
|
| 98 | ```python
|
| 99 | from minisweagent.agents.default import DefaultAgent
|
| 100 | from minisweagent.models import get_model
|
| 101 | from minisweagent.environments.local import LocalEnvironment
|
| 102 |
|
| 103 | agent = DefaultAgent(
|
| 104 | get_model(input_model_name=model_name),
|
| 105 | LocalEnvironment(),
|
| 106 | )
|
| 107 | ```
|
| 108 |
|
| 109 | === "Human in the loop"
|
| 110 |
|
| 111 | ```python
|
| 112 | from minisweagent.agents.interactive import InteractiveAgent
|
| 113 | from minisweagent.models import get_model
|
| 114 | from minisweagent.environments.local import LocalEnvironment
|
| 115 |
|
| 116 | agent = InteractiveAgent(
|
| 117 | get_model(input_model_name=model_name),
|
| 118 | LocalEnvironment(),
|
| 119 | )
|
| 120 | ```
|
| 121 |
|
| 122 | ## Advanced
|
| 123 |
|
| 124 | ### Customizing execution
|
| 125 |
|
| 126 | An agent that uses python function for some actions:
|
| 127 |
|
| 128 |
|
| 129 | === "Subclassing the agent"
|
| 130 |
|
| 131 | ```python
|
| 132 | from minisweagent.agents.default import DefaultAgent
|
| 133 | import shlex
|
| 134 |
|
| 135 | def python_function(*args) -> dict:
|
| 136 | ...
|
| 137 | return {"output": "..."}
|
| 138 |
|
| 139 | class AgentWithPythonFunctions(DefaultAgent):
|
| 140 | def execute_actions(self, message: dict) -> list[dict]:
|
| 141 | for action in message.get("extra", {}).get("actions", []):
|
| 142 | command = action.get("command", "")
|
| 143 | if command.startswith("python_function"):
|
| 144 | args = shlex.split(command.removeprefix("python_function").strip())
|
| 145 | return self.add_messages(self.model.format_observation_messages(
|
| 146 | message, [python_function(*args)], self.get_template_vars()
|
| 147 | ))
|
| 148 | # everything else works as usual
|
| 149 | return super().execute_actions(message)
|
| 150 | ```
|
| 151 |
|
| 152 |
|
| 153 | === "Subclassing the environment"
|
| 154 |
|
| 155 | ```python
|
| 156 | from minisweagent.agents.default import DefaultAgent
|
| 157 | from minisweagent.environments.local import LocalEnvironment
|
| 158 | import shlex
|
| 159 |
|
| 160 | def python_function(*args) -> dict:
|
| 161 | ...
|
| 162 | return {"output": "..."}
|
| 163 |
|
| 164 | class EnvironmentWithPythonFunctions(LocalEnvironment):
|
| 165 | def execute(self, action: dict, cwd: str = "") -> dict:
|
| 166 | command = action.get("command", "")
|
| 167 | if command.startswith("python_function"):
|
| 168 | args = shlex.split(command.removeprefix("python_function").strip())
|
| 169 | return python_function(*args)
|
| 170 | # all other commands are executed as usual
|
| 171 | return super().execute(action, cwd)
|
| 172 |
|
| 173 | agent = DefaultAgent(
|
| 174 | LitellmModel(model_name=model_name),
|
| 175 | EnvironmentWithPythonFunctions(),
|
| 176 | )
|
| 177 | ```
|
| 178 |
|
| 179 | An agent that exits when the `submit` command is issued:
|
| 180 |
|
| 181 | === "Subclassing the agent"
|
| 182 |
|
| 183 | ```python
|
| 184 | from minisweagent.agents.default import DefaultAgent
|
| 185 | from minisweagent.exceptions import Submitted
|
| 186 |
|
| 187 | class AgentQuitsOnSubmit(DefaultAgent):
|
| 188 | def execute_actions(self, message: dict) -> list[dict]:
|
| 189 | for action in message.get("extra", {}).get("actions", []):
|
| 190 | if action.get("command", "") == "submit":
|
| 191 | # The `Submitted` exception will be caught by the agent and
|
| 192 | # the final output will be printed.
|
| 193 | raise Submitted({
|
| 194 | "role": "exit",
|
| 195 | "content": "The agent has finished its task.",
|
| 196 | "extra": {"exit_status": "Submitted", "submission": ""},
|
| 197 | })
|
| 198 | return super().execute_actions(message)
|
| 199 | ```
|
| 200 |
|
| 201 | === "Subclassing the environment"
|
| 202 |
|
| 203 | ```python
|
| 204 | from minisweagent.agents.default import DefaultAgent
|
| 205 | from minisweagent.environments.local import LocalEnvironment
|
| 206 | from minisweagent.exceptions import Submitted
|
| 207 |
|
| 208 | class EnvironmentQuitsOnSubmit(LocalEnvironment):
|
| 209 | def execute(self, action: dict, cwd: str = "") -> dict:
|
| 210 | if action.get("command", "") == "submit":
|
| 211 | raise Submitted({
|
| 212 | "role": "exit",
|
| 213 | "content": "The agent has finished its task.",
|
| 214 | "extra": {"exit_status": "Submitted", "submission": ""},
|
| 215 | })
|
| 216 | return super().execute(action, cwd)
|
| 217 |
|
| 218 | agent = DefaultAgent(
|
| 219 | LitellmModel(model_name=model_name),
|
| 220 | EnvironmentQuitsOnSubmit(),
|
| 221 | )
|
| 222 | ```
|
| 223 |
|
| 224 |
|
| 225 | An agent that validates actions before execution (also an example of how to use an extended config class):
|
| 226 |
|
| 227 | === "Subclassing the agent"
|
| 228 |
|
| 229 | ```python
|
| 230 | import re
|
| 231 | from minisweagent.agents.default import DefaultAgent, AgentConfig
|
| 232 | from minisweagent.exceptions import FormatError
|
| 233 | from pydantic import BaseModel
|
| 234 |
|
| 235 | class ValidatingAgentConfig(AgentConfig):
|
| 236 | forbidden_patterns: list[str] = [
|
| 237 | r"rm -rf /",
|
| 238 | r"sudo.*passwd",
|
| 239 | r"mkfs\.",
|
| 240 | ]
|
| 241 |
|
| 242 | class ValidatingAgent(DefaultAgent):
|
| 243 | def __init__(self, *args, **kwargs):
|
| 244 | super().__init__(*args, **kwargs, config_class=ValidatingAgentConfig)
|
| 245 |
|
| 246 | def execute_actions(self, message: dict) -> list[dict]:
|
| 247 | for action in message.get("extra", {}).get("actions", []):
|
| 248 | command = action.get("command", "")
|
| 249 | for pattern in self.config.forbidden_patterns:
|
| 250 | if re.search(pattern, command, re.IGNORECASE):
|
| 251 | raise FormatError(self.model.format_message(
|
| 252 | role="user", content="Action blocked: forbidden pattern detected"
|
| 253 | ))
|
| 254 | return super().execute_actions(message)
|
| 255 | ```
|
| 256 |
|
| 257 | === "Subclassing the environment"
|
| 258 |
|
| 259 | ```python
|
| 260 | import re
|
| 261 | from minisweagent.agents.default import DefaultAgent
|
| 262 | from minisweagent.environments.local import LocalEnvironment, LocalEnvironmentConfig
|
| 263 | from minisweagent.models.litellm_model import LitellmModel
|
| 264 |
|
| 265 | class EnvironmentWithForbiddenPatternsConfig(LocalEnvironmentConfig):
|
| 266 | forbidden_patterns: list[str] = [
|
| 267 | r"rm -rf /",
|
| 268 | r"sudo.*passwd",
|
| 269 | r"mkfs\.",
|
| 270 | ]
|
| 271 |
|
| 272 | class EnvironmentWithForbiddenPatterns(LocalEnvironment):
|
| 273 | def __init__(self, *args, **kwargs):
|
| 274 | super().__init__(*args, **kwargs, config_class=EnvironmentWithForbiddenPatternsConfig)
|
| 275 |
|
| 276 | def execute(self, action: dict, cwd: str = "") -> dict:
|
| 277 | command = action.get("command", "")
|
| 278 | for pattern in self.config.forbidden_patterns:
|
| 279 | if re.search(pattern, command, re.IGNORECASE):
|
| 280 | return {"output": "Action blocked: forbidden pattern detected", "returncode": 1}
|
| 281 | return super().execute(action, cwd)
|
| 282 |
|
| 283 | agent = DefaultAgent(
|
| 284 | LitellmModel(model_name=model_name),
|
| 285 | EnvironmentWithForbiddenPatterns(),
|
| 286 | )
|
| 287 | ```
|
| 288 |
|
| 289 | ### Running mini-swe-agent on Ray
|
| 290 |
|
| 291 | [This blog post](https://www.anyscale.com/blog/massively-parallel-agentic-simulations-with-ray)
|
| 292 | describes how to parallelize mini-swe-agent runs with Ray.
|
| 293 |
|
| 294 | {% include-markdown "_footer.md" %}
|
| 295 |
|