CoolFace
Apppublic

Backup-bdg/OpenHands

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
0likes
settings.py408 linesDownload Raw Back to cli
1from prompt_toolkit import PromptSession, print_formatted_text2from prompt_toolkit.completion import FuzzyWordCompleter3from prompt_toolkit.formatted_text import HTML4from prompt_toolkit.shortcuts import print_container5from prompt_toolkit.widgets import Frame, TextArea6from pydantic import SecretStr7 8from openhands.cli.tui import (9    COLOR_GREY,10    UserCancelledError,11    cli_confirm,12    kb_cancel,13)14from openhands.cli.utils import (15    VERIFIED_ANTHROPIC_MODELS,16    VERIFIED_OPENAI_MODELS,17    VERIFIED_PROVIDERS,18    organize_models_and_providers,19)20from openhands.controller.agent import Agent21from openhands.core.config import OpenHandsConfig22from openhands.core.config.condenser_config import NoOpCondenserConfig23from openhands.core.config.utils import OH_DEFAULT_AGENT24from openhands.memory.condenser.impl.llm_summarizing_condenser import (25    LLMSummarizingCondenserConfig,26)27from openhands.storage.data_models.settings import Settings28from openhands.storage.settings.file_settings_store import FileSettingsStore29from openhands.utils.llm import get_supported_llm_models30 31 32def display_settings(config: OpenHandsConfig) -> None:33    llm_config = config.get_llm_config()34    advanced_llm_settings = True if llm_config.base_url else False35 36    # Prepare labels and values based on settings37    labels_and_values = []38    if not advanced_llm_settings:39        # Attempt to determine provider, fallback if not directly available40        provider = getattr(41            llm_config,42            'provider',43            llm_config.model.split('/')[0] if '/' in llm_config.model else 'Unknown',44        )45        labels_and_values.extend(46            [47                ('   LLM Provider', str(provider)),48                ('   LLM Model', str(llm_config.model)),49                ('   API Key', '********' if llm_config.api_key else 'Not Set'),50            ]51        )52    else:53        labels_and_values.extend(54            [55                ('   Custom Model', str(llm_config.model)),56                ('   Base URL', str(llm_config.base_url)),57                ('   API Key', '********' if llm_config.api_key else 'Not Set'),58            ]59        )60 61    # Common settings62    labels_and_values.extend(63        [64            ('   Agent', str(config.default_agent)),65            (66                '   Confirmation Mode',67                'Enabled' if config.security.confirmation_mode else 'Disabled',68            ),69            (70                '   Memory Condensation',71                'Enabled' if config.enable_default_condenser else 'Disabled',72            ),73        ]74    )75 76    # Calculate max widths for alignment77    # Ensure values are strings for len() calculation78    str_labels_and_values = [(label, str(value)) for label, value in labels_and_values]79    max_label_width = (80        max(len(label) for label, _ in str_labels_and_values)81        if str_labels_and_values82        else 083    )84 85    # Construct the summary text with aligned columns86    settings_lines = [87        f'{label + ":":<{max_label_width + 1}} {value:<}'  # Changed value alignment to left (<)88        for label, value in str_labels_and_values89    ]90    settings_text = '\n'.join(settings_lines)91 92    container = Frame(93        TextArea(94            text=settings_text,95            read_only=True,96            style=COLOR_GREY,97            wrap_lines=True,98        ),99        title='Settings',100        style=f'fg:{COLOR_GREY}',101    )102 103    print_container(container)104 105 106async def get_validated_input(107    session: PromptSession,108    prompt_text: str,109    completer=None,110    validator=None,111    error_message: str = 'Input cannot be empty',112) -> str:113    session.completer = completer114    value = None115 116    while True:117        value = await session.prompt_async(prompt_text)118 119        if validator:120            is_valid = validator(value)121            if not is_valid:122                print_formatted_text('')123                print_formatted_text(HTML(f'<grey>{error_message}: {value}</grey>'))124                print_formatted_text('')125                continue126        elif not value:127            print_formatted_text('')128            print_formatted_text(HTML(f'<grey>{error_message}</grey>'))129            print_formatted_text('')130            continue131 132        break133 134    return value135 136 137def save_settings_confirmation() -> bool:138    return (139        cli_confirm(140            '\nSave new settings? (They will take effect after restart)',141            ['Yes, save', 'No, discard'],142        )143        == 0144    )145 146 147async def modify_llm_settings_basic(148    config: OpenHandsConfig, settings_store: FileSettingsStore149) -> None:150    model_list = get_supported_llm_models(config)151    organized_models = organize_models_and_providers(model_list)152 153    provider_list = list(organized_models.keys())154    verified_providers = [p for p in VERIFIED_PROVIDERS if p in provider_list]155    provider_list = [p for p in provider_list if p not in verified_providers]156    provider_list = verified_providers + provider_list157 158    provider_completer = FuzzyWordCompleter(provider_list)159    session = PromptSession(key_bindings=kb_cancel())160 161    # Set default provider - use the first available provider from the list162    provider = provider_list[0] if provider_list else 'openai'163    model = None164    api_key = None165 166    try:167        # Show the default provider but allow changing it168        print_formatted_text(169            HTML(f'\n<grey>Default provider: </grey><green>{provider}</green>')170        )171        change_provider = (172            cli_confirm(173                'Do you want to use a different provider?',174                [f'Use {provider}', 'Select another provider'],175            )176            == 1177        )178 179        if change_provider:180            # Define a validator function that prints an error message181            def provider_validator(x):182                is_valid = x in organized_models183                if not is_valid:184                    print_formatted_text(185                        HTML('<grey>Invalid provider selected: {}</grey>'.format(x))186                    )187                return is_valid188 189            provider = await get_validated_input(190                session,191                '(Step 1/3) Select LLM Provider (TAB for options, CTRL-c to cancel): ',192                completer=provider_completer,193                validator=provider_validator,194                error_message='Invalid provider selected',195            )196 197        # Make sure the provider exists in organized_models198        if provider not in organized_models:199            # If the provider doesn't exist, use the first available provider200            provider = (201                next(iter(organized_models.keys())) if organized_models else 'openai'202            )203 204        provider_models = organized_models[provider]['models']205        if provider == 'openai':206            provider_models = [207                m for m in provider_models if m not in VERIFIED_OPENAI_MODELS208            ]209            provider_models = VERIFIED_OPENAI_MODELS + provider_models210        if provider == 'anthropic':211            provider_models = [212                m for m in provider_models if m not in VERIFIED_ANTHROPIC_MODELS213            ]214            provider_models = VERIFIED_ANTHROPIC_MODELS + provider_models215 216        # Set default model to the first model in the list217        default_model = provider_models[0] if provider_models else 'gpt-4'218 219        # Show the default model but allow changing it220        print_formatted_text(221            HTML(f'\n<grey>Default model: </grey><green>{default_model}</green>')222        )223        change_model = (224            cli_confirm(225                'Do you want to use a different model?',226                [f'Use {default_model}', 'Select another model'],227            )228            == 1229        )230 231        if change_model:232            model_completer = FuzzyWordCompleter(provider_models)233 234            # Define a validator function that prints an error message235            def model_validator(x):236                is_valid = x in provider_models237                if not is_valid:238                    print_formatted_text(239                        HTML(240                            f'<grey>Invalid model selected for provider {provider}: {x}</grey>'241                        )242                    )243                return is_valid244 245            model = await get_validated_input(246                session,247                '(Step 2/3) Select LLM Model (TAB for options, CTRL-c to cancel): ',248                completer=model_completer,249                validator=model_validator,250                error_message=f'Invalid model selected for provider {provider}',251            )252        else:253            # Use the default model254            model = default_model255 256        api_key = await get_validated_input(257            session,258            '(Step 3/3) Enter API Key (CTRL-c to cancel): ',259            error_message='API Key cannot be empty',260        )261 262    except (263        UserCancelledError,264        KeyboardInterrupt,265        EOFError,266    ):267        return  # Return on exception268 269    # The try-except block above ensures we either have valid inputs or we've already returned270    # No need to check for None values here271 272    save_settings = save_settings_confirmation()273 274    if not save_settings:275        return276 277    llm_config = config.get_llm_config()278    llm_config.model = f'{provider}{organized_models[provider]["separator"]}{model}'279    llm_config.api_key = SecretStr(api_key)280    llm_config.base_url = None281    config.set_llm_config(llm_config)282 283    config.default_agent = OH_DEFAULT_AGENT284    config.enable_default_condenser = True285 286    agent_config = config.get_agent_config(config.default_agent)287    agent_config.condenser = LLMSummarizingCondenserConfig(288        llm_config=llm_config,289        type='llm',290    )291    config.set_agent_config(agent_config, config.default_agent)292 293    settings = await settings_store.load()294    if not settings:295        settings = Settings()296 297    settings.llm_model = f'{provider}{organized_models[provider]["separator"]}{model}'298    settings.llm_api_key = SecretStr(api_key)299    settings.llm_base_url = None300    settings.agent = OH_DEFAULT_AGENT301    settings.enable_default_condenser = True302 303    await settings_store.store(settings)304 305 306async def modify_llm_settings_advanced(307    config: OpenHandsConfig, settings_store: FileSettingsStore308) -> None:309    session = PromptSession(key_bindings=kb_cancel())310 311    custom_model = None312    base_url = None313    api_key = None314    agent = None315 316    try:317        custom_model = await get_validated_input(318            session,319            '(Step 1/6) Custom Model (CTRL-c to cancel): ',320            error_message='Custom Model cannot be empty',321        )322 323        base_url = await get_validated_input(324            session,325            '(Step 2/6) Base URL (CTRL-c to cancel): ',326            error_message='Base URL cannot be empty',327        )328 329        api_key = await get_validated_input(330            session,331            '(Step 3/6) API Key (CTRL-c to cancel): ',332            error_message='API Key cannot be empty',333        )334 335        agent_list = Agent.list_agents()336        agent_completer = FuzzyWordCompleter(agent_list)337        agent = await get_validated_input(338            session,339            '(Step 4/6) Agent (TAB for options, CTRL-c to cancel): ',340            completer=agent_completer,341            validator=lambda x: x in agent_list,342            error_message='Invalid agent selected',343        )344 345        enable_confirmation_mode = (346            cli_confirm(347                question='(Step 5/6) Confirmation Mode (CTRL-c to cancel):',348                choices=['Enable', 'Disable'],349            )350            == 0351        )352 353        enable_memory_condensation = (354            cli_confirm(355                question='(Step 6/6) Memory Condensation (CTRL-c to cancel):',356                choices=['Enable', 'Disable'],357            )358            == 0359        )360 361    except (362        UserCancelledError,363        KeyboardInterrupt,364        EOFError,365    ):366        return  # Return on exception367 368    # The try-except block above ensures we either have valid inputs or we've already returned369    # No need to check for None values here370 371    save_settings = save_settings_confirmation()372 373    if not save_settings:374        return375 376    llm_config = config.get_llm_config()377    llm_config.model = custom_model378    llm_config.base_url = base_url379    llm_config.api_key = SecretStr(api_key)380    config.set_llm_config(llm_config)381 382    config.default_agent = agent383 384    config.security.confirmation_mode = enable_confirmation_mode385 386    agent_config = config.get_agent_config(config.default_agent)387    if enable_memory_condensation:388        agent_config.condenser = LLMSummarizingCondenserConfig(389            llm_config=llm_config,390            type='llm',391        )392    else:393        agent_config.condenser = NoOpCondenserConfig(type='noop')394    config.set_agent_config(agent_config)395 396    settings = await settings_store.load()397    if not settings:398        settings = Settings()399 400    settings.llm_model = custom_model401    settings.llm_api_key = SecretStr(api_key)402    settings.llm_base_url = base_url403    settings.agent = agent404    settings.confirmation_mode = enable_confirmation_mode405    settings.enable_default_condenser = enable_memory_condensation406 407    await settings_store.store(settings)408