mini-swe-agent 1.8.1__tar.gz → 1.9.1__tar.gz
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.
- {mini_swe_agent-1.8.1/src/mini_swe_agent.egg-info → mini_swe_agent-1.9.1}/PKG-INFO +3 -2
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/pyproject.toml +2 -1
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1/src/mini_swe_agent.egg-info}/PKG-INFO +3 -2
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/mini_swe_agent.egg-info/SOURCES.txt +3 -1
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/mini_swe_agent.egg-info/requires.txt +2 -1
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/__init__.py +17 -2
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/agents/default.py +5 -5
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/agents/interactive.py +2 -2
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/agents/interactive_textual.py +4 -4
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/docker.py +8 -4
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/extra/swerex_docker.py +11 -3
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/local.py +6 -1
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/singularity.py +6 -3
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/litellm_model.py +4 -1
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/test_models.py +5 -1
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/swebench.py +15 -12
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/swebench_single.py +18 -2
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/mini.py +14 -17
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/utils/save.py +3 -1
- mini_swe_agent-1.9.1/src/minisweagent/utils/__init__.py +0 -0
- mini_swe_agent-1.9.1/src/minisweagent/utils/log.py +36 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/LICENSE.md +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/README.md +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/setup.cfg +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/mini_swe_agent.egg-info/dependency_links.txt +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/mini_swe_agent.egg-info/entry_points.txt +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/mini_swe_agent.egg-info/top_level.txt +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/__main__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/agents/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/README.md +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/default.yaml +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/extra/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/extra/swebench.yaml +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/github_issue.yaml +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/mini.tcss +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/mini.yaml +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/config/mini_no_temp.yaml +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/extra/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/__init__.py +2 -2
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/anthropic.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/utils/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/utils/cache_control.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/utils/key_per_thread.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/py.typed +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/config.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/utils/__init__.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/utils/batch_progress.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/github_issue.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/hello_world.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/inspector.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/mini_extra.py +0 -0
- {mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/utils/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mini-swe-agent
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.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
|
|
@@ -48,9 +48,10 @@ Requires-Dist: typer
|
|
|
48
48
|
Requires-Dist: platformdirs
|
|
49
49
|
Requires-Dist: textual
|
|
50
50
|
Requires-Dist: prompt_toolkit
|
|
51
|
+
Requires-Dist: openai<=1.99.5
|
|
51
52
|
Provides-Extra: full
|
|
52
53
|
Requires-Dist: mini-swe-agent[dev]; extra == "full"
|
|
53
|
-
Requires-Dist: swe-rex; extra == "full"
|
|
54
|
+
Requires-Dist: swe-rex>=1.4.0; extra == "full"
|
|
54
55
|
Provides-Extra: dev
|
|
55
56
|
Requires-Dist: datasets; extra == "dev"
|
|
56
57
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -42,12 +42,13 @@ dependencies = [
|
|
|
42
42
|
"platformdirs",
|
|
43
43
|
"textual",
|
|
44
44
|
"prompt_toolkit",
|
|
45
|
+
"openai <= 1.99.5", # https://github.com/SWE-agent/mini-swe-agent/issues/446
|
|
45
46
|
]
|
|
46
47
|
|
|
47
48
|
[project.optional-dependencies]
|
|
48
49
|
full = [
|
|
49
50
|
"mini-swe-agent[dev]",
|
|
50
|
-
"swe-rex",
|
|
51
|
+
"swe-rex>=1.4.0",
|
|
51
52
|
]
|
|
52
53
|
|
|
53
54
|
dev = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mini-swe-agent
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.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
|
|
@@ -48,9 +48,10 @@ Requires-Dist: typer
|
|
|
48
48
|
Requires-Dist: platformdirs
|
|
49
49
|
Requires-Dist: textual
|
|
50
50
|
Requires-Dist: prompt_toolkit
|
|
51
|
+
Requires-Dist: openai<=1.99.5
|
|
51
52
|
Provides-Extra: full
|
|
52
53
|
Requires-Dist: mini-swe-agent[dev]; extra == "full"
|
|
53
|
-
Requires-Dist: swe-rex; extra == "full"
|
|
54
|
+
Requires-Dist: swe-rex>=1.4.0; extra == "full"
|
|
54
55
|
Provides-Extra: dev
|
|
55
56
|
Requires-Dist: datasets; extra == "dev"
|
|
56
57
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -49,4 +49,6 @@ src/minisweagent/run/extra/swebench_single.py
|
|
|
49
49
|
src/minisweagent/run/extra/utils/__init__.py
|
|
50
50
|
src/minisweagent/run/extra/utils/batch_progress.py
|
|
51
51
|
src/minisweagent/run/utils/__init__.py
|
|
52
|
-
src/minisweagent/run/utils/save.py
|
|
52
|
+
src/minisweagent/run/utils/save.py
|
|
53
|
+
src/minisweagent/utils/__init__.py
|
|
54
|
+
src/minisweagent/utils/log.py
|
|
@@ -8,7 +8,7 @@ This file provides:
|
|
|
8
8
|
unless you want the static type checking.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
__version__ = "1.
|
|
11
|
+
__version__ = "1.9.1"
|
|
12
12
|
|
|
13
13
|
import os
|
|
14
14
|
from pathlib import Path
|
|
@@ -18,6 +18,8 @@ import dotenv
|
|
|
18
18
|
from platformdirs import user_config_dir
|
|
19
19
|
from rich.console import Console
|
|
20
20
|
|
|
21
|
+
from minisweagent.utils.log import logger
|
|
22
|
+
|
|
21
23
|
package_dir = Path(__file__).resolve().parent
|
|
22
24
|
|
|
23
25
|
global_config_dir = Path(os.getenv("MSWEA_GLOBAL_CONFIG_DIR") or user_config_dir("mini-swe-agent"))
|
|
@@ -45,6 +47,8 @@ class Model(Protocol):
|
|
|
45
47
|
|
|
46
48
|
def query(self, messages: list[dict[str, str]], **kwargs) -> dict: ...
|
|
47
49
|
|
|
50
|
+
def get_template_vars(self) -> dict[str, Any]: ...
|
|
51
|
+
|
|
48
52
|
|
|
49
53
|
class Environment(Protocol):
|
|
50
54
|
"""Protocol for execution environments."""
|
|
@@ -53,6 +57,8 @@ class Environment(Protocol):
|
|
|
53
57
|
|
|
54
58
|
def execute(self, command: str, cwd: str = "") -> dict[str, str]: ...
|
|
55
59
|
|
|
60
|
+
def get_template_vars(self) -> dict[str, Any]: ...
|
|
61
|
+
|
|
56
62
|
|
|
57
63
|
class Agent(Protocol):
|
|
58
64
|
"""Protocol for agents."""
|
|
@@ -64,4 +70,13 @@ class Agent(Protocol):
|
|
|
64
70
|
def run(self, task: str, **kwargs) -> tuple[str, str]: ...
|
|
65
71
|
|
|
66
72
|
|
|
67
|
-
__all__ = [
|
|
73
|
+
__all__ = [
|
|
74
|
+
"Agent",
|
|
75
|
+
"Model",
|
|
76
|
+
"Environment",
|
|
77
|
+
"package_dir",
|
|
78
|
+
"__version__",
|
|
79
|
+
"global_config_file",
|
|
80
|
+
"global_config_dir",
|
|
81
|
+
"logger",
|
|
82
|
+
]
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"""Basic agent class. See https://mini-swe-agent.com/latest/advanced/control_flow/ for visual explanation."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
import platform
|
|
5
3
|
import re
|
|
6
4
|
import subprocess
|
|
7
5
|
from collections.abc import Callable
|
|
@@ -61,19 +59,21 @@ class DefaultAgent:
|
|
|
61
59
|
self.messages: list[dict] = []
|
|
62
60
|
self.model = model
|
|
63
61
|
self.env = env
|
|
62
|
+
self.extra_template_vars = {}
|
|
64
63
|
|
|
65
64
|
def render_template(self, template: str, **kwargs) -> str:
|
|
66
|
-
|
|
67
|
-
return Template(template).render(**kwargs, **
|
|
65
|
+
template_vars = asdict(self.config) | self.env.get_template_vars() | self.model.get_template_vars()
|
|
66
|
+
return Template(template).render(**kwargs, **template_vars, **self.extra_template_vars)
|
|
68
67
|
|
|
69
68
|
def add_message(self, role: str, content: str, **kwargs):
|
|
70
69
|
self.messages.append({"role": role, "content": content, **kwargs})
|
|
71
70
|
|
|
72
71
|
def run(self, task: str, **kwargs) -> tuple[str, str]:
|
|
73
72
|
"""Run step() until agent is finished. Return exit status & message"""
|
|
73
|
+
self.extra_template_vars |= {"task": task, **kwargs}
|
|
74
74
|
self.messages = []
|
|
75
75
|
self.add_message("system", self.render_template(self.config.system_template))
|
|
76
|
-
self.add_message("user", self.render_template(self.config.instance_template
|
|
76
|
+
self.add_message("user", self.render_template(self.config.instance_template))
|
|
77
77
|
while True:
|
|
78
78
|
try:
|
|
79
79
|
self.step()
|
|
@@ -39,9 +39,9 @@ class InteractiveAgent(DefaultAgent):
|
|
|
39
39
|
super().__init__(*args, config_class=config_class, **kwargs)
|
|
40
40
|
self.cost_last_confirmed = 0.0
|
|
41
41
|
|
|
42
|
-
def add_message(self, role: str, content: str):
|
|
42
|
+
def add_message(self, role: str, content: str, **kwargs):
|
|
43
43
|
# Extend supermethod to print messages
|
|
44
|
-
super().add_message(role, content)
|
|
44
|
+
super().add_message(role, content, **kwargs)
|
|
45
45
|
if role == "assistant":
|
|
46
46
|
console.print(
|
|
47
47
|
f"\n[red][bold]mini-swe-agent[/bold] (step [bold]{self.model.n_calls}[/bold], [bold]${self.model.cost:.2f}[/bold]):[/red]\n",
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/agents/interactive_textual.py
RENAMED
|
@@ -44,8 +44,8 @@ class _TextualAgent(DefaultAgent):
|
|
|
44
44
|
super().__init__(*args, config_class=TextualAgentConfig, **kwargs)
|
|
45
45
|
self._current_action_from_human = False
|
|
46
46
|
|
|
47
|
-
def add_message(self, role: str, content: str):
|
|
48
|
-
super().add_message(role, content)
|
|
47
|
+
def add_message(self, role: str, content: str, **kwargs):
|
|
48
|
+
super().add_message(role, content, **kwargs)
|
|
49
49
|
if self.app.agent_state != "UNINITIALIZED":
|
|
50
50
|
self.app.call_from_thread(self.app.on_message_added)
|
|
51
51
|
|
|
@@ -276,8 +276,8 @@ class TextualAgent(App):
|
|
|
276
276
|
|
|
277
277
|
self._vscroll = VerticalScroll()
|
|
278
278
|
|
|
279
|
-
def run(self, task: str) -> tuple[str, str]:
|
|
280
|
-
threading.Thread(target=lambda: self.agent.run(task), daemon=True).start()
|
|
279
|
+
def run(self, task: str, **kwargs) -> tuple[str, str]:
|
|
280
|
+
threading.Thread(target=lambda: self.agent.run(task, **kwargs), daemon=True).start()
|
|
281
281
|
super().run()
|
|
282
282
|
return self.exit_status, self.result
|
|
283
283
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
import shlex
|
|
3
4
|
import subprocess
|
|
4
5
|
import uuid
|
|
5
|
-
from dataclasses import dataclass, field
|
|
6
|
+
from dataclasses import asdict, dataclass, field
|
|
6
7
|
from typing import Any
|
|
7
8
|
|
|
8
9
|
|
|
@@ -33,10 +34,14 @@ class DockerEnvironment:
|
|
|
33
34
|
"""This class executes bash commands in a Docker container using direct docker commands.
|
|
34
35
|
See `DockerEnvironmentConfig` for keyword arguments.
|
|
35
36
|
"""
|
|
37
|
+
self.logger = logging.getLogger("minisweagent.environment")
|
|
36
38
|
self.container_id: str | None = None
|
|
37
39
|
self.config = config_class(**kwargs)
|
|
38
40
|
self._start_container()
|
|
39
41
|
|
|
42
|
+
def get_template_vars(self) -> dict[str, Any]:
|
|
43
|
+
return asdict(self.config)
|
|
44
|
+
|
|
40
45
|
def _start_container(self):
|
|
41
46
|
"""Start the Docker container and return the container ID."""
|
|
42
47
|
container_name = f"minisweagent-{uuid.uuid4().hex[:8]}"
|
|
@@ -53,7 +58,7 @@ class DockerEnvironment:
|
|
|
53
58
|
"sleep",
|
|
54
59
|
self.config.container_timeout,
|
|
55
60
|
]
|
|
56
|
-
|
|
61
|
+
self.logger.debug(f"Starting container with command: {shlex.join(cmd)}")
|
|
57
62
|
result = subprocess.run(
|
|
58
63
|
cmd,
|
|
59
64
|
capture_output=True,
|
|
@@ -61,7 +66,7 @@ class DockerEnvironment:
|
|
|
61
66
|
timeout=120, # docker pull might take a while
|
|
62
67
|
check=True,
|
|
63
68
|
)
|
|
64
|
-
|
|
69
|
+
self.logger.info(f"Started container {container_name} with ID {result.stdout.strip()}")
|
|
65
70
|
self.container_id = result.stdout.strip()
|
|
66
71
|
|
|
67
72
|
def execute(self, command: str, cwd: str = "") -> dict[str, Any]:
|
|
@@ -91,7 +96,6 @@ class DockerEnvironment:
|
|
|
91
96
|
def cleanup(self):
|
|
92
97
|
"""Stop and remove the Docker container."""
|
|
93
98
|
if getattr(self, "container_id", None) is not None: # if init fails early, container_id might not be set
|
|
94
|
-
print(f"Stopping container {self.container_id}")
|
|
95
99
|
cmd = f"(timeout 60 {self.config.executable} stop {self.container_id} || {self.config.executable} rm -f {self.container_id}) >/dev/null 2>&1 &"
|
|
96
100
|
subprocess.Popen(cmd, shell=True)
|
|
97
101
|
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/extra/swerex_docker.py
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from dataclasses import dataclass, field
|
|
2
|
+
from dataclasses import asdict, dataclass, field
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from swerex.deployment.docker import DockerDeployment
|
|
@@ -29,11 +29,19 @@ class SwerexDockerEnvironment:
|
|
|
29
29
|
output = asyncio.run(
|
|
30
30
|
self.deployment.runtime.execute(
|
|
31
31
|
RexCommand(
|
|
32
|
-
command=command,
|
|
32
|
+
command=command,
|
|
33
|
+
shell=True,
|
|
34
|
+
check=False,
|
|
35
|
+
cwd=cwd or self.config.cwd,
|
|
36
|
+
timeout=self.config.timeout,
|
|
37
|
+
merge_output_streams=True,
|
|
33
38
|
)
|
|
34
39
|
)
|
|
35
40
|
)
|
|
36
41
|
return {
|
|
37
|
-
"output":
|
|
42
|
+
"output": output.stdout,
|
|
38
43
|
"returncode": output.exit_code,
|
|
39
44
|
}
|
|
45
|
+
|
|
46
|
+
def get_template_vars(self) -> dict[str, Any]:
|
|
47
|
+
return asdict(self.config)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import platform
|
|
2
3
|
import subprocess
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
|
+
from dataclasses import asdict, dataclass, field
|
|
5
|
+
from typing import Any
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
@dataclass
|
|
@@ -31,3 +33,6 @@ class LocalEnvironment:
|
|
|
31
33
|
stderr=subprocess.STDOUT,
|
|
32
34
|
)
|
|
33
35
|
return {"output": result.stdout, "returncode": result.returncode}
|
|
36
|
+
|
|
37
|
+
def get_template_vars(self) -> dict[str, Any]:
|
|
38
|
+
return asdict(self.config) | platform.uname()._asdict() | os.environ
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import os
|
|
4
5
|
import shutil
|
|
5
6
|
import subprocess
|
|
6
7
|
import tempfile
|
|
7
8
|
import uuid
|
|
8
|
-
from dataclasses import dataclass, field
|
|
9
|
+
from dataclasses import asdict, dataclass, field
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
from typing import Any
|
|
11
12
|
|
|
@@ -27,14 +28,17 @@ class SingularityEnvironmentConfig:
|
|
|
27
28
|
class SingularityEnvironment:
|
|
28
29
|
def __init__(self, **kwargs):
|
|
29
30
|
"""Singularity environment. See `SingularityEnvironmentConfig` for kwargs."""
|
|
31
|
+
self.logger = logging.getLogger("minisweagent.environment")
|
|
30
32
|
self.config = SingularityEnvironmentConfig(**kwargs)
|
|
31
33
|
self.sandbox_dir = Path(tempfile.gettempdir()) / f"minisweagent-{uuid.uuid4().hex[:8]}"
|
|
32
|
-
|
|
33
34
|
subprocess.run(
|
|
34
35
|
[self.config.executable, "build", "--sandbox", self.sandbox_dir, self.config.image],
|
|
35
36
|
check=True,
|
|
36
37
|
)
|
|
37
38
|
|
|
39
|
+
def get_template_vars(self) -> dict[str, Any]:
|
|
40
|
+
return asdict(self.config)
|
|
41
|
+
|
|
38
42
|
def execute(self, command: str, cwd: str = "") -> dict[str, Any]:
|
|
39
43
|
"""Execute a command in a Singularity container and return the result as a dict."""
|
|
40
44
|
cmd = [self.config.executable, "exec"]
|
|
@@ -66,7 +70,6 @@ class SingularityEnvironment:
|
|
|
66
70
|
|
|
67
71
|
def cleanup(self):
|
|
68
72
|
if self.sandbox_dir.exists():
|
|
69
|
-
print(f"Removing sandbox {self.sandbox_dir}")
|
|
70
73
|
shutil.rmtree(self.sandbox_dir)
|
|
71
74
|
|
|
72
75
|
def __del__(self):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
-
from dataclasses import dataclass, field
|
|
4
|
+
from dataclasses import asdict, dataclass, field
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
@@ -68,3 +68,6 @@ class LitellmModel:
|
|
|
68
68
|
return {
|
|
69
69
|
"content": response.choices[0].message.content or "", # type: ignore
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
def get_template_vars(self) -> dict[str, Any]:
|
|
73
|
+
return asdict(self.config) | {"n_model_calls": self.n_calls, "model_cost": self.cost}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import time
|
|
3
|
-
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
from minisweagent.models import GLOBAL_MODEL_STATS
|
|
6
7
|
|
|
@@ -36,3 +37,6 @@ class DeterministicModel:
|
|
|
36
37
|
self.cost += self.config.cost_per_call
|
|
37
38
|
GLOBAL_MODEL_STATS.add(self.config.cost_per_call)
|
|
38
39
|
return {"content": output}
|
|
40
|
+
|
|
41
|
+
def get_template_vars(self) -> dict[str, Any]:
|
|
42
|
+
return asdict(self.config) | {"n_model_calls": self.n_calls, "model_cost": self.cost}
|
|
@@ -24,6 +24,7 @@ from minisweagent.environments import get_environment
|
|
|
24
24
|
from minisweagent.models import get_model
|
|
25
25
|
from minisweagent.run.extra.utils.batch_progress import RunBatchProgressManager
|
|
26
26
|
from minisweagent.run.utils.save import save_traj
|
|
27
|
+
from minisweagent.utils.log import add_file_handler, logger
|
|
27
28
|
|
|
28
29
|
_HELP_TEXT = """Run mini-SWE-agent on SWEBench instances.
|
|
29
30
|
|
|
@@ -141,7 +142,7 @@ def process_instance(
|
|
|
141
142
|
)
|
|
142
143
|
exit_status, result = agent.run(task)
|
|
143
144
|
except Exception as e:
|
|
144
|
-
|
|
145
|
+
logger.error(f"Error processing instance {instance_id}: {e}", exc_info=True)
|
|
145
146
|
exit_status, result = type(e).__name__, str(e)
|
|
146
147
|
extra_info = {"traceback": traceback.format_exc()}
|
|
147
148
|
finally:
|
|
@@ -152,6 +153,7 @@ def process_instance(
|
|
|
152
153
|
result=result,
|
|
153
154
|
extra_info=extra_info,
|
|
154
155
|
instance_id=instance_id,
|
|
156
|
+
print_fct=logger.info,
|
|
155
157
|
)
|
|
156
158
|
update_preds_file(output_dir / "preds.json", instance_id, model.config.model_name, result)
|
|
157
159
|
progress_manager.on_instance_end(instance_id, exit_status)
|
|
@@ -168,12 +170,12 @@ def filter_instances(
|
|
|
168
170
|
before_filter = len(instances)
|
|
169
171
|
instances = [instance for instance in instances if re.match(filter_spec, instance["instance_id"])]
|
|
170
172
|
if (after_filter := len(instances)) != before_filter:
|
|
171
|
-
|
|
173
|
+
logger.info(f"Instance filter: {before_filter} -> {after_filter} instances")
|
|
172
174
|
if slice_spec:
|
|
173
175
|
values = [int(x) if x else None for x in slice_spec.split(":")]
|
|
174
176
|
instances = instances[slice(*values)]
|
|
175
177
|
if (after_slice := len(instances)) != before_filter:
|
|
176
|
-
|
|
178
|
+
logger.info(f"Instance slice: {before_filter} -> {after_slice} instances")
|
|
177
179
|
return instances
|
|
178
180
|
|
|
179
181
|
|
|
@@ -193,20 +195,22 @@ def main(
|
|
|
193
195
|
environment_class: str | None = typer.Option( None, "--environment-class", help="Environment type to use. Recommended are docker or singularity", rich_help_panel="Advanced"),
|
|
194
196
|
) -> None:
|
|
195
197
|
# fmt: on
|
|
198
|
+
output_path = Path(output)
|
|
199
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
200
|
+
logger.info(f"Results will be saved to {output_path}")
|
|
201
|
+
add_file_handler(output_path / "minisweagent.log")
|
|
202
|
+
|
|
196
203
|
dataset_path = DATASET_MAPPING.get(subset, subset)
|
|
197
|
-
|
|
204
|
+
logger.info(f"Loading dataset {dataset_path}, split {split}...")
|
|
198
205
|
instances = list(load_dataset(dataset_path, split=split))
|
|
199
206
|
|
|
200
207
|
instances = filter_instances(instances, filter_spec=filter_spec, slice_spec=slice_spec, shuffle=shuffle)
|
|
201
|
-
output_path = Path(output)
|
|
202
208
|
if not redo_existing and (output_path / "preds.json").exists():
|
|
203
209
|
existing_instances = list(json.loads((output_path / "preds.json").read_text()).keys())
|
|
204
|
-
|
|
210
|
+
logger.info(f"Skipping {len(existing_instances)} existing instances")
|
|
205
211
|
instances = [instance for instance in instances if instance["instance_id"] not in existing_instances]
|
|
212
|
+
logger.info(f"Running on {len(instances)} instances...")
|
|
206
213
|
|
|
207
|
-
output_path.mkdir(parents=True, exist_ok=True)
|
|
208
|
-
print(f"Running on {len(instances)} instances...")
|
|
209
|
-
print(f"Results will be saved to {output_path}")
|
|
210
214
|
|
|
211
215
|
config = yaml.safe_load(get_config_path(config_spec).read_text())
|
|
212
216
|
if environment_class is not None:
|
|
@@ -224,8 +228,7 @@ def main(
|
|
|
224
228
|
pass
|
|
225
229
|
except Exception as e:
|
|
226
230
|
instance_id = futures[future]
|
|
227
|
-
|
|
228
|
-
traceback.print_exc()
|
|
231
|
+
logger.error(f"Error in future for instance {instance_id}: {e}", exc_info=True)
|
|
229
232
|
progress_manager.on_uncaught_exception(instance_id, e)
|
|
230
233
|
|
|
231
234
|
with Live(progress_manager.render_group, refresh_per_second=4):
|
|
@@ -239,7 +242,7 @@ def main(
|
|
|
239
242
|
try:
|
|
240
243
|
process_futures(futures)
|
|
241
244
|
except KeyboardInterrupt:
|
|
242
|
-
|
|
245
|
+
logger.info("Cancelling all pending jobs. Press ^C again to exit immediately.")
|
|
243
246
|
for future in futures:
|
|
244
247
|
if not future.running() and not future.done():
|
|
245
248
|
future.cancel()
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"""Run on a single SWE-Bench instance."""
|
|
2
2
|
|
|
3
|
+
import traceback
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
import typer
|
|
6
7
|
import yaml
|
|
7
8
|
from datasets import load_dataset
|
|
8
9
|
|
|
10
|
+
from minisweagent import global_config_dir
|
|
9
11
|
from minisweagent.agents.interactive import InteractiveAgent
|
|
10
12
|
from minisweagent.config import builtin_config_dir, get_config_path
|
|
11
13
|
from minisweagent.models import get_model
|
|
@@ -13,9 +15,13 @@ from minisweagent.run.extra.swebench import (
|
|
|
13
15
|
DATASET_MAPPING,
|
|
14
16
|
get_sb_environment,
|
|
15
17
|
)
|
|
18
|
+
from minisweagent.run.utils.save import save_traj
|
|
19
|
+
from minisweagent.utils.log import logger
|
|
16
20
|
|
|
17
21
|
app = typer.Typer(add_completion=False)
|
|
18
22
|
|
|
23
|
+
DEFAULT_OUTPUT = global_config_dir / "last_swebench_single_run.traj.json"
|
|
24
|
+
|
|
19
25
|
|
|
20
26
|
# fmt: off
|
|
21
27
|
@app.command()
|
|
@@ -27,11 +33,12 @@ def main(
|
|
|
27
33
|
config_path: Path = typer.Option( builtin_config_dir / "extra" / "swebench.yaml", "-c", "--config", help="Path to a config file", rich_help_panel="Basic"),
|
|
28
34
|
environment_class: str | None = typer.Option(None, "--environment-class", rich_help_panel="Advanced"),
|
|
29
35
|
exit_immediately: bool = typer.Option( False, "--exit-immediately", help="Exit immediately when the agent wants to finish instead of prompting.", rich_help_panel="Basic"),
|
|
36
|
+
output: Path = typer.Option(DEFAULT_OUTPUT, "-o", "--output", help="Output trajectory file", rich_help_panel="Basic"),
|
|
30
37
|
) -> None:
|
|
31
38
|
# fmt: on
|
|
32
39
|
"""Run on a single SWE-Bench instance."""
|
|
33
40
|
dataset_path = DATASET_MAPPING.get(subset, subset)
|
|
34
|
-
|
|
41
|
+
logger.info(f"Loading dataset from {dataset_path}, split {split}...")
|
|
35
42
|
instances = {
|
|
36
43
|
inst["instance_id"]: inst # type: ignore
|
|
37
44
|
for inst in load_dataset(dataset_path, split=split)
|
|
@@ -51,7 +58,16 @@ def main(
|
|
|
51
58
|
env,
|
|
52
59
|
**({"mode": "yolo"} | config.get("agent", {})),
|
|
53
60
|
)
|
|
54
|
-
|
|
61
|
+
|
|
62
|
+
exit_status, result, extra_info = None, None, None
|
|
63
|
+
try:
|
|
64
|
+
exit_status, result = agent.run(instance["problem_statement"]) # type: ignore[arg-type]
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(f"Error processing instance {instance_spec}: {e}", exc_info=True)
|
|
67
|
+
exit_status, result = type(e).__name__, str(e)
|
|
68
|
+
extra_info = {"traceback": traceback.format_exc()}
|
|
69
|
+
finally:
|
|
70
|
+
save_traj(agent, output, exit_status=exit_status, result=result, extra_info=extra_info) # type: ignore[arg-type]
|
|
55
71
|
|
|
56
72
|
|
|
57
73
|
if __name__ == "__main__":
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# Read this first: https://mini-swe-agent.com/latest/usage/mini/ (usage)
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
+
import traceback
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
@@ -22,6 +23,7 @@ from minisweagent.environments.local import LocalEnvironment
|
|
|
22
23
|
from minisweagent.models import get_model
|
|
23
24
|
from minisweagent.run.extra.config import configure_if_first_time
|
|
24
25
|
from minisweagent.run.utils.save import save_traj
|
|
26
|
+
from minisweagent.utils.log import logger
|
|
25
27
|
|
|
26
28
|
DEFAULT_CONFIG = Path(os.getenv("MSWEA_MINI_CONFIG_PATH", builtin_config_dir / "mini.yaml"))
|
|
27
29
|
DEFAULT_OUTPUT = global_config_dir / "last_mini_run.traj.json"
|
|
@@ -41,29 +43,19 @@ More information about the usage: [bold green]https://mini-swe-agent.com/latest/
|
|
|
41
43
|
"""
|
|
42
44
|
|
|
43
45
|
|
|
46
|
+
# fmt: off
|
|
44
47
|
@app.command(help=_HELP_TEXT)
|
|
45
48
|
def main(
|
|
46
|
-
visual: bool = typer.Option(
|
|
47
|
-
|
|
48
|
-
"-v",
|
|
49
|
-
"--visual",
|
|
50
|
-
help="Toggle (pager-style) UI (Textual) depending on the MSWEA_VISUAL_MODE_DEFAULT environment setting",
|
|
51
|
-
),
|
|
52
|
-
model_name: str | None = typer.Option(
|
|
53
|
-
None,
|
|
54
|
-
"-m",
|
|
55
|
-
"--model",
|
|
56
|
-
help="Model to use",
|
|
57
|
-
),
|
|
49
|
+
visual: bool = typer.Option(False, "-v", "--visual", help="Toggle (pager-style) UI (Textual) depending on the MSWEA_VISUAL_MODE_DEFAULT environment setting",),
|
|
50
|
+
model_name: str | None = typer.Option( None, "-m", "--model", help="Model to use",),
|
|
58
51
|
task: str | None = typer.Option(None, "-t", "--task", help="Task/problem statement", show_default=False),
|
|
59
52
|
yolo: bool = typer.Option(False, "-y", "--yolo", help="Run without confirmation"),
|
|
60
53
|
cost_limit: float | None = typer.Option(None, "-l", "--cost-limit", help="Cost limit. Set to 0 to disable."),
|
|
61
54
|
config_spec: Path = typer.Option(DEFAULT_CONFIG, "-c", "--config", help="Path to config file"),
|
|
62
55
|
output: Path | None = typer.Option(DEFAULT_OUTPUT, "-o", "--output", help="Output trajectory file"),
|
|
63
|
-
exit_immediately: bool = typer.Option(
|
|
64
|
-
False, "--exit-immediately", help="Exit immediately when the agent wants to finish instead of prompting."
|
|
65
|
-
),
|
|
56
|
+
exit_immediately: bool = typer.Option( False, "--exit-immediately", help="Exit immediately when the agent wants to finish instead of prompting."),
|
|
66
57
|
) -> Any:
|
|
58
|
+
# fmt: on
|
|
67
59
|
configure_if_first_time()
|
|
68
60
|
config = yaml.safe_load(get_config_path(config_spec).read_text())
|
|
69
61
|
|
|
@@ -92,13 +84,18 @@ def main(
|
|
|
92
84
|
agent_class = InteractiveAgent
|
|
93
85
|
if visual == (os.getenv("MSWEA_VISUAL_MODE_DEFAULT", "false") == "false"):
|
|
94
86
|
agent_class = TextualAgent
|
|
95
|
-
|
|
87
|
+
|
|
96
88
|
agent = agent_class(model, env, **config.get("agent", {}))
|
|
89
|
+
exit_status, result, extra_info = None, None, None
|
|
97
90
|
try:
|
|
98
91
|
exit_status, result = agent.run(task) # type: ignore[arg-type]
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Error running agent: {e}", exc_info=True)
|
|
94
|
+
exit_status, result = type(e).__name__, str(e)
|
|
95
|
+
extra_info = {"traceback": traceback.format_exc()}
|
|
99
96
|
finally:
|
|
100
97
|
if output:
|
|
101
|
-
save_traj(agent, output, exit_status=exit_status, result=result) # type: ignore[arg-type]
|
|
98
|
+
save_traj(agent, output, exit_status=exit_status, result=result, extra_info=extra_info) # type: ignore[arg-type]
|
|
102
99
|
return agent
|
|
103
100
|
|
|
104
101
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from collections.abc import Callable
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
4
5
|
from minisweagent import Agent, __version__
|
|
@@ -12,6 +13,7 @@ def save_traj(
|
|
|
12
13
|
exit_status: str | None = None,
|
|
13
14
|
result: str | None = None,
|
|
14
15
|
extra_info: dict | None = None,
|
|
16
|
+
print_fct: Callable = print,
|
|
15
17
|
**kwargs,
|
|
16
18
|
):
|
|
17
19
|
"""Save the trajectory of the agent to a file.
|
|
@@ -49,4 +51,4 @@ def save_traj(
|
|
|
49
51
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
50
52
|
path.write_text(json.dumps(data, indent=2))
|
|
51
53
|
if print_path:
|
|
52
|
-
|
|
54
|
+
print_fct(f"Saved trajectory to '{path}'")
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from rich.logging import RichHandler
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _setup_root_logger() -> None:
|
|
8
|
+
logger = logging.getLogger("minisweagent")
|
|
9
|
+
logger.setLevel(logging.DEBUG)
|
|
10
|
+
_handler = RichHandler(
|
|
11
|
+
show_path=False,
|
|
12
|
+
show_time=False,
|
|
13
|
+
show_level=False,
|
|
14
|
+
markup=True,
|
|
15
|
+
)
|
|
16
|
+
_formatter = logging.Formatter("%(name)s: %(levelname)s: %(message)s")
|
|
17
|
+
_handler.setFormatter(_formatter)
|
|
18
|
+
logger.addHandler(_handler)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def add_file_handler(path: Path | str, level: int = logging.DEBUG, *, print_path: bool = True) -> None:
|
|
22
|
+
logger = logging.getLogger("minisweagent")
|
|
23
|
+
handler = logging.FileHandler(path)
|
|
24
|
+
handler.setLevel(level)
|
|
25
|
+
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
26
|
+
handler.setFormatter(formatter)
|
|
27
|
+
logger.addHandler(handler)
|
|
28
|
+
if print_path:
|
|
29
|
+
print(f"Logging to '{path}'")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_setup_root_logger()
|
|
33
|
+
logger = logging.getLogger("minisweagent")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = ["logger"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/mini_swe_agent.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/environments/extra/__init__.py
RENAMED
|
File without changes
|
|
@@ -63,10 +63,10 @@ def get_model_name(input_model_name: str | None = None, config: dict | None = No
|
|
|
63
63
|
config = {}
|
|
64
64
|
if input_model_name:
|
|
65
65
|
return input_model_name
|
|
66
|
-
if from_env := os.getenv("MSWEA_MODEL_NAME"):
|
|
67
|
-
return from_env
|
|
68
66
|
if from_config := config.get("model_name"):
|
|
69
67
|
return from_config
|
|
68
|
+
if from_env := os.getenv("MSWEA_MODEL_NAME"):
|
|
69
|
+
return from_env
|
|
70
70
|
raise ValueError("No default model set. Please run `mini-extra config setup` to set one.")
|
|
71
71
|
|
|
72
72
|
|
|
File without changes
|
|
File without changes
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/utils/cache_control.py
RENAMED
|
File without changes
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/models/utils/key_per_thread.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mini_swe_agent-1.8.1 → mini_swe_agent-1.9.1}/src/minisweagent/run/extra/utils/batch_progress.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|