diff --git a/frontend_single_user/app.py b/frontend_single_user/app.py index 3668440f..ff789b94 100644 --- a/frontend_single_user/app.py +++ b/frontend_single_user/app.py @@ -382,9 +382,11 @@ def initialize_browser_settings(browser_state, session_state: SessionState): session_state.speedvsdetail = speedvsdetail session_state.model_profile = model_profile profile_markdown = _profile_models_markdown(model_profile) - return openrouter_api_key, model, speedvsdetail, model_profile, profile_markdown, "", browser_state, session_state + open_dir_visible = gr.update(visible=is_open_dir_service_running()) + return openrouter_api_key, model, speedvsdetail, model_profile, profile_markdown, "", open_dir_visible, browser_state, session_state -def update_browser_settings_callback(openrouter_api_key, model, speedvsdetail, model_profile, browser_state, session_state: SessionState): +def save_browser_settings_callback(openrouter_api_key, model, speedvsdetail, model_profile, browser_state): + """Persist current settings to BrowserState. Called on submit/retry, not on every change.""" try: settings = json.loads(browser_state) if browser_state else {} except Exception: @@ -393,13 +395,7 @@ def update_browser_settings_callback(openrouter_api_key, model, speedvsdetail, m settings["model_radio"] = model settings["speedvsdetail_radio"] = speedvsdetail settings["model_profile_radio"] = model_profile - updated_browser_state = json.dumps(settings) - session_state.openrouter_api_key = openrouter_api_key - session_state.llm_model = model - session_state.speedvsdetail = speedvsdetail - session_state.model_profile = model_profile - profile_markdown = _profile_models_markdown(model_profile) - return updated_browser_state, openrouter_api_key, model, speedvsdetail, model_profile, profile_markdown, "", session_state + return json.dumps(settings) def run_planner(submit_or_retry_button, plan_prompt, browser_state, session_state: SessionState): """ @@ -765,7 +761,7 @@ def check_api_key(session_state: SessionState): speedvsdetail_items, value=SpeedVsDetailEnum.ALL_DETAILS_BUT_SLOW, label="Speed vs Detail", - interactive=True + interactive=True ) if CONFIG.visible_llm_info: @@ -783,7 +779,7 @@ def check_api_key(session_state: SessionState): available_model_names, value=default_model_value, label="Model", - interactive=True + interactive=True ) model_profile_radio = gr.Radio( @@ -848,6 +844,10 @@ def check_api_key(session_state: SessionState): fn=clear_status, inputs=session_state, outputs=[status_markdown, session_state] + ).then( + fn=save_browser_settings_callback, + inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, browser_state], + outputs=[browser_state] ).then( fn=run_planner, inputs=[submit_btn, prompt_input, browser_state, session_state], @@ -861,6 +861,10 @@ def check_api_key(session_state: SessionState): fn=clear_status, inputs=session_state, outputs=[status_markdown, session_state] + ).then( + fn=save_browser_settings_callback, + inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, browser_state], + outputs=[browser_state] ).then( fn=run_planner, inputs=[retry_btn, prompt_input, browser_state, session_state], @@ -888,46 +892,41 @@ def check_api_key(session_state: SessionState): ) # The download file value is updated by run_planner generator outputs. - # Unified change callbacks for settings. + # Settings change callbacks — update session_state and profile display. + settings_change_inputs = [openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, session_state] + settings_change_outputs = [profile_models_markdown, active_config_markdown, session_state] + + def update_settings_on_change(openrouter_api_key, model, speedvsdetail, model_profile, session_state: SessionState): + session_state.openrouter_api_key = openrouter_api_key + session_state.llm_model = model + session_state.speedvsdetail = speedvsdetail + session_state.model_profile = model_profile + profile_markdown = _profile_models_markdown(model_profile) + return profile_markdown, "", session_state + openrouter_api_key_text.change( - fn=update_browser_settings_callback, - inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, browser_state, session_state], - outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, profile_models_markdown, active_config_markdown, session_state] - ).then( - fn=check_api_key, - inputs=[session_state], - outputs=[api_key_warning] - ) + fn=update_settings_on_change, + inputs=settings_change_inputs, + outputs=settings_change_outputs, + ).then(fn=check_api_key, inputs=[session_state], outputs=[api_key_warning]) model_radio.change( - fn=update_browser_settings_callback, - inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, browser_state, session_state], - outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, profile_models_markdown, active_config_markdown, session_state] - ).then( - fn=check_api_key, - inputs=[session_state], - outputs=[api_key_warning] - ) + fn=update_settings_on_change, + inputs=settings_change_inputs, + outputs=settings_change_outputs, + ).then(fn=check_api_key, inputs=[session_state], outputs=[api_key_warning]) speedvsdetail_radio.change( - fn=update_browser_settings_callback, - inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, browser_state, session_state], - outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, profile_models_markdown, active_config_markdown, session_state] - ).then( - fn=check_api_key, - inputs=[session_state], - outputs=[api_key_warning] - ) + fn=update_settings_on_change, + inputs=settings_change_inputs, + outputs=settings_change_outputs, + ).then(fn=check_api_key, inputs=[session_state], outputs=[api_key_warning]) model_profile_radio.change( - fn=update_browser_settings_callback, - inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, browser_state, session_state], - outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, profile_models_markdown, active_config_markdown, session_state] - ).then( - fn=check_api_key, - inputs=[session_state], - outputs=[api_key_warning] - ) + fn=update_settings_on_change, + inputs=settings_change_inputs, + outputs=settings_change_outputs, + ).then(fn=check_api_key, inputs=[session_state], outputs=[api_key_warning]) purge_button.click( fn=trigger_purge_runs, @@ -935,20 +934,18 @@ def check_api_key(session_state: SessionState): outputs=[purge_status, session_state] ) - # Initialize settings on load from persistent browser_state. - demo_text2plan.load( + # Restore settings from BrowserState when it loads from localStorage. + # We use browser_state.change instead of demo_text2plan.load because + # Gradio 6.11 has a bug where .load with outputs breaks tab switching. + browser_state.change( fn=initialize_browser_settings, inputs=[browser_state, session_state], - outputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, profile_models_markdown, active_config_markdown, browser_state, session_state] + outputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, model_profile_radio, profile_models_markdown, active_config_markdown, open_dir_btn, browser_state, session_state] ).then( fn=check_api_key, inputs=[session_state], outputs=[api_key_warning] ) - demo_text2plan.load( - fn=update_open_dir_button_visibility, - outputs=[open_dir_btn] - ) def run_app(): # print("Environment variables Gradio:\n" + get_env_as_string() + "\n\n\n")