Skip to content

Cookbook

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 first

Development setup

Make sure to follow the dev setup instructions in quickstart.md.

We provide several different entry points to the agent, for example hello world, or the default when calling mini.

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 (e.g., simplest example, with human in the loop)
  2. How should actions be executed? Pick an environment class (e.g., local, or docker)
  3. How is the LM queried? Pick a model class (e.g., litellm)
  4. How to invoke the agent? Bind them all together in a run script, possibly reading from a config (e.g., hello world, or mini entry point)

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 for the most basic example.

Mix & match

Models

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)
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

from minisweagent.environments.local import LocalEnvironment

agent = DefaultAgent(
    LitellmModel(model_name=model_name),
    LocalEnvironment(),
)
from minisweagent.environments.docker import DockerEnvironment

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

Agents

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(),
)
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:

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)
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:

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)
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):

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)
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 describes how to parallelize mini-swe-agent runs with Ray.