diff --git a/openhands-cli/openhands_cli/tui/settings/settings_screen.py b/openhands-cli/openhands_cli/tui/settings/settings_screen.py index 4822555539..0f6799ed3d 100644 --- a/openhands-cli/openhands_cli/tui/settings/settings_screen.py +++ b/openhands-cli/openhands_cli/tui/settings/settings_screen.py @@ -1,6 +1,6 @@ import os -from openhands.sdk import LLM, BaseConversation, LocalFileStore +from openhands.sdk import LLM, BaseConversation, LLMSummarizingCondenser, LocalFileStore from prompt_toolkit import HTML, print_formatted_text from prompt_toolkit.shortcuts import print_container from prompt_toolkit.widgets import Frame, TextArea @@ -182,7 +182,14 @@ class SettingsScreen: if not agent: agent = get_default_cli_agent(llm=llm) + # Must update all LLMs agent = agent.model_copy(update={'llm': llm}) + condenser = LLMSummarizingCondenser( + llm=llm.model_copy( + update={"usage_id": "condenser"} + ) + ) + agent = agent.model_copy(update={'condenser': condenser}) self.agent_store.save(agent) def _save_advanced_settings( diff --git a/openhands-cli/tests/settings/test_settings_workflow.py b/openhands-cli/tests/settings/test_settings_workflow.py index 192938380e..157b3cddad 100644 --- a/openhands-cli/tests/settings/test_settings_workflow.py +++ b/openhands-cli/tests/settings/test_settings_workflow.py @@ -121,6 +121,38 @@ def test_update_existing_settings_workflow(tmp_path: Path): assert True # If we get here, the workflow completed successfully +def test_all_llms_in_agent_are_updated(): + """Test that modifying LLM settings creates multiple LLMs with same API key but different usage_ids.""" + # Create a screen with existing agent settings + screen = SettingsScreen(conversation=None) + initial_llm = LLM(model='openai/gpt-3.5-turbo', api_key=SecretStr('sk-initial'), usage_id='test-service') + initial_agent = get_default_cli_agent(llm=initial_llm) + + # Mock the agent store to return the initial agent and capture the save call + with ( + patch.object(screen.agent_store, 'load', return_value=initial_agent), + patch.object(screen.agent_store, 'save') as mock_save + ): + # Modify the LLM settings with new API key + screen._save_llm_settings(model='openai/gpt-4o-mini', api_key='sk-updated-123') + mock_save.assert_called_once() + + # Get the saved agent from the mock + saved_agent = mock_save.call_args[0][0] + all_llms = list(saved_agent.get_all_llms()) + assert len(all_llms) >= 2, f"Expected at least 2 LLMs, got {len(all_llms)}" + + # Verify all LLMs have the same API key + api_keys = [llm.api_key.get_secret_value() for llm in all_llms] + assert all(api_key == 'sk-updated-123' for api_key in api_keys), \ + f"Not all LLMs have the same API key: {api_keys}" + + # Verify none of the usage_id attributes match + usage_ids = [llm.usage_id for llm in all_llms] + assert len(set(usage_ids)) == len(usage_ids), \ + f"Some usage_ids are duplicated: {usage_ids}" + + @pytest.mark.parametrize( 'step_to_cancel', ['type', 'provider', 'model', 'apikey', 'save'], diff --git a/openhands-cli/uv.lock b/openhands-cli/uv.lock index 4c0ba740b9..64d56cc3b3 100644 --- a/openhands-cli/uv.lock +++ b/openhands-cli/uv.lock @@ -1828,7 +1828,7 @@ wheels = [ [[package]] name = "openhands" -version = "1.0.3" +version = "1.0.4" source = { editable = "." } dependencies = [ { name = "openhands-sdk" },