mini-swe-agent 1.4.2__py3-none-any.whl → 1.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mini-swe-agent
3
- Version: 1.4.2
3
+ Version: 1.5.1
4
4
  Summary: Nano SWE Agent - A simple AI software engineering agent
5
5
  Author-email: Kilian Lieret <kilian.lieret@posteo.de>, "Carlos E. Jimenez" <carlosej@princeton.edu>
6
6
  License: MIT License
@@ -82,7 +82,7 @@ We now ask: **What if SWE-agent was 100x smaller, and still worked nearly as wel
82
82
 
83
83
  `mini` is for
84
84
 
85
- - **Researchers** who want to **benchmark, fine-tune or RL** without assumptions, bloat, or surprises
85
+ - **Researchers** who want to **[benchmark](https://swe-bench.com), [fine-tune](https://swesmith.com/) or RL** without assumptions, bloat, or surprises
86
86
  - **Developers** who like their tools like their scripts: **short, sharp, and readable**
87
87
  - **Engineers** who want something **trivial to sandbox & to deploy anywhere**
88
88
 
@@ -90,7 +90,7 @@ Here's some details:
90
90
 
91
91
  - **Minimal**: Just [100 lines of python](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/agents/default.py) (+100 total for [env](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/environments/local.py),
92
92
  [model](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/models/litellm_model.py), [script](https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/run/hello_world.py)) — no fancy dependencies!
93
- - **Powerful:** Resolves 65% of GitHub issues in the [SWE-bench verified benchmark](https://www.swebench.com/) (with Claude Sonnet 4).
93
+ - **Powerful:** Resolves 65% of GitHub issues in the [SWE-bench verified benchmark](https://www.swebench.com/) ([leaderboard](https://swe-bench.com/)).
94
94
  - **Convenient:** Comes with UIs that turn this into your daily dev swiss army knife!
95
95
  - **Deployable:** In addition to local envs, you can use **docker**, **podman**, **singularity**, **apptainer**, and more
96
96
  - **Tested:** [![Codecov](https://img.shields.io/codecov/c/github/swe-agent/mini-swe-agent?style=flat-square)](https://codecov.io/gh/SWE-agent/mini-swe-agent)
@@ -116,6 +116,7 @@ In fact, mini-SWE-agent
116
116
 
117
117
  This makes it perfect as a baseline system and for a system that puts the language model (rather than
118
118
  the agent scaffold) in the middle of our attention.
119
+ You can see the result on the [SWE-bench (bash only)](https://www.swebench.com/) leaderboard, that evaluates the performance of different LMs with `mini`.
119
120
 
120
121
  </details>
121
122
 
@@ -1,11 +1,11 @@
1
- mini_swe_agent-1.4.2.dist-info/licenses/LICENSE.md,sha256=D3luWPkdHAe7LBsdD4vzqDAXw6Xewb3G-uczss0uh1s,1094
2
- minisweagent/__init__.py,sha256=oYWkIRVhPyOg1ZdA0e-yH_3gk4L19SUUb68qsCNQsPo,1787
1
+ mini_swe_agent-1.5.1.dist-info/licenses/LICENSE.md,sha256=D3luWPkdHAe7LBsdD4vzqDAXw6Xewb3G-uczss0uh1s,1094
2
+ minisweagent/__init__.py,sha256=_z5QkBGjq4zOO2GWbaJCtjSI02UC6JUb2a_dUGaYlY0,1787
3
3
  minisweagent/__main__.py,sha256=FIyAOiw--c3FQ2g240FOM1FdL0lk_PxSpixu0pQ7WFo,194
4
4
  minisweagent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  minisweagent/agents/__init__.py,sha256=cpjJLzg1IGxLM-tZpoMJV9S33ye13XtdBO0x7DU_Lrk,48
6
- minisweagent/agents/default.py,sha256=9LxgX3KWHFGkGE4FjGOZwK5oA8ykzg9KgmpgyqlEuoo,5460
6
+ minisweagent/agents/default.py,sha256=bqLMtEptn61zc_ptAIQkz_2fMI8hBoVpydVA84mPH8I,5471
7
7
  minisweagent/agents/interactive.py,sha256=7HW2cffaV5f66DIjxvtIbL8mo_S5aZSwgNLSmHp6VC0,7450
8
- minisweagent/agents/interactive_textual.py,sha256=BgHOeTCDmHGph5oXEYDM5bqSlOuDrEE2X2ukN4m4T4E,16258
8
+ minisweagent/agents/interactive_textual.py,sha256=Ef2GTH2_9ujD95ukVf-hb7X6FCRVgvIdlJZvPvCAd-E,17629
9
9
  minisweagent/config/README.md,sha256=tPruhnQDhZ8ugc1FNPKk9tVMRltmmIjdYgvHCmN-3Hs,354
10
10
  minisweagent/config/__init__.py,sha256=UfORdQID1Ek_dduZlybUsIKJjihImkSqNU5tIjpw0hk,694
11
11
  minisweagent/config/default.yaml,sha256=AGhcIq6X6n5Fs71ufO3B6CtZ4PS877tCxkPkrWR5Ylg,4497
@@ -30,17 +30,17 @@ minisweagent/run/__init__.py,sha256=WIoYgHVl7iZF2YncrfV3IttupG6P5KogroKHKECka3A,
30
30
  minisweagent/run/github_issue.py,sha256=GWOkGM09jOYV93p6xIM_kKWmC1yP_d5lprafWlqoBN0,2748
31
31
  minisweagent/run/hello_world.py,sha256=erLnEwNmPFLxq3-8zyv66Vy1kIqMqQf97vISX7LrQXg,959
32
32
  minisweagent/run/inspector.py,sha256=QnY3oYzm-yq3w9Jzs112Lco2Rg84vSocAWrQRVz_1lc,7127
33
- minisweagent/run/mini.py,sha256=Q-B5LDFQtEoqxMC3cHpbQr8IW1qNpiTh_eaQpYHz954,4589
33
+ minisweagent/run/mini.py,sha256=yeVYaaQrYfAW5gzPsunxqB73CTnwugkQ1qPn2-Os-GM,4849
34
34
  minisweagent/run/mini_extra.py,sha256=ecA1PnTWElpO60G9RktvVLtUOf3bZ_ESmnSttS6izhQ,1465
35
35
  minisweagent/run/extra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- minisweagent/run/extra/config.py,sha256=paMHfplhKsqNmzhCmozxhXWHvBzBCUlwUWD8N7ytCPc,3277
36
+ minisweagent/run/extra/config.py,sha256=ezUu8n2-h79cfphWXv-j9LQXfxzkxrF2aPlh7mObF7k,3545
37
37
  minisweagent/run/extra/swebench.py,sha256=m5_PZI4ojkUyCxzkkMtel_vlnYmjziWrXu73yHoZGFs,9688
38
38
  minisweagent/run/extra/swebench_single.py,sha256=L3Kk4G65o3MCPLMEwGNIs77-AFf6Lfc8o1oxrbN-ZWM,1991
39
39
  minisweagent/run/extra/utils/batch_progress.py,sha256=u__khJ-fipZLxTJu43LamGAtPUCqEZYEi8J7SfH7X6A,6211
40
40
  minisweagent/run/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- minisweagent/run/utils/save.py,sha256=q7omf7zYHg73k8-Iyp9w5YVSYvDAacRrh4X9L_4VhNM,942
42
- mini_swe_agent-1.4.2.dist-info/METADATA,sha256=j1Pbp3dIQR4QarSo7Srmbm_ePbGfVQFZWPkn7i7w90c,13462
43
- mini_swe_agent-1.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
- mini_swe_agent-1.4.2.dist-info/entry_points.txt,sha256=d1_yRbTaGjs1UXHa6JQK0sKDGBIVGm8oeW0k2kfbJgQ,182
45
- mini_swe_agent-1.4.2.dist-info/top_level.txt,sha256=zKF4t8bFpV87fdVABZt2Da-vnb4Vkh_CxkwQx5YT4Ew,13
46
- mini_swe_agent-1.4.2.dist-info/RECORD,,
41
+ minisweagent/run/utils/save.py,sha256=yI_hSU-GOaB7j8YeHBCc7Fhl4js9AyO9N5SC6p-nnu8,1606
42
+ mini_swe_agent-1.5.1.dist-info/METADATA,sha256=vhNmjVsIhc6H04u8X1zDTVkOdl9jd4CtCnG889AW-MU,13684
43
+ mini_swe_agent-1.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
+ mini_swe_agent-1.5.1.dist-info/entry_points.txt,sha256=d1_yRbTaGjs1UXHa6JQK0sKDGBIVGm8oeW0k2kfbJgQ,182
45
+ mini_swe_agent-1.5.1.dist-info/top_level.txt,sha256=zKF4t8bFpV87fdVABZt2Da-vnb4Vkh_CxkwQx5YT4Ew,13
46
+ mini_swe_agent-1.5.1.dist-info/RECORD,,
minisweagent/__init__.py CHANGED
@@ -8,7 +8,7 @@ This file provides:
8
8
  unless you want the static type checking.
9
9
  """
10
10
 
11
- __version__ = "1.4.2"
11
+ __version__ = "1.5.1"
12
12
 
13
13
  import os
14
14
  from pathlib import Path
@@ -66,8 +66,8 @@ class DefaultAgent:
66
66
  cs = asdict(self.config) | asdict(self.env.config) | asdict(self.model.config) | platform.uname()._asdict()
67
67
  return Template(template).render(**kwargs, **cs, **os.environ)
68
68
 
69
- def add_message(self, role: str, content: str):
70
- self.messages.append({"role": role, "content": content})
69
+ def add_message(self, role: str, content: str, **kwargs):
70
+ self.messages.append({"role": role, "content": content, **kwargs})
71
71
 
72
72
  def run(self, task: str) -> tuple[str, str]:
73
73
  """Run step() until agent is finished. Return exit status & message"""
@@ -92,7 +92,7 @@ class DefaultAgent:
92
92
  if 0 < self.config.step_limit <= self.model.n_calls or 0 < self.config.cost_limit <= self.model.cost:
93
93
  raise LimitsExceeded()
94
94
  response = self.model.query(self.messages)
95
- self.add_message("assistant", response["content"])
95
+ self.add_message("assistant", **response)
96
96
  return response
97
97
 
98
98
  def get_observation(self, response: dict) -> dict:
@@ -9,17 +9,19 @@ import re
9
9
  import threading
10
10
  import time
11
11
  import traceback
12
+ from collections.abc import Iterable
12
13
  from dataclasses import dataclass, field
13
14
  from pathlib import Path
14
15
  from typing import Literal
15
16
 
16
17
  from rich.spinner import Spinner
17
18
  from rich.text import Text
18
- from textual.app import App, ComposeResult
19
+ from textual.app import App, ComposeResult, SystemCommand
19
20
  from textual.binding import Binding
20
21
  from textual.containers import Container, Vertical, VerticalScroll
21
22
  from textual.css.query import NoMatches
22
23
  from textual.events import Key
24
+ from textual.screen import Screen
23
25
  from textual.widgets import Footer, Header, Input, Static, TextArea
24
26
 
25
27
  from minisweagent.agents.default import AgentConfig, DefaultAgent, NonTerminatingException, Submitted
@@ -62,11 +64,12 @@ class TextualAgent(DefaultAgent):
62
64
  exit_status, result = super().run(task)
63
65
  except Exception as e:
64
66
  result = str(e)
67
+ self.app.call_from_thread(self.app.action_quit)
65
68
  print(traceback.format_exc())
66
- self.app.call_from_thread(self.app.on_agent_finished, "ERROR", result)
67
69
  return "ERROR", result
68
70
  else:
69
71
  self.app.call_from_thread(self.app.on_agent_finished, exit_status, result)
72
+ self.app.call_from_thread(self.app.action_quit)
70
73
  return exit_status, result
71
74
 
72
75
  def execute_action(self, action: dict) -> dict:
@@ -238,16 +241,22 @@ class SmartInputContainer(Container):
238
241
 
239
242
  class AgentApp(App):
240
243
  BINDINGS = [
241
- Binding("right,l", "next_step", "Step++"),
242
- Binding("left,h", "previous_step", "Step--"),
243
- Binding("0", "first_step", "Step=0"),
244
- Binding("$", "last_step", "Step=-1"),
245
- Binding("j,down", "scroll_down", "Scroll down"),
246
- Binding("k,up", "scroll_up", "Scroll up"),
247
- Binding("q", "quit", "Quit"),
248
- Binding("y", "yolo", "Switch to YOLO Mode"),
249
- Binding("c", "confirm", "Switch to Confirm Mode"),
250
- Binding("u", "human", "Switch to Human Mode"),
244
+ Binding("right,l", "next_step", "Step++", tooltip="Show next step of the agent"),
245
+ Binding("left,h", "previous_step", "Step--", tooltip="Show previous step of the agent"),
246
+ Binding("0", "first_step", "Step=0", tooltip="Show first step of the agent", show=False),
247
+ Binding("$", "last_step", "Step=-1", tooltip="Show last step of the agent", show=False),
248
+ Binding("j,down", "scroll_down", "Scroll down", show=False),
249
+ Binding("k,up", "scroll_up", "Scroll up", show=False),
250
+ Binding("q,ctrl+q", "quit", "Quit", tooltip="Quit the agent"),
251
+ Binding("y,ctrl+y", "yolo", "YOLO mode", tooltip="Switch to YOLO Mode (LM actions will execute immediately)"),
252
+ Binding(
253
+ "c",
254
+ "confirm",
255
+ "CONFIRM mode",
256
+ tooltip="Switch to Confirm Mode (LM proposes commands and you confirm/reject them)",
257
+ ),
258
+ Binding("u,ctrl+u", "human", "HUMAN mode", tooltip="Switch to Human Mode (you can now type commands directly)"),
259
+ Binding("f1,question_mark", "toggle_help_panel", "Help", tooltip="Show help"),
251
260
  ]
252
261
 
253
262
  def __init__(self, model, env, task: str, **kwargs):
@@ -367,6 +376,15 @@ class AgentApp(App):
367
376
  except NoMatches: # might be called when shutting down
368
377
  pass
369
378
 
379
+ # --- Other textual overrides ---
380
+
381
+ def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]:
382
+ # Add to palette
383
+ yield from super().get_system_commands(screen)
384
+ for binding in self.BINDINGS:
385
+ description = f"{binding.description} (shortcut {' OR '.join(binding.key.split(','))})" # type: ignore[attr-defined]
386
+ yield SystemCommand(description, binding.tooltip, binding.action) # type: ignore[attr-defined]
387
+
370
388
  # --- Textual bindings ---
371
389
 
372
390
  def action_yolo(self):
@@ -404,3 +422,9 @@ class AgentApp(App):
404
422
 
405
423
  def action_scroll_up(self) -> None:
406
424
  self._vscroll.scroll_to(y=self._vscroll.scroll_target_y - 15)
425
+
426
+ def action_toggle_help_panel(self) -> None:
427
+ if self.query("HelpPanel"):
428
+ self.action_hide_help_panel()
429
+ else:
430
+ self.action_show_help_panel()
@@ -12,7 +12,7 @@ from dotenv import set_key, unset_key
12
12
  from prompt_toolkit import prompt
13
13
  from rich.console import Console
14
14
  from rich.rule import Rule
15
- from typer import Option, Typer
15
+ from typer import Argument, Typer
16
16
 
17
17
  from minisweagent import global_config_file
18
18
 
@@ -25,9 +25,7 @@ app = Typer(
25
25
  console = Console(highlight=False)
26
26
 
27
27
 
28
- _SETUP_HELP = """Welcome to Mini!
29
-
30
- To get started, we need to set up your global config file.
28
+ _SETUP_HELP = """To get started, we need to set up your global config file.
31
29
 
32
30
  You can edit it manually or use the [bold green]mini-extra config set[/bold green] or [bold green]mini-extra config edit[/bold green] commands.
33
31
 
@@ -39,6 +37,8 @@ Here's a few popular models and the required API keys:
39
37
  [bold green]o3[/bold green] ([bold green]OPENAI_API_KEY[/bold green])
40
38
 
41
39
  [bold yellow]You can leave any setting blank to skip it.[/bold yellow]
40
+
41
+ More information at https://mini-swe-agent.com/latest/quickstart/
42
42
  """
43
43
 
44
44
 
@@ -79,16 +79,22 @@ def setup():
79
79
 
80
80
  @app.command()
81
81
  def set(
82
- key: str = Option(..., help="The key to set", prompt=True),
83
- value: str = Option(..., help="The value to set", prompt=True),
82
+ key: str | None = Argument(None, help="The key to set"),
83
+ value: str | None = Argument(None, help="The value to set"),
84
84
  ):
85
85
  """Set a key in the global config file."""
86
+ if key is None:
87
+ key = prompt("Enter the key to set: ")
88
+ if value is None:
89
+ value = prompt(f"Enter the value for {key}: ")
86
90
  set_key(global_config_file, key, value)
87
91
 
88
92
 
89
93
  @app.command()
90
- def unset(key: str = Option(..., help="The key to unset")):
94
+ def unset(key: str | None = Argument(None, help="The key to unset")):
91
95
  """Unset a key in the global config file."""
96
+ if key is None:
97
+ key = prompt("Enter the key to unset: ")
92
98
  unset_key(global_config_file, key)
93
99
 
94
100
 
minisweagent/run/mini.py CHANGED
@@ -73,7 +73,12 @@ def run_textual(model: Model, env: Environment, agent_config: dict, task: str, o
73
73
 
74
74
  @app.command(help=_HELP_TEXT)
75
75
  def main(
76
- visual: bool = typer.Option(False, "-v", "--visual", help="Use visual (pager-style) UI (Textual)"),
76
+ visual: bool = typer.Option(
77
+ False,
78
+ "-v",
79
+ "--visual",
80
+ help="Toggle (pager-style) UI (Textual) depending on the MSWEA_VISUAL_MODE_DEFAULT environment setting",
81
+ ),
77
82
  model_name: str | None = typer.Option(
78
83
  None,
79
84
  "-m",
@@ -113,7 +118,8 @@ def main(
113
118
  model = get_model(model_name, config.get("model", {}))
114
119
  env = LocalEnvironment(**config.get("env", {}))
115
120
 
116
- if visual:
121
+ # Both visual flag and the MSWEA_VISUAL_MODE_DEFAULT flip the mode, so it's essentially a XOR
122
+ if visual == (os.getenv("MSWEA_VISUAL_MODE_DEFAULT", "false") == "false"):
117
123
  return run_textual(model, env, config["agent"], task, output) # type: ignore[arg-type]
118
124
  else:
119
125
  return run_interactive(model, env, config["agent"], task, output) # type: ignore[arg-type]
@@ -1,18 +1,31 @@
1
1
  import json
2
2
  from pathlib import Path
3
3
 
4
- from minisweagent import Agent
4
+ from minisweagent import Agent, __version__
5
5
 
6
6
 
7
7
  def save_traj(
8
8
  agent: Agent | None,
9
9
  path: Path,
10
10
  *,
11
+ print_path: bool = True,
11
12
  exit_status: str | None = None,
12
13
  result: str | None = None,
13
14
  extra_info: dict | None = None,
14
15
  **kwargs,
15
16
  ):
17
+ """Save the trajectory of the agent to a file.
18
+
19
+ Args:
20
+ agent: The agent to save the trajectory of.
21
+ path: The path to save the trajectory to.
22
+ print_path: Whether to print confirmation of path to the terminal.
23
+ exit_status: The exit status of the agent.
24
+ result: The result/submission of the agent.
25
+ extra_info: Extra information to save (will be merged into the info dict).
26
+ **kwargs: Additional information to save (will be merged into top level)
27
+
28
+ """
16
29
  data = {
17
30
  "info": {
18
31
  "exit_status": exit_status,
@@ -21,6 +34,7 @@ def save_traj(
21
34
  "instance_cost": 0.0,
22
35
  "api_calls": 0,
23
36
  },
37
+ "mini_version": __version__,
24
38
  },
25
39
  "messages": [],
26
40
  "trajectory_format": "mini-swe-agent-1",
@@ -34,3 +48,5 @@ def save_traj(
34
48
 
35
49
  path.parent.mkdir(parents=True, exist_ok=True)
36
50
  path.write_text(json.dumps(data, indent=2))
51
+ if print_path:
52
+ print(f"Saved trajectory to '{path}'")