OpenHands/openhands/cli/fast_help.py
Tim O'Farrell f292f3a84d
V1 Integration (#11183)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-10-14 02:16:44 +00:00

179 lines
5.4 KiB
Python

"""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
from openhands.cli.deprecation_warning import display_deprecation_warning
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'):
display_deprecation_warning()
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'):
from openhands import get_version
print(f'OpenHands CLI version: {get_version()}')
display_deprecation_warning()
return True
return False