From 2ff6ae5212daf3da20ba9aba05de0ce75a9f4357 Mon Sep 17 00:00:00 2001 From: Eric Hare Date: Thu, 9 Apr 2026 11:18:55 -0700 Subject: [PATCH] fix: Don't update the model selection when changing key (#12596) * fix: Don't update the model selection when changing key * Add a test for this behavior --- src/backend/tests/unit/test_unified_models.py | 44 +++++++++++++++++++ .../models/unified_models/build_config.py | 10 +++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/backend/tests/unit/test_unified_models.py b/src/backend/tests/unit/test_unified_models.py index eb4d6b6e33..424676e39b 100644 --- a/src/backend/tests/unit/test_unified_models.py +++ b/src/backend/tests/unit/test_unified_models.py @@ -741,6 +741,50 @@ def test_handle_model_input_update_returns_dict(): assert isinstance(result, dict) +def test_handle_model_input_update_api_key_change_preserves_model_selection(): + """Changing the api_key field must NOT reset the selected model value. + + Regression test: previously, the default-model logic checked ``field_value`` + (the api_key text) instead of the model field's own value. When the api_key + was empty or falsy (e.g. selecting a global variable), the model was + incorrectly reset to the first option. + """ + component = _make_mock_component() + selected_model = [{"name": "gpt-4o", "provider": "OpenAI", "metadata": {}}] + options = [ + {"name": "claude-3-opus", "provider": "Anthropic", "metadata": {}}, + {"name": "gpt-4o", "provider": "OpenAI", "metadata": {}}, + ] + build_config = { + "model": _make_model_field(value=selected_model, options=options), + "api_key": {"show": True, "required": True, "value": "old-key"}, + } + + # Simulate typing a new api_key (non-empty field_value) + result = handle_model_input_update( + component, + build_config, + field_value="sk-new-key", + field_name="api_key", + get_options_func=lambda user_id=None: options, # noqa: ARG005 + ) + assert result["model"]["value"] == selected_model, "Model should be preserved when api_key is non-empty" + + # Simulate clearing the api_key / selecting a global variable (empty field_value) + build_config2 = { + "model": _make_model_field(value=selected_model, options=options), + "api_key": {"show": True, "required": True, "value": ""}, + } + result2 = handle_model_input_update( + component, + build_config2, + field_value="", + field_name="api_key", + get_options_func=lambda user_id=None: options, # noqa: ARG005 + ) + assert result2["model"]["value"] == selected_model, "Model should be preserved even when api_key is empty" + + def test_handle_model_input_update_custom_model_field_name(): """handle_model_input_update should support a custom model_field_name.""" component = _make_mock_component() diff --git a/src/lfx/src/lfx/base/models/unified_models/build_config.py b/src/lfx/src/lfx/base/models/unified_models/build_config.py index 575c5bc284..a1316d704f 100644 --- a/src/lfx/src/lfx/base/models/unified_models/build_config.py +++ b/src/lfx/src/lfx/base/models/unified_models/build_config.py @@ -187,9 +187,13 @@ def update_model_options_in_build_config( cached = component.cache.get(cache_key, {"options": []}) build_config[model_field_name]["options"] = cached["options"] - # Set default value on initial load when field is empty - # Fetch from user's default model setting in the database - if not field_value or field_value == "": + # Set default value on initial load when the model field has no value. + # We check the model field's own value (not field_value, which is the value + # of whatever field triggered the update — e.g. api_key text). Using + # field_value here would incorrectly reset the model selection whenever a + # non-model field (like api_key) is cleared or set to a global variable. + current_model_value = build_config.get(model_field_name, {}).get("value") + if not current_model_value: options = cached.get("options", []) if options: # Determine model type based on cache_key_prefix