mini-swe-agent 1.17.1__py3-none-any.whl → 1.17.3__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.17.1
3
+ Version: 1.17.3
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
@@ -86,21 +86,21 @@ In 2024, [SWE-bench](https://github.com/swe-bench/SWE-bench) & [SWE-agent](https
86
86
 
87
87
  We now ask: **What if SWE-agent was 100x smaller, and still worked nearly as well?**
88
88
 
89
- `mini` is for
89
+ The `mini` agent is for
90
90
 
91
91
  - **Researchers** who want to **[benchmark](https://swe-bench.com), [fine-tune](https://swesmith.com/) or RL** without assumptions, bloat, or surprises
92
- - **Developers** who like their tools like their scripts: **short, sharp, and readable**
92
+ - **Developers** who like to **own, understand, and modify** their tools
93
93
  - **Engineers** who want something **trivial to sandbox & to deploy anywhere**
94
94
 
95
95
  Here's some details:
96
96
 
97
97
  - **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),
98
98
  [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!
99
- - **Powerful:** Resolves >74% of GitHub issues in the [SWE-bench verified benchmark](https://www.swebench.com/) ([leaderboard](https://swe-bench.com/)).
100
- - **Convenient:** Comes with UIs that turn this into your daily dev swiss army knife!
99
+ - **Performant:** Scores >74% on the [SWE-bench verified benchmark](https://www.swebench.com/) benchmark; starts faster than Claude Code
101
100
  - **Deployable:** In addition to local envs, you can use **docker**, **podman**, **singularity**, **apptainer**, and more
102
- - **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)
103
101
  - **Cutting edge:** Built by the Princeton & Stanford team behind [SWE-bench](https://swebench.com) and [SWE-agent](https://swe-agent.com).
102
+ - **Widely adopted:** In use by Meta, NVIDIA, Essential AI, Anyscale, and others
103
+ - **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)
104
104
 
105
105
  <details>
106
106
 
@@ -108,7 +108,7 @@ Here's some details:
108
108
 
109
109
  [SWE-agent](https://swe-agent.com/latest/) jump-started the development of AI agents in 2024. Back then, we placed a lot of emphasis on tools and special interfaces for the agent.
110
110
  However, one year later, as LMs have become more capable, a lot of this is not needed at all to build a useful agent!
111
- In fact, mini-SWE-agent
111
+ In fact, the `mini` agent
112
112
 
113
113
  - **Does not have any tools other than bash** — it doesn't even use the tool-calling interface of the LMs.
114
114
  This means that you can run it with literally any model. When running in sandboxed environments you also don't need to take care
@@ -131,7 +131,7 @@ You can see the result on the [SWE-bench (bash only)](https://www.swebench.com/)
131
131
 
132
132
  Some agents are overfitted research artifacts. Others are UI-heavy frontend monsters.
133
133
 
134
- `mini` wants to be a hackable tool, not a black box.
134
+ The `mini` agent wants to be a hackable tool, not a black box.
135
135
 
136
136
  - **Simple** enough to understand at a glance
137
137
  - **Convenient** enough to use in daily workflows
@@ -1,9 +1,9 @@
1
- mini_swe_agent-1.17.1.dist-info/licenses/LICENSE.md,sha256=D3luWPkdHAe7LBsdD4vzqDAXw6Xewb3G-uczss0uh1s,1094
2
- minisweagent/__init__.py,sha256=92sn1eUs4LJ0jSNW-ZAZjAIagd1Fbts0js5hTfuw-5E,2016
1
+ mini_swe_agent-1.17.3.dist-info/licenses/LICENSE.md,sha256=D3luWPkdHAe7LBsdD4vzqDAXw6Xewb3G-uczss0uh1s,1094
2
+ minisweagent/__init__.py,sha256=eWlfblsvb5AJPNFfCN2buiqwmeZ0h_Ssk7tzniLhn_8,2016
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=6XQEf4bawQL-J2r4ClsDsO_1uQ-VM7WrW3hGaHxKcQE,5657
6
+ minisweagent/agents/default.py,sha256=NLHCTR8CrM0-1aNXT0zZZ044RBYQWACfNzKwAg69IWM,6054
7
7
  minisweagent/agents/interactive.py,sha256=NBeNamRuqww9ZRhOg1q8xPO9ziUw2gpAVV6hCPbpBxU,7470
8
8
  minisweagent/agents/interactive_textual.py,sha256=yUDMkuvhhnZAP8LtiBWmt5J5WzfWBeR0zNlJbdbEGa0,18153
9
9
  minisweagent/config/README.md,sha256=ZGH5KbFHpkwYOwoZgwP1dHOikuvU11dIG_TqyI73dik,355
@@ -25,12 +25,12 @@ minisweagent/environments/extra/bubblewrap.py,sha256=G12Dm63N30qByfLb1SKNsI4G4gL
25
25
  minisweagent/environments/extra/swerex_docker.py,sha256=WPYbohT_vqTHkde9cxpbV6chLXCpLl0PDAcgMbZsV0M,1707
26
26
  minisweagent/models/__init__.py,sha256=RGJgMPeF8W2Ix8_xwvHjjDCD9I6ygirz4v8Ps1KG6dI,4435
27
27
  minisweagent/models/anthropic.py,sha256=4p-LxQ_RYQUX1rBsffAj3T1bBb2uMRhA4IyKfDcMpgo,1517
28
- minisweagent/models/litellm_model.py,sha256=A_M5PEBhWa2NmANYCF1MGw4tNwA89HLdeZw_ay3Xugw,4310
29
- minisweagent/models/litellm_response_api_model.py,sha256=FF-Xab6xBvkxh_E6VoMx-Km1owRpHrkSIfgXZ31hCsU,2946
30
- minisweagent/models/openrouter_model.py,sha256=dsVl8pnZ9M6nZ5DpLy69v1bizMR73mixXdVZVNzvknc,4712
31
- minisweagent/models/portkey_model.py,sha256=6HMOsmHd6Q6WdLUDa_1XFCrU0BaCUP5RqI3h6L8AxJQ,7223
32
- minisweagent/models/portkey_response_api_model.py,sha256=muHiiRpm7nXP1jylZovE4Ttr_JwFt1b9-YZgRCthTbk,2938
33
- minisweagent/models/requesty_model.py,sha256=Dqr0cLNSstj3VrzYhf-Sqsju8OvJrRPK2mctajgRnNs,3781
28
+ minisweagent/models/litellm_model.py,sha256=0HBnb53GdeqSAwNcJuu8hXrd3XqqIm4BHS1WkwK3ZGE,4394
29
+ minisweagent/models/litellm_response_api_model.py,sha256=Niq4HepQm_dlCkGdXsg9_7zNNRxJlnwWK-JJE0lP9Qg,3150
30
+ minisweagent/models/openrouter_model.py,sha256=YgML8_p9gHMjoBcxszmgyrIr5DLRX2vZiBwHC47N5mg,4796
31
+ minisweagent/models/portkey_model.py,sha256=_eK8maRm2kwombWYbYtH7MXj8rhd18ZE7tGer2YXvws,7307
32
+ minisweagent/models/portkey_response_api_model.py,sha256=JcODu40mYsqWnwWntTSjRUMTzifLUZZpFL5sF3FUk3s,2960
33
+ minisweagent/models/requesty_model.py,sha256=t4iQD7mH61UlldQmydcGYmoj-dAG8K_2347DBjl-4vo,3865
34
34
  minisweagent/models/test_models.py,sha256=ItCA6ddntzkYA7dzSuUEaLMV-AE8TBuXBFP8CzpiO3U,1351
35
35
  minisweagent/models/extra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  minisweagent/models/extra/roulette.py,sha256=idteU0pGvmmipNr0s-42GAbVkmKE20hY2LTFxbkAgoI,2048
@@ -49,13 +49,13 @@ minisweagent/run/extra/config.py,sha256=KDMwg6eQCxbwI6P1phosCwaLQhJQXB4ti65M_Hox
49
49
  minisweagent/run/extra/swebench.py,sha256=sO3LnjLXdU6Zbo409YhxVdizU8LaQcJUdcD8Tj6saMw,11741
50
50
  minisweagent/run/extra/swebench_single.py,sha256=KmoUkD6UQ1P0MY_73-OtYuQAsNPmOLlZIZSYKZGs5MQ,3699
51
51
  minisweagent/run/extra/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- minisweagent/run/extra/utils/batch_progress.py,sha256=xhJ7FmsaTBGz-yh8pzYl4yMoUGjn7GA24eYrP-nHj60,6804
52
+ minisweagent/run/extra/utils/batch_progress.py,sha256=URgnm5MpUA6liESNFqDIbzELM869PbXro7jKzvdbiv0,6804
53
53
  minisweagent/run/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  minisweagent/run/utils/save.py,sha256=bokvblZ1SaIvCXimkRQqgvERKmVM0jn8SF7UoHBeerQ,2546
55
55
  minisweagent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  minisweagent/utils/log.py,sha256=ruDMNKMrVC9NPvCeHwO3QYz5jsVNUGQB2dRAEAPAWp8,996
57
- mini_swe_agent-1.17.1.dist-info/METADATA,sha256=pDciZvio2ToJP8llJbDE2qP1PaeeaP1Inp8MchsKW4g,14851
58
- mini_swe_agent-1.17.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
59
- mini_swe_agent-1.17.1.dist-info/entry_points.txt,sha256=d1_yRbTaGjs1UXHa6JQK0sKDGBIVGm8oeW0k2kfbJgQ,182
60
- mini_swe_agent-1.17.1.dist-info/top_level.txt,sha256=zKF4t8bFpV87fdVABZt2Da-vnb4Vkh_CxkwQx5YT4Ew,13
61
- mini_swe_agent-1.17.1.dist-info/RECORD,,
57
+ mini_swe_agent-1.17.3.dist-info/METADATA,sha256=zowefUb3iP7jiHwasuE_WQc40kshknJQpzlli4ix0mk,14836
58
+ mini_swe_agent-1.17.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
59
+ mini_swe_agent-1.17.3.dist-info/entry_points.txt,sha256=d1_yRbTaGjs1UXHa6JQK0sKDGBIVGm8oeW0k2kfbJgQ,182
60
+ mini_swe_agent-1.17.3.dist-info/top_level.txt,sha256=zKF4t8bFpV87fdVABZt2Da-vnb4Vkh_CxkwQx5YT4Ew,13
61
+ mini_swe_agent-1.17.3.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.17.1"
11
+ __version__ = "1.17.3"
12
12
 
13
13
  import os
14
14
  from pathlib import Path
@@ -20,7 +20,15 @@ class AgentConfig:
20
20
  )
21
21
  timeout_template: str = (
22
22
  "The last command <command>{{action['action']}}</command> timed out and has been killed.\n"
23
- "The output of the command was:\n <output>\n{{output}}\n</output>\n"
23
+ "The output of the command was:\n"
24
+ "{% if output | length < 10000 -%}\n"
25
+ "<output>\n{{output}}\n</output>\n"
26
+ "{%- else -%}\n"
27
+ "<warning>Output was too long and has been truncated.</warning>\n"
28
+ "<output_head>\n{{ output[:5000] }}\n</output_head>\n"
29
+ "<elided_chars>{{ output | length - 10000 }} characters elided</elided_chars>\n"
30
+ "<output_tail>\n{{ output[-5000:] }}\n</output_tail>\n"
31
+ "{%- endif %}\n"
24
32
  "Please try another command and make sure to avoid those requiring interactive input."
25
33
  )
26
34
  format_error_template: str = "Please always provide EXACTLY ONE action in triple backticks."
@@ -41,6 +41,7 @@ class LitellmModel:
41
41
  litellm.utils.register_model(json.loads(Path(self.config.litellm_model_registry).read_text()))
42
42
 
43
43
  @retry(
44
+ reraise=True,
44
45
  stop=stop_after_attempt(int(os.getenv("MSWEA_MODEL_RETRY_STOP_AFTER_ATTEMPT", "10"))),
45
46
  wait=wait_exponential(multiplier=1, min=4, max=60),
46
47
  before_sleep=before_sleep_log(logger, logging.WARNING),
@@ -68,7 +69,7 @@ class LitellmModel:
68
69
  def query(self, messages: list[dict[str, str]], **kwargs) -> dict:
69
70
  if self.config.set_cache_control:
70
71
  messages = set_cache_control(messages, mode=self.config.set_cache_control)
71
- response = self._query(messages, **kwargs)
72
+ response = self._query([{"role": msg["role"], "content": msg["content"]} for msg in messages], **kwargs)
72
73
  try:
73
74
  cost = litellm.cost_calculator.completion_cost(response, model=self.config.model_name)
74
75
  if cost <= 0.0:
@@ -28,6 +28,7 @@ class LitellmResponseAPIModel(LitellmModel):
28
28
  self._previous_response_id: str | None = None
29
29
 
30
30
  @retry(
31
+ reraise=True,
31
32
  stop=stop_after_attempt(10),
32
33
  wait=wait_exponential(multiplier=1, min=4, max=60),
33
34
  before_sleep=before_sleep_log(logger, logging.WARNING),
@@ -45,9 +46,11 @@ class LitellmResponseAPIModel(LitellmModel):
45
46
  )
46
47
  def _query(self, messages: list[dict[str, str]], **kwargs):
47
48
  try:
49
+ # Remove 'timestamp' field added by agent - not supported by OpenAI responses API
50
+ clean_messages = [{"role": msg["role"], "content": msg["content"]} for msg in messages]
48
51
  resp = litellm.responses(
49
52
  model=self.config.model_name,
50
- input=messages if self._previous_response_id is None else messages[-1:],
53
+ input=clean_messages if self._previous_response_id is None else clean_messages[-1:],
51
54
  previous_response_id=self._previous_response_id,
52
55
  **(self.config.model_kwargs | kwargs),
53
56
  )
@@ -59,7 +62,6 @@ class LitellmResponseAPIModel(LitellmModel):
59
62
 
60
63
  def query(self, messages: list[dict[str, str]], **kwargs) -> dict:
61
64
  response = self._query(messages, **kwargs)
62
- print(response)
63
65
  text = coerce_responses_text(response)
64
66
  try:
65
67
  cost = litellm.cost_calculator.completion_cost(response, model=self.config.model_name)
@@ -56,6 +56,7 @@ class OpenRouterModel:
56
56
  self._api_key = os.getenv("OPENROUTER_API_KEY", "")
57
57
 
58
58
  @retry(
59
+ reraise=True,
59
60
  stop=stop_after_attempt(int(os.getenv("MSWEA_MODEL_RETRY_STOP_AFTER_ATTEMPT", "10"))),
60
61
  wait=wait_exponential(multiplier=1, min=4, max=60),
61
62
  before_sleep=before_sleep_log(logger, logging.WARNING),
@@ -97,7 +98,7 @@ class OpenRouterModel:
97
98
  def query(self, messages: list[dict[str, str]], **kwargs) -> dict:
98
99
  if self.config.set_cache_control:
99
100
  messages = set_cache_control(messages, mode=self.config.set_cache_control)
100
- response = self._query(messages, **kwargs)
101
+ response = self._query([{"role": msg["role"], "content": msg["content"]} for msg in messages], **kwargs)
101
102
 
102
103
  usage = response.get("usage", {})
103
104
  cost = usage.get("cost", 0.0)
@@ -74,6 +74,7 @@ class PortkeyModel:
74
74
  self.client = Portkey(**client_kwargs)
75
75
 
76
76
  @retry(
77
+ reraise=True,
77
78
  stop=stop_after_attempt(int(os.getenv("MSWEA_MODEL_RETRY_STOP_AFTER_ATTEMPT", "10"))),
78
79
  wait=wait_exponential(multiplier=1, min=4, max=60),
79
80
  before_sleep=before_sleep_log(logger, logging.WARNING),
@@ -90,7 +91,7 @@ class PortkeyModel:
90
91
  def query(self, messages: list[dict[str, str]], **kwargs) -> dict:
91
92
  if self.config.set_cache_control:
92
93
  messages = set_cache_control(messages, mode=self.config.set_cache_control)
93
- response = self._query(messages, **kwargs)
94
+ response = self._query([{"role": msg["role"], "content": msg["content"]} for msg in messages], **kwargs)
94
95
  cost = self._calculate_cost(response)
95
96
  self.n_calls += 1
96
97
  self.cost += cost
@@ -30,6 +30,7 @@ class PortkeyResponseAPIModel(PortkeyModel):
30
30
  self._previous_response_id: str | None = None
31
31
 
32
32
  @retry(
33
+ reraise=True,
33
34
  stop=stop_after_attempt(int(os.getenv("MSWEA_MODEL_RETRY_STOP_AFTER_ATTEMPT", "10"))),
34
35
  wait=wait_exponential(multiplier=1, min=4, max=60),
35
36
  before_sleep=before_sleep_log(logger, logging.WARNING),
@@ -51,6 +51,7 @@ class RequestyModel:
51
51
  self._api_key = os.getenv("REQUESTY_API_KEY", "")
52
52
 
53
53
  @retry(
54
+ reraise=True,
54
55
  stop=stop_after_attempt(10),
55
56
  wait=wait_exponential(multiplier=1, min=4, max=60),
56
57
  before_sleep=before_sleep_log(logger, logging.WARNING),
@@ -91,7 +92,7 @@ class RequestyModel:
91
92
  raise RequestyAPIError(f"Request failed: {e}") from e
92
93
 
93
94
  def query(self, messages: list[dict[str, str]], **kwargs) -> dict:
94
- response = self._query(messages, **kwargs)
95
+ response = self._query([{"role": msg["role"], "content": msg["content"]} for msg in messages], **kwargs)
95
96
 
96
97
  # Extract cost from usage information
97
98
  usage = response.get("usage", {})
@@ -79,7 +79,7 @@ class RunBatchProgressManager:
79
79
  "[cyan]Overall Progress", total=num_instances, total_cost="0.00", eta=""
80
80
  )
81
81
 
82
- self.render_group = Group(Table(), self._task_progress_bar, self._main_progress_bar)
82
+ self.render_group = Group(self._main_progress_bar, Table(), self._task_progress_bar)
83
83
  self._yaml_report_path = yaml_report_path
84
84
 
85
85
  @property
@@ -112,7 +112,7 @@ class RunBatchProgressManager:
112
112
  instances_str = _shorten_str(", ".join(reversed(instances)), 55)
113
113
  t.add_row(status, str(len(instances)), instances_str)
114
114
  assert self.render_group is not None
115
- self.render_group.renderables[0] = t
115
+ self.render_group.renderables[1] = t
116
116
 
117
117
  def _update_total_costs(self) -> None:
118
118
  with self._lock: