mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 13:47:19 +08:00
fix: improve CLI help and version command performance (#10908)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
@@ -2,32 +2,24 @@
|
||||
|
||||
import sys
|
||||
|
||||
# Import only essential modules for CLI help
|
||||
# Other imports are deferred until they're actually needed
|
||||
import openhands
|
||||
import openhands.cli.suppress_warnings # noqa: F401
|
||||
from openhands.cli.gui_launcher import launch_gui_server
|
||||
from openhands.cli.main import run_cli_command
|
||||
from openhands.core.config import get_cli_parser
|
||||
from openhands.core.config.arg_utils import get_subparser
|
||||
from openhands.cli.fast_help import handle_fast_commands
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point with subcommand support and backward compatibility."""
|
||||
parser = get_cli_parser()
|
||||
|
||||
# If user only asks for --help or -h without a subcommand
|
||||
if len(sys.argv) == 2 and sys.argv[1] in ('--help', '-h'):
|
||||
# Print top-level help
|
||||
print(parser.format_help())
|
||||
|
||||
# Also print help for `cli` subcommand
|
||||
print('\n' + '=' * 80)
|
||||
print('CLI command help:\n')
|
||||
|
||||
cli_parser = get_subparser(parser, 'cli')
|
||||
print(cli_parser.format_help())
|
||||
|
||||
# Fast path for help and version commands
|
||||
if handle_fast_commands():
|
||||
sys.exit(0)
|
||||
|
||||
# Import parser only when needed - only if we're not just showing help
|
||||
from openhands.core.config import get_cli_parser
|
||||
|
||||
parser = get_cli_parser()
|
||||
|
||||
# Special case: no subcommand provided, simulate "openhands cli"
|
||||
if len(sys.argv) == 1 or (
|
||||
len(sys.argv) > 1 and sys.argv[1] not in ['cli', 'serve']
|
||||
@@ -42,8 +34,14 @@ def main():
|
||||
sys.exit(0)
|
||||
|
||||
if args.command == 'serve':
|
||||
# Import gui_launcher only when needed
|
||||
from openhands.cli.gui_launcher import launch_gui_server
|
||||
|
||||
launch_gui_server(mount_cwd=args.mount_cwd, gpu=args.gpu)
|
||||
elif args.command == 'cli' or args.command is None:
|
||||
# Import main only when needed
|
||||
from openhands.cli.main import run_cli_command
|
||||
|
||||
run_cli_command(args)
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
172
openhands/cli/fast_help.py
Normal file
172
openhands/cli/fast_help.py
Normal file
@@ -0,0 +1,172 @@
|
||||
"""Fast help module for OpenHands CLI.
|
||||
|
||||
This module provides a lightweight implementation of the CLI help and version commands
|
||||
without loading all the dependencies, which significantly improves the
|
||||
performance of `openhands --help` and `openhands --version`.
|
||||
|
||||
The approach is to create a simplified version of the CLI parser that only includes
|
||||
the necessary options for displaying help and version information. This avoids loading
|
||||
the full OpenHands codebase, which can take several seconds.
|
||||
|
||||
This implementation addresses GitHub issue #10698, which reported that
|
||||
`openhands --help` was taking around 20 seconds to run.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
def get_fast_cli_parser() -> argparse.ArgumentParser:
|
||||
"""Create a lightweight argument parser for CLI help command."""
|
||||
# Create a description with welcome message explaining available commands
|
||||
description = (
|
||||
'Welcome to OpenHands: Code Less, Make More\n\n'
|
||||
'OpenHands supports two main commands:\n'
|
||||
' serve - Launch the OpenHands GUI server (web interface)\n'
|
||||
' cli - Run OpenHands in CLI mode (terminal interface)\n\n'
|
||||
'Running "openhands" without a command is the same as "openhands cli"'
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
prog='openhands',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog='For more information about a command, run: openhands COMMAND --help',
|
||||
)
|
||||
|
||||
# Create subparsers
|
||||
subparsers = parser.add_subparsers(
|
||||
dest='command',
|
||||
title='commands',
|
||||
description='OpenHands supports two main commands:',
|
||||
metavar='COMMAND',
|
||||
)
|
||||
|
||||
# Add 'serve' subcommand
|
||||
serve_parser = subparsers.add_parser(
|
||||
'serve', help='Launch the OpenHands GUI server using Docker (web interface)'
|
||||
)
|
||||
serve_parser.add_argument(
|
||||
'--mount-cwd',
|
||||
help='Mount the current working directory into the GUI server container',
|
||||
action='store_true',
|
||||
default=False,
|
||||
)
|
||||
serve_parser.add_argument(
|
||||
'--gpu',
|
||||
help='Enable GPU support by mounting all GPUs into the Docker container via nvidia-docker',
|
||||
action='store_true',
|
||||
default=False,
|
||||
)
|
||||
|
||||
# Add 'cli' subcommand with common arguments
|
||||
cli_parser = subparsers.add_parser(
|
||||
'cli', help='Run OpenHands in CLI mode (terminal interface)'
|
||||
)
|
||||
|
||||
# Add common arguments
|
||||
cli_parser.add_argument(
|
||||
'--config-file',
|
||||
type=str,
|
||||
default='config.toml',
|
||||
help='Path to the config file (default: config.toml in the current directory)',
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'-t',
|
||||
'--task',
|
||||
type=str,
|
||||
default='',
|
||||
help='The task for the agent to perform',
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'-f',
|
||||
'--file',
|
||||
type=str,
|
||||
help='Path to a file containing the task. Overrides -t if both are provided.',
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'-n',
|
||||
'--name',
|
||||
help='Session name',
|
||||
type=str,
|
||||
default='',
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'--log-level',
|
||||
help='Set the log level',
|
||||
type=str,
|
||||
default=None,
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'-l',
|
||||
'--llm-config',
|
||||
default=None,
|
||||
type=str,
|
||||
help='Replace default LLM ([llm] section in config.toml) config with the specified LLM config, e.g. "llama3" for [llm.llama3] section in config.toml',
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'--agent-config',
|
||||
default=None,
|
||||
type=str,
|
||||
help='Replace default Agent ([agent] section in config.toml) config with the specified Agent config, e.g. "CodeAct" for [agent.CodeAct] section in config.toml',
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'-v', '--version', action='store_true', help='Show version information'
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
'--override-cli-mode',
|
||||
help='Override the default settings for CLI mode',
|
||||
type=bool,
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--conversation',
|
||||
help='The conversation id to continue',
|
||||
type=str,
|
||||
default=None,
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def get_fast_subparser(
|
||||
parser: argparse.ArgumentParser, name: str
|
||||
) -> argparse.ArgumentParser:
|
||||
"""Get a subparser by name."""
|
||||
for action in parser._actions:
|
||||
if isinstance(action, argparse._SubParsersAction):
|
||||
if name in action.choices:
|
||||
return action.choices[name]
|
||||
raise ValueError(f"Subparser '{name}' not found")
|
||||
|
||||
|
||||
def handle_fast_commands() -> bool:
|
||||
"""Handle fast path commands like help and version.
|
||||
|
||||
Returns:
|
||||
bool: True if a command was handled, False otherwise.
|
||||
"""
|
||||
# Handle --help or -h
|
||||
if len(sys.argv) == 2 and sys.argv[1] in ('--help', '-h'):
|
||||
parser = get_fast_cli_parser()
|
||||
|
||||
# Print top-level help
|
||||
print(parser.format_help())
|
||||
|
||||
# Also print help for `cli` subcommand
|
||||
print('\n' + '=' * 80)
|
||||
print('CLI command help:\n')
|
||||
|
||||
cli_parser = get_fast_subparser(parser, 'cli')
|
||||
print(cli_parser.format_help())
|
||||
|
||||
return True
|
||||
|
||||
# Handle --version or -v
|
||||
if len(sys.argv) == 2 and sys.argv[1] in ('--version', '-v'):
|
||||
import openhands
|
||||
|
||||
print(f'OpenHands CLI version: {openhands.get_version()}')
|
||||
return True
|
||||
|
||||
return False
|
||||
Reference in New Issue
Block a user