| 1 | #!/usr/bin/env python3
|
| 2 |
|
| 3 | """Run mini-SWE-agent in your local environment. This is the default executable `mini`."""
|
| 4 | # Read this first: https://mini-swe-agent.com/latest/usage/mini/ (usage)
|
| 5 |
|
| 6 | import os
|
| 7 | from pathlib import Path
|
| 8 | from typing import Any
|
| 9 |
|
| 10 | import typer
|
| 11 | from rich.console import Console
|
| 12 |
|
| 13 | from minisweagent import global_config_dir
|
| 14 | from minisweagent.agents.interactive import InteractiveAgent, _multiline_prompt
|
| 15 | from minisweagent.config import builtin_config_dir, get_config_from_spec
|
| 16 | from minisweagent.environments.local import LocalEnvironment
|
| 17 | from minisweagent.models import get_model
|
| 18 | from minisweagent.run.utilities.config import configure_if_first_time
|
| 19 | from minisweagent.utils.serialize import UNSET, recursive_merge
|
| 20 |
|
| 21 | DEFAULT_CONFIG_FILE = Path(os.getenv("MSWEA_MINI_CONFIG_PATH", builtin_config_dir / "mini.yaml"))
|
| 22 | DEFAULT_OUTPUT_FILE = global_config_dir / "last_mini_run.traj.json"
|
| 23 |
|
| 24 |
|
| 25 | _HELP_TEXT = """Run mini-SWE-agent in your local environment.
|
| 26 |
|
| 27 | [not dim]
|
| 28 | More information about the usage: [bold green]https://mini-swe-agent.com/latest/usage/mini/[/bold green]
|
| 29 | [/not dim]
|
| 30 | """
|
| 31 |
|
| 32 | _CONFIG_SPEC_HELP_TEXT = """Path to config files, filenames, or key-value pairs.
|
| 33 |
|
| 34 | [bold red]IMPORTANT:[/bold red] [red]If you set this option, the default config file will not be used.[/red]
|
| 35 | So you need to explicitly set it e.g., with [bold green]-c mini.yaml <other options>[/bold green]
|
| 36 |
|
| 37 | Multiple configs will be recursively merged.
|
| 38 |
|
| 39 | Examples:
|
| 40 |
|
| 41 | [bold red]-c model.model_kwargs.temperature=0[/bold red] [red]You forgot to add the default config file! See above.[/red]
|
| 42 |
|
| 43 | [bold green]-c mini.yaml -c model.model_kwargs.temperature=0.5[/bold green]
|
| 44 |
|
| 45 | [bold green]-c swebench.yaml agent.mode=yolo[/bold green]
|
| 46 | """
|
| 47 |
|
| 48 | console = Console(highlight=False)
|
| 49 | app = typer.Typer(rich_markup_mode="rich")
|
| 50 |
|
| 51 |
|
| 52 | # fmt: off
|
| 53 | @app.command(help=_HELP_TEXT)
|
| 54 | def main(
|
| 55 | model_name: str | None = typer.Option(None, "-m", "--model", help="Model to use",),
|
| 56 | model_class: str | None = typer.Option(None, "--model-class", help="Model class to use (e.g., 'anthropic' or 'minisweagent.models.anthropic.AnthropicModel')", rich_help_panel="Advanced"),
|
| 57 | task: str | None = typer.Option(None, "-t", "--task", help="Task/problem statement", show_default=False),
|
| 58 | yolo: bool = typer.Option(False, "-y", "--yolo", help="Run without confirmation"),
|
| 59 | cost_limit: float | None = typer.Option(None, "-l", "--cost-limit", help="Cost limit. Set to 0 to disable."),
|
| 60 | config_spec: list[str] = typer.Option([str(DEFAULT_CONFIG_FILE)], "-c", "--config", help=_CONFIG_SPEC_HELP_TEXT),
|
| 61 | output: Path | None = typer.Option(DEFAULT_OUTPUT_FILE, "-o", "--output", help="Output trajectory file"),
|
| 62 | exit_immediately: bool = typer.Option(False, "--exit-immediately", help="Exit immediately when the agent wants to finish instead of prompting.", rich_help_panel="Advanced"),
|
| 63 | ) -> Any:
|
| 64 | # fmt: on
|
| 65 | configure_if_first_time()
|
| 66 |
|
| 67 | # Build the config from the command line arguments
|
| 68 | console.print(f"Building agent config from specs: [bold green]{config_spec}[/bold green]")
|
| 69 | configs = [get_config_from_spec(spec) for spec in config_spec]
|
| 70 | configs.append({
|
| 71 | "agent": {
|
| 72 | "mode": "yolo" if yolo else UNSET,
|
| 73 | "cost_limit": cost_limit or UNSET,
|
| 74 | "confirm_exit": False if exit_immediately else UNSET,
|
| 75 | "output_path": output or UNSET,
|
| 76 | },
|
| 77 | "model": {
|
| 78 | "model_class": model_class or UNSET,
|
| 79 | "model_name": model_name or UNSET,
|
| 80 | },
|
| 81 | })
|
| 82 | config = recursive_merge(*configs)
|
| 83 |
|
| 84 | if not task:
|
| 85 | console.print("[bold yellow]What do you want to do?")
|
| 86 | task = _multiline_prompt()
|
| 87 | console.print("[bold green]Got that, thanks![/bold green]")
|
| 88 |
|
| 89 | model = get_model(config=config.get("model", {}))
|
| 90 | env = LocalEnvironment(**config.get("environment", {}))
|
| 91 | agent = InteractiveAgent(model, env, **config.get("agent", {}))
|
| 92 | agent.run(task) # type: ignore[arg-type]
|
| 93 | if output:
|
| 94 | console.print(f"Saved trajectory to [bold green]'{output}'[/bold green]")
|
| 95 | return agent
|
| 96 |
|
| 97 |
|
| 98 | if __name__ == "__main__":
|
| 99 | app()
|
| 100 |
|