mini-swe-agent

1. Panorama

Mini-SWE-Agent: A Minimalist SWE Scaffold

  • Mini-SWE-Agent is a minimalist, bash-centric software engineering agent scaffold that maintains core capabilities like code navigation, testing, and iterative refinement.
  • It operates as a single-agent loop executing one thought and one bash command per cycle, supporting both repository repair and embodied controller generation.
  • Empirical studies show MSWEA achieves competitive resolution rates with strong models while facing challenges such as context degradation and token bloat.

The main structure of MSWEA is like this:

The file structure is :

1
2
3
4
5
6
7
8
src/minisweagent/
├── __init__.py # protocols / interfaces ...
├── agents/ # harness parts
├── environments/ # action execution environments
├── models/ # LLM interface
├── config/ # yaml files
├── run/ # entrance scripts
└── utils/ # log, serialize

2. __init__.py

__init__.py mainly defines 4 files:

version, Model Protocol, Environment Protocol and Agent Protocol.

2.1 Version

Current version is 2.4.6 (2026-09-09).

1
__version__ = "2.4.6"

2.2 Model Protocol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Model(Protocol):
"""Protocol for language models."""

config: Any

def query(self, messages: list[dict[str, str]], **kwargs) -> dict: ...

def format_message(self, **kwargs) -> dict: ...

def format_observation_messages(
self, message: dict, outputs: list[dict], template_vars: dict | None = None
) -> list[dict]: ...

def get_template_vars(self, **kwargs) -> dict[str, Any]: ...

def serialize(self) -> dict: ...

This part defines a LLM protocol.

2.2.1 query

  • Function Name:

    query

  • Params:

    self

    messages: list[dict[str, str]]

    **kwargs

  • Return:

    dict

  • Function Description:

    Send the conversation history to the LLM, receive the response, parse the bash action to be executed, and return it wrapped in a dict.

  • e.g

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    message = self.model.query(self.messages)

    # self.message example
    # [
    # {"role": "system", "content": "You are a helpful assistant..."},
    # {"role": "user", "content": "Please solve this issue:repair add function"},
    # ]

    # the returned message like this:
    {
    "role": "assistant",
    "content": "I'll first look at the repository structure.",
    "extra": {
    "actions": [{"command": "ls -la", "tool_call_id": "call_abc123"}], # parsed bash action
    "cost": 0.0123, # cost of this call(dollar)
    "timestamp": 1730000000.0,
    },
    }

2.2.2 format_message

  • Function Name:

    format_message

  • Params:

    self

    **kwargs

  • Return:

    dict

  • Function Description:

    Assembles the input fields into a standard message; the default implementation mainly expands multimodal content.

  • e.g

    1
    2
    3
    4
    5
    6
    7
    8
    # assemble system prompt:
    self.model.format_message(role="system", content="You are a helpful assistant...")
    # return:
    {"role": "system", "content": "You are a helpful assistant..."}

    # assemble user message:
    self.model.format_message(role="user", content="Please solve this issue: ...")
    {"role": "user", "content": "Please solve this issue: ..."}

2.2.3 format_observation_messages

  • Function Name:

    format_observation_messages

  • Params:

    self

    message: dict

    outputs: list[dict]

    template_vars: dict | None = None

  • Return:

    list[dict]

  • Function Description:

    Render the command execution result into an observation message, append it back to the conversation history, and let the model see what the previous step produced.

  • e.g

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # assume the last command is `ls -la`
    outputs = [{"output": "file1.py\nfile2.py\n", "returncode": 0, "exception_info": ""}]

    # agent calls:
    self.model.format_observation_messages(message, outputs, self.get_template_vars())

    # return:
    [{
    "role": "tool",
    "tool_call_id": "call_abc123",
    "content": "<returncode>0</returncode>\n<output>\nfile1.py\nfile2.py\n</output>",
    "extra": {"raw_output": "file1.py\nfile2.py\n", "returncode": 0, "timestamp": 1730000001.0},
    }]

2.2.4 get_template_vars

  • Function Name:

    get_template_vars

  • Params:

    self

    **kwargs

  • Return:

    dict[str, Any]

  • Function Description:

    Provide the variables needed to render the Jinja2 template (e.g., model name, model_kwargs, etc.).

    • e.g

      1
      2
      3
      4
      5
      6
      7
      8
      9
      def get_template_vars(self, **kwargs):
      return self.config.model_dump()

      # return likes:
      {
      "model_name": "anthropic/claude-sonnet-4-5-20250929",
      "model_kwargs": {"drop_params": True},
      ...
      }

      These variables will be used to render system/instance template by Agent

2.2.5 serialize

  • Function Name:

    serialize

  • Params:

    self

  • Return:

    dict

  • Function Description:

    Serialize the model config/state for writing to the trajectory file at the end, recording which model was used.

  • e.g

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # when agent archive, it merges model information into final data
    recursive_merge(agent_data, self.model.serialize(), self.env.serialize(), *extra_dicts)

    # LitellmModel.serialize() return:
    {
    "info": {
    "config": {
    "model": {"model_name": "anthropic/claude-sonnet-4-5-20250929", ...},
    "model_type": "minisweagent.models.litellm_model.LitellmModel",
    }
    }
    }

    # the information will be written into last_mini_run.traj.json:
    # {
    # "info": { "model_stats": {...}, "config": {"agent": {...}, "model": {...}, "environment": {...}} },
    # "messages": [ ...dialog history... ]
    # }

2.3 Environment Protocol

2.3.1 execute

  • Function Name:

    execute

  • Params:

    self

    action: dict

    cwd: str = “”

  • Return:

    dict[str, Any]

  • Description:

    Actually execute a bash command and return a dict bundling stdout, the exit code, and whether it errored. There’s also a hidden key behavior: if the first line of the output is “COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT”, it raises a Submitted exception to signal task completion.

  • e.g

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # e.g agent parses action from response of LLM:
    action = {"command": "ls -la", "tool_call_id": "call_abc123"}

    # agent calls:
    outputs = [self.env.execute(action) for action in actions]

    # the Agent calls subprocess to run the command actually,
    # the return is:
    {
    "output": "total 8\ndrwxr-xr-x ...\nfile1.py\nfile2.py\n",
    "returncode": 0, # 0 == success
    "exception_info": "", # empty == no error raised
    }

    # if command fails:
    # 如果命令失败了(比如文件不存在):
    {
    "output": "ls: cannot access 'nope': No such file or directory\n",
    "returncode": 2, # not-0 == failure
    "exception_info": "",
    }
  • If task finished, it can be detected:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # when task finished
    echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT

    # raise submitted
    raise Submitted({
    "role": "exit",
    "content": "",
    "extra": {"exit_status": "Submitted", "submission": ""},
    })

2.3.2 get_template_vars

  • Function Name:

    get_template_vars

  • Params:

    self

    **kwargs

  • Return:

    dict[str, Any]

  • Description:

    Collect environment-related template variables (working directory config, OS info, environment variables, etc.) for the agent to fill in when rendering the system/instance prompts.

  • e.g.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # Impelemtation in LocalEnvironment
    def get_template_vars(self, **kwargs):
    return recursive_merge(self.config.model_dump(), platform.uname()._asdict(), os.environ, kwargs)

    # it returns three types information
    {
    # ① Env Config
    "cwd": "", "env": {...}, "timeout": 30,
    # ② OS information(platform.uname())
    "system": "Linux", "release": "6.8.0-...", "version": "...", "machine": "x86_64",
    # ③ all Environment Variables(os.environ)
    "PATH": "/usr/bin:...", "HOME": "/root", ...
    }

2.3.1 serialize

  • Function Name:

    serialize

  • Params:

    self

  • Return:

    dict

  • Description:

    Serialize the environment config/type into a dict for writing to the trajectory file at the end, recording which environment it ran in.

  • e.g.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # when agent archives, the information will be merged.
    recursive_merge(agent_data, self.model.serialize(), self.env.serialize(), *extra_dicts)

    # return of LocalEnvironment.serialize()
    {
    "info": {
    "config": {
    "environment": {"cwd": "", "env": {}, "timeout": 30},
    "environment_type": "minisweagent.environments.local.LocalEnvironment",
    }
    }
    }

2.3.1

  • Function Name:

  • Params:

  • Return:

  • Description:

  • e.g.

本文链接:https://wangyier.top/mini-swe-agent/

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 The Great Library