| 1 | #!/usr/bin/env python3
|
| 2 |
|
| 3 | """Utility to manage the global config file.
|
| 4 |
|
| 5 | You can also directly edit the `.env` file in the config directory.
|
| 6 |
|
| 7 | It is located at [bold green]{global_config_file}[/bold green].
|
| 8 | """
|
| 9 |
|
| 10 | import os
|
| 11 | import subprocess
|
| 12 |
|
| 13 | from dotenv import set_key, unset_key
|
| 14 | from prompt_toolkit import prompt
|
| 15 | from rich.console import Console
|
| 16 | from rich.rule import Rule
|
| 17 | from typer import Argument, Typer
|
| 18 |
|
| 19 | from minisweagent import global_config_file
|
| 20 |
|
| 21 | app = Typer(
|
| 22 | help=__doc__.format(global_config_file=global_config_file), # type: ignore
|
| 23 | no_args_is_help=True,
|
| 24 | rich_markup_mode="rich",
|
| 25 | add_completion=False,
|
| 26 | )
|
| 27 | console = Console(highlight=False)
|
| 28 |
|
| 29 |
|
| 30 | _SETUP_HELP = """To get started, we need to set up your global config file.
|
| 31 |
|
| 32 | 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 |
|
| 34 | This setup will ask you for your model and an API key.
|
| 35 |
|
| 36 | Here's a few popular models and the required API keys:
|
| 37 |
|
| 38 | [bold green]anthropic/claude-sonnet-4-5-20250929[/bold green] ([bold green]ANTHROPIC_API_KEY[/bold green])
|
| 39 | [bold green]openai/gpt-5[/bold green] or [bold green]openai/gpt-5-mini[/bold green] ([bold green]OPENAI_API_KEY[/bold green])
|
| 40 | [bold green]gemini/gemini-3-pro-preview[/bold green] ([bold green]GEMINI_API_KEY[/bold green])
|
| 41 |
|
| 42 | [bold]Note: Please always include the provider (e.g., "openai/") in the model name.[/bold]
|
| 43 |
|
| 44 | [bold yellow]You can leave any setting blank to skip it.[/bold yellow]
|
| 45 |
|
| 46 | More information at https://mini-swe-agent.com/latest/quickstart/
|
| 47 | To find the best model, check the leaderboard at https://swebench.com/
|
| 48 | """
|
| 49 |
|
| 50 |
|
| 51 | def configure_if_first_time():
|
| 52 | if not os.getenv("MSWEA_CONFIGURED"):
|
| 53 | console.print(Rule())
|
| 54 | setup()
|
| 55 | console.print(Rule())
|
| 56 |
|
| 57 |
|
| 58 | @app.command()
|
| 59 | def setup():
|
| 60 | """Setup the global config file."""
|
| 61 | console.print(_SETUP_HELP.format(global_config_file=global_config_file))
|
| 62 | default_model = prompt(
|
| 63 | "Enter your default model (e.g., anthropic/claude-sonnet-4-5-20250929): ",
|
| 64 | default=os.getenv("MSWEA_MODEL_NAME", ""),
|
| 65 | ).strip()
|
| 66 | if default_model:
|
| 67 | set_key(global_config_file, "MSWEA_MODEL_NAME", default_model)
|
| 68 | console.print(
|
| 69 | "[bold yellow]If you already have your API keys set as environment variables, you can ignore the next question.[/bold yellow]"
|
| 70 | )
|
| 71 | key_name = prompt("Enter your API key name (e.g., ANTHROPIC_API_KEY): ").strip()
|
| 72 | key_value = None
|
| 73 | if key_name:
|
| 74 | key_value = prompt("Enter your API key value (e.g., sk-1234567890): ", default=os.getenv(key_name, "")).strip()
|
| 75 | if key_value:
|
| 76 | set_key(global_config_file, key_name, key_value)
|
| 77 | if not key_value:
|
| 78 | console.print(
|
| 79 | "[bold red]API key setup not completed.[/bold red] Totally fine if you have your keys as environment variables."
|
| 80 | )
|
| 81 | set_key(global_config_file, "MSWEA_CONFIGURED", "true")
|
| 82 | console.print(
|
| 83 | "\n[bold yellow]Config finished.[/bold yellow] If you want to revisit it, run [bold green]mini-extra config setup[/bold green]."
|
| 84 | )
|
| 85 |
|
| 86 |
|
| 87 | @app.command()
|
| 88 | def set(
|
| 89 | key: str | None = Argument(None, help="The key to set"),
|
| 90 | value: str | None = Argument(None, help="The value to set"),
|
| 91 | ):
|
| 92 | """Set a key in the global config file."""
|
| 93 | if key is None:
|
| 94 | key = prompt("Enter the key to set: ")
|
| 95 | if value is None:
|
| 96 | value = prompt(f"Enter the value for {key}: ")
|
| 97 | set_key(global_config_file, key, value)
|
| 98 |
|
| 99 |
|
| 100 | @app.command()
|
| 101 | def unset(key: str | None = Argument(None, help="The key to unset")):
|
| 102 | """Unset a key in the global config file."""
|
| 103 | if key is None:
|
| 104 | key = prompt("Enter the key to unset: ")
|
| 105 | unset_key(global_config_file, key)
|
| 106 |
|
| 107 |
|
| 108 | @app.command()
|
| 109 | def edit():
|
| 110 | """Edit the global config file."""
|
| 111 | editor = os.getenv("EDITOR", "nano")
|
| 112 | subprocess.run([editor, global_config_file])
|
| 113 |
|
| 114 |
|
| 115 | if __name__ == "__main__":
|
| 116 | app()
|
| 117 |
|