mini-swe-agent 1.14.4__py3-none-any.whl → 1.15.0__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.14.4
3
+ Version: 1.15.0
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
@@ -248,7 +248,7 @@ agent.run("Write a sudoku game")
248
248
 
249
249
  ## Let's get started!
250
250
 
251
- Option 1: Install + run in virtual environment
251
+ **Option 1:** If you just want to try out the CLI (package installed in anonymous virtual environment)
252
252
 
253
253
  ```bash
254
254
  pip install uv && uvx mini-swe-agent [-v]
@@ -256,19 +256,19 @@ pip install uv && uvx mini-swe-agent [-v]
256
256
  pip install pipx && pipx ensurepath && pipx run mini-swe-agent [-v]
257
257
  ```
258
258
 
259
- Option 2: Install in current environment
259
+ **Option 2:** Install CLI & python bindings in current environment
260
260
 
261
261
  ```bash
262
- pip install mini-swe-agent && mini [-v]
262
+ pip install mini-swe-agent
263
+ mini -v # run the CLI
263
264
  ```
264
265
 
265
- Option 3: Install from source
266
+ **Option 3:** Install from source (developer setup)
266
267
 
267
268
  ```bash
268
269
  git clone https://github.com/SWE-agent/mini-swe-agent.git
269
- cd mini-swe-agent
270
- pip install -e .
271
- mini [-v]
270
+ cd mini-swe-agent && pip install -e .
271
+ mini [-v] # run the CLI
272
272
  ```
273
273
 
274
274
  Read more in our [documentation](https://mini-swe-agent.com/latest/):
@@ -298,14 +298,15 @@ If you found this work helpful, please consider citing the [SWE-agent paper](htt
298
298
  Our other projects:
299
299
 
300
300
  <div align="center">
301
- <a href="https://github.com/SWE-agent/SWE-agent"><img src="https://github.com/SWE-agent/mini-swe-agent/raw/main/docs/assets/sweagent_logo_text_below.svg" alt="SWE-agent" height="120px"></a>
301
+ <a href="https://github.com/SWE-agent/SWE-agent"><img src="https://raw.githubusercontent.com/SWE-agent/swe-agent-media/refs/heads/main/media/logos_banners/sweagent_logo_text_below.svg" alt="SWE-agent" height="120px"></a>
302
302
  &nbsp;&nbsp;
303
- <a href="https://github.com/SWE-agent/SWE-ReX"><img src="https://github.com/SWE-agent/mini-swe-agent/raw/main/docs/assets/swerex_logo_text_below.svg" alt="SWE-ReX" height="120px"></a>
303
+ <a href="https://github.com/SWE-agent/SWE-ReX"><img src="https://raw.githubusercontent.com/SWE-agent/swe-agent-media/refs/heads/main/media/logos_banners/swerex_logo_text_below.svg" alt="SWE-ReX" height="120px"></a>
304
304
  &nbsp;&nbsp;
305
- <a href="https://github.com/SWE-bench/SWE-bench"><img src="https://github.com/SWE-agent/mini-swe-agent/raw/main/docs/assets/swebench_logo_text_below.svg" alt="SWE-bench" height="120px"></a>
305
+ <a href="https://github.com/SWE-bench/SWE-bench"><img src="https://raw.githubusercontent.com/SWE-agent/swe-agent-media/refs/heads/main/media/logos_banners/swebench_logo_text_below.svg" alt="SWE-bench" height="120px"></a>
306
306
  &nbsp;&nbsp;
307
- <a href="https://github.com/SWE-bench/SWE-smith"><img src="https://github.com/SWE-agent/mini-swe-agent/raw/main/docs/assets/swesmith_logo_text_below.svg" alt="SWE-smith" height="120px"></a>
307
+ <a href="https://github.com/SWE-bench/SWE-smith"><img src="https://raw.githubusercontent.com/SWE-agent/swe-agent-media/refs/heads/main/media/logos_banners/swesmith_logo_text_below.svg" alt="SWE-smith" height="120px"></a>
308
308
  &nbsp;&nbsp;
309
- <a href="https://github.com/SWE-bench/sb-cli"><img src="https://github.com/SWE-agent/mini-swe-agent/raw/main/docs/assets/sbcli_logo_text_below.svg" alt="sb-cli" height="120px"></a>
309
+ <a href="https://github.com/codeclash-ai/codeclash"><img src="https://raw.githubusercontent.com/SWE-agent/swe-agent-media/refs/heads/main/media/logos_banners/codeclash_logo_text_below.svg" alt="CodeClash" height="120px"></a>
310
+ &nbsp;&nbsp;
311
+ <a href="https://github.com/SWE-bench/sb-cli"><img src="https://raw.githubusercontent.com/SWE-agent/swe-agent-media/refs/heads/main/media/logos_banners/sbcli_logo_text_below.svg" alt="sb-cli" height="120px"></a>
310
312
  </div>
311
-
@@ -1,5 +1,5 @@
1
- mini_swe_agent-1.14.4.dist-info/licenses/LICENSE.md,sha256=D3luWPkdHAe7LBsdD4vzqDAXw6Xewb3G-uczss0uh1s,1094
2
- minisweagent/__init__.py,sha256=DhyfEPFkbOEoEnUa_Z6_XD7ExVCSzaLnFqaEH5laa9I,2016
1
+ mini_swe_agent-1.15.0.dist-info/licenses/LICENSE.md,sha256=D3luWPkdHAe7LBsdD4vzqDAXw6Xewb3G-uczss0uh1s,1094
2
+ minisweagent/__init__.py,sha256=FPYqBxLN7o08s1a-cjj5m1peNt7U9uMqDHH94SNiAKs,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
@@ -25,9 +25,9 @@ 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=Ol95N3oEDlojz7IBw10A7xf5rKfxtjESyJuEWOwZyzo,4171
27
27
  minisweagent/models/anthropic.py,sha256=4p-LxQ_RYQUX1rBsffAj3T1bBb2uMRhA4IyKfDcMpgo,1517
28
- minisweagent/models/litellm_model.py,sha256=wtGeCwjvCbL2pRN8PTDDIaGYoCnPyMjD0dGn0fkjcLo,3533
29
- minisweagent/models/openrouter_model.py,sha256=RMVcj74yO0TMzEPn35NjUzJ_PIOeO6TZpP-MmLJbGRw,4209
30
- minisweagent/models/portkey_model.py,sha256=OYXE2RVibuYiTe9gwK40yUIJiJEV3Qbu6VXUJrc_Ep8,6479
28
+ minisweagent/models/litellm_model.py,sha256=LXhTK3eSIsgLOmmzyewJedQMkFhpO4pIpQV8g2qy1sI,4239
29
+ minisweagent/models/openrouter_model.py,sha256=dsVl8pnZ9M6nZ5DpLy69v1bizMR73mixXdVZVNzvknc,4712
30
+ minisweagent/models/portkey_model.py,sha256=whDS1lG30EhjE1z3k1TuvGsuj7WzzUy_Ti1p9fgPsEI,7256
31
31
  minisweagent/models/test_models.py,sha256=ItCA6ddntzkYA7dzSuUEaLMV-AE8TBuXBFP8CzpiO3U,1351
32
32
  minisweagent/models/extra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  minisweagent/models/extra/roulette.py,sha256=SqLj_wz9Vkbxou7i9Ef4Uzmg_eheDouNySkkV7pm2Ys,2093
@@ -38,7 +38,7 @@ minisweagent/run/__init__.py,sha256=WIoYgHVl7iZF2YncrfV3IttupG6P5KogroKHKECka3A,
38
38
  minisweagent/run/github_issue.py,sha256=35mZoPLc4JV6XXJKRv55lnuKbXf5lDftd51N89-x9J0,3192
39
39
  minisweagent/run/hello_world.py,sha256=erLnEwNmPFLxq3-8zyv66Vy1kIqMqQf97vISX7LrQXg,959
40
40
  minisweagent/run/inspector.py,sha256=QnY3oYzm-yq3w9Jzs112Lco2Rg84vSocAWrQRVz_1lc,7127
41
- minisweagent/run/mini.py,sha256=uDRb_gac9WcVBVF7kZxknHCwoAPRtLwtPi77ox6Zhjw,4945
41
+ minisweagent/run/mini.py,sha256=N3ZvTQmKHNJ9bEaiz5YHjJT4Arg0WtjxGLBTtj8-T0E,4922
42
42
  minisweagent/run/mini_extra.py,sha256=ecA1PnTWElpO60G9RktvVLtUOf3bZ_ESmnSttS6izhQ,1465
43
43
  minisweagent/run/extra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  minisweagent/run/extra/config.py,sha256=5s0ZjjE4QTphOqQzCJqHD2APq5jCdod5jFjGo3sXDms,3868
@@ -47,11 +47,11 @@ minisweagent/run/extra/swebench_single.py,sha256=KmoUkD6UQ1P0MY_73-OtYuQAsNPmOLl
47
47
  minisweagent/run/extra/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  minisweagent/run/extra/utils/batch_progress.py,sha256=xhJ7FmsaTBGz-yh8pzYl4yMoUGjn7GA24eYrP-nHj60,6804
49
49
  minisweagent/run/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- minisweagent/run/utils/save.py,sha256=2xd-UnUzI7Fr_AUZ5KEJ53Aa4kpuuGYxkLwyUcvqyMM,2503
50
+ minisweagent/run/utils/save.py,sha256=bokvblZ1SaIvCXimkRQqgvERKmVM0jn8SF7UoHBeerQ,2546
51
51
  minisweagent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
52
  minisweagent/utils/log.py,sha256=ruDMNKMrVC9NPvCeHwO3QYz5jsVNUGQB2dRAEAPAWp8,996
53
- mini_swe_agent-1.14.4.dist-info/METADATA,sha256=rOK_KGZBF7DWMzian2VW2Kw0bGcZYJJXkkSUTEzvkPg,14151
54
- mini_swe_agent-1.14.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
- mini_swe_agent-1.14.4.dist-info/entry_points.txt,sha256=d1_yRbTaGjs1UXHa6JQK0sKDGBIVGm8oeW0k2kfbJgQ,182
56
- mini_swe_agent-1.14.4.dist-info/top_level.txt,sha256=zKF4t8bFpV87fdVABZt2Da-vnb4Vkh_CxkwQx5YT4Ew,13
57
- mini_swe_agent-1.14.4.dist-info/RECORD,,
53
+ mini_swe_agent-1.15.0.dist-info/METADATA,sha256=OOC0rEl3tuJDSiL9hq_OIP_e3xXqNzhibE2ihzXPsK4,14679
54
+ mini_swe_agent-1.15.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
+ mini_swe_agent-1.15.0.dist-info/entry_points.txt,sha256=d1_yRbTaGjs1UXHa6JQK0sKDGBIVGm8oeW0k2kfbJgQ,182
56
+ mini_swe_agent-1.15.0.dist-info/top_level.txt,sha256=zKF4t8bFpV87fdVABZt2Da-vnb4Vkh_CxkwQx5YT4Ew,13
57
+ mini_swe_agent-1.15.0.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.14.4"
11
+ __version__ = "1.15.0"
12
12
 
13
13
  import os
14
14
  from pathlib import Path
@@ -27,6 +27,8 @@ class LitellmModelConfig:
27
27
  litellm_model_registry: Path | str | None = os.getenv("LITELLM_MODEL_REGISTRY_PATH")
28
28
  set_cache_control: Literal["default_end"] | None = None
29
29
  """Set explicit cache control markers, for example for Anthropic models"""
30
+ cost_tracking: Literal["default", "ignore_errors"] = os.getenv("MSWEA_COST_TRACKING", "default")
31
+ """Cost tracking mode for this model. Can be "default" or "ignore_errors" (ignore errors/missing cost info)"""
30
32
 
31
33
 
32
34
  class LitellmModel:
@@ -68,15 +70,22 @@ class LitellmModel:
68
70
  response = self._query(messages, **kwargs)
69
71
  try:
70
72
  cost = litellm.cost_calculator.completion_cost(response)
73
+ if cost <= 0.0:
74
+ raise ValueError(f"Cost must be > 0.0, got {cost}")
71
75
  except Exception as e:
72
- logger.critical(
73
- f"Error calculating cost for model {self.config.model_name}: {e}. "
74
- "Please check the 'Updating the model registry' section in the documentation at "
75
- "https://klieret.short.gy/litellm-model-registry Still stuck? Please open a github issue for help!"
76
- )
77
- raise
76
+ cost = 0.0
77
+ if self.config.cost_tracking != "ignore_errors":
78
+ msg = (
79
+ f"Error calculating cost for model {self.config.model_name}: {e}, perhaps it's not registered? "
80
+ "You can ignore this issue from your config file with cost_tracking: 'ignore_errors' or "
81
+ "globally with export MSWEA_COST_TRACKING='ignore_errors'. "
82
+ "Alternatively check the 'Cost tracking' section in the documentation at "
83
+ "https://klieret.short.gy/mini-local-models. "
84
+ " Still stuck? Please open a github issue at https://github.com/SWE-agent/mini-swe-agent/issues/new/choose!"
85
+ )
86
+ logger.critical(msg)
87
+ raise RuntimeError(msg) from e
78
88
  self.n_calls += 1
79
- assert cost >= 0.0, f"Cost is negative: {cost}"
80
89
  self.cost += cost
81
90
  GLOBAL_MODEL_STATS.add(cost)
82
91
  return {
@@ -25,6 +25,8 @@ class OpenRouterModelConfig:
25
25
  model_kwargs: dict[str, Any] = field(default_factory=dict)
26
26
  set_cache_control: Literal["default_end"] | None = None
27
27
  """Set explicit cache control markers, for example for Anthropic models"""
28
+ cost_tracking: Literal["default", "ignore_errors"] = os.getenv("MSWEA_COST_TRACKING", "default")
29
+ """Cost tracking mode for this model. Can be "default" or "ignore_errors" (ignore errors/missing cost info)"""
28
30
 
29
31
 
30
32
  class OpenRouterAPIError(Exception):
@@ -97,16 +99,15 @@ class OpenRouterModel:
97
99
  messages = set_cache_control(messages, mode=self.config.set_cache_control)
98
100
  response = self._query(messages, **kwargs)
99
101
 
100
- # Extract cost from usage information
101
102
  usage = response.get("usage", {})
102
103
  cost = usage.get("cost", 0.0)
103
- assert cost >= 0.0, f"Cost is negative: {cost}"
104
-
105
- # If total_cost is not available, raise an error
106
- if cost == 0.0:
107
- raise OpenRouterAPIError(
108
- f"No cost information available from OpenRouter API for model {self.config.model_name}. "
109
- "Cost tracking is required but not provided by the API response."
104
+ if cost <= 0.0 and self.config.cost_tracking != "ignore_errors":
105
+ raise RuntimeError(
106
+ f"No valid cost information available from OpenRouter API for model {self.config.model_name}: "
107
+ f"Usage {usage}, cost {cost}. Cost must be > 0.0. Set cost_tracking: 'ignore_errors' in your config file or "
108
+ "export MSWEA_COST_TRACKING='ignore_errors' to ignore cost tracking errors "
109
+ "(for example for free/local models), more information at https://klieret.short.gy/mini-local-models "
110
+ "for more details. Still stuck? Please open a github issue at https://github.com/SWE-agent/mini-swe-agent/issues/new/choose!"
110
111
  )
111
112
 
112
113
  self.n_calls += 1
@@ -40,6 +40,8 @@ class PortkeyModelConfig:
40
40
  """
41
41
  set_cache_control: Literal["default_end"] | None = None
42
42
  """Set explicit cache control markers, for example for Anthropic models"""
43
+ cost_tracking: Literal["default", "ignore_errors"] = os.getenv("MSWEA_COST_TRACKING", "default")
44
+ """Cost tracking mode for this model. Can be "default" or "ignore_errors" (ignore errors/missing cost info)"""
43
45
 
44
46
 
45
47
  class PortkeyModel:
@@ -91,6 +93,22 @@ class PortkeyModel:
91
93
  if self.config.set_cache_control:
92
94
  messages = set_cache_control(messages, mode=self.config.set_cache_control)
93
95
  response = self._query(messages, **kwargs)
96
+ cost = self._calculate_cost(response)
97
+ self.n_calls += 1
98
+ self.cost += cost
99
+ GLOBAL_MODEL_STATS.add(cost)
100
+ return {
101
+ "content": response.choices[0].message.content or "",
102
+ "extra": {
103
+ "response": response.model_dump(),
104
+ "cost": cost,
105
+ },
106
+ }
107
+
108
+ def get_template_vars(self) -> dict[str, Any]:
109
+ return asdict(self.config) | {"n_model_calls": self.n_calls, "model_cost": self.cost}
110
+
111
+ def _calculate_cost(self, response) -> float:
94
112
  response_for_cost_calc = response.model_copy()
95
113
  if self.config.litellm_model_name_override:
96
114
  if response_for_cost_calc.model:
@@ -114,33 +132,25 @@ class PortkeyModel:
114
132
  f"WARNING: Total tokens - prompt tokens - completion tokens != 0: {response_for_cost_calc.model_dump()}."
115
133
  " This is probably a portkey bug or incompatibility with litellm cost tracking. "
116
134
  "Setting prompt tokens based on total tokens and completion tokens. You might want to double check your costs. "
117
- "Full response: {response_for_cost_calc.model_dump()}"
135
+ f"Full response: {response_for_cost_calc.model_dump()}"
118
136
  )
119
137
  response_for_cost_calc.usage.prompt_tokens = total_tokens - completion_tokens
120
138
  try:
121
139
  cost = litellm.cost_calculator.completion_cost(
122
140
  response_for_cost_calc, model=self.config.litellm_model_name_override or None
123
141
  )
142
+ assert cost >= 0.0, f"Cost is negative: {cost}"
124
143
  except Exception as e:
125
- logger.critical(
126
- f"Error calculating cost for model {self.config.model_name} based on {response_for_cost_calc.model_dump()}: {e}. "
127
- "Please check the 'Updating the model registry' section in the documentation at "
128
- "https://klieret.short.gy/litellm-model-registry Still stuck? Please open a github issue for help!"
129
- )
130
- raise
131
- assert cost >= 0.0, f"Cost is negative: {cost}"
132
-
133
- self.n_calls += 1
134
- self.cost += cost
135
- GLOBAL_MODEL_STATS.add(cost)
136
-
137
- return {
138
- "content": response.choices[0].message.content or "",
139
- "extra": {
140
- "response": response.model_dump(),
141
- "cost": cost,
142
- },
143
- }
144
-
145
- def get_template_vars(self) -> dict[str, Any]:
146
- return asdict(self.config) | {"n_model_calls": self.n_calls, "model_cost": self.cost}
144
+ cost = 0.0
145
+ if self.config.cost_tracking != "ignore_errors":
146
+ msg = (
147
+ f"Error calculating cost for model {self.config.model_name} based on {response_for_cost_calc.model_dump()}: {e}. "
148
+ "You can ignore this issue from your config file with cost_tracking: 'ignore_errors' or "
149
+ "globally with export MSWEA_COST_TRACKING='ignore_errors' to ignore this error. "
150
+ "Alternatively check the 'Cost tracking' section in the documentation at "
151
+ "https://klieret.short.gy/mini-local-models. "
152
+ "Still stuck? Please open a github issue at https://github.com/SWE-agent/mini-swe-agent/issues/new/choose!"
153
+ )
154
+ logger.critical(msg)
155
+ raise RuntimeError(msg) from e
156
+ return cost
minisweagent/run/mini.py CHANGED
@@ -100,8 +100,7 @@ def main(
100
100
  exit_status, result = type(e).__name__, str(e)
101
101
  extra_info = {"traceback": traceback.format_exc()}
102
102
  finally:
103
- if output:
104
- save_traj(agent, output, exit_status=exit_status, result=result, extra_info=extra_info) # type: ignore[arg-type]
103
+ save_traj(agent, output, exit_status=exit_status, result=result, extra_info=extra_info) # type: ignore[arg-type]
105
104
  return agent
106
105
 
107
106
 
@@ -21,7 +21,7 @@ def _asdict(obj: Any) -> dict:
21
21
 
22
22
  def save_traj(
23
23
  agent: Agent | None,
24
- path: Path,
24
+ path: Path | None,
25
25
  *,
26
26
  print_path: bool = True,
27
27
  exit_status: str | None = None,
@@ -42,6 +42,8 @@ def save_traj(
42
42
  **kwargs: Additional information to save (will be merged into top level)
43
43
 
44
44
  """
45
+ if path is None:
46
+ return
45
47
  data = {
46
48
  "info": {
47
49
  "exit_status": exit_status,