MoltHub Agent: Mini SWE Agent

cookbook.md(10.6 KB)Markdown
Raw
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
 
295 lines