-
Notifications
You must be signed in to change notification settings - Fork 7k
Add automatic setup flow in CLI mode when settings are not found #8775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 12 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
57705f3
Add automatic setup flow in CLI mode when settings are not found
openhands-agent 001986c
Move inline imports to the top of the file
openhands-agent 980171e
Ensure CLI exits after settings are modified with success message
openhands-agent 9adbff4
Set Anthropic and claude-sonnet-4-20250514 as default provider and model
openhands-agent 7319bc3
Apply suggestions from code review
rbren 37e74af
simplify options
rbren 928188e
Show ASCII art banner before setup flow
openhands-agent 82b7275
fix default file store path
rbren bedaab7
try emoji art
rbren 486d37e
hand emojis
rbren b48cc2a
new ascii art
rbren 03a71fe
Update openhands/cli/main.py
rbren 7582d62
Update openhands/cli/settings.py
rbren f965eaf
revert tui
rbren e47e319
Merge branch 'main' into auto-setup-flow-cli-mode
rbren b4f3c54
Fix CLI tests and settings validation
openhands-agent 38d14c3
Update openhands/cli/main.py
rbren 4fd7aeb
Merge branch 'main' into auto-setup-flow-cli-mode
rbren File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import asyncio | ||
import unittest | ||
from unittest.mock import AsyncMock, MagicMock, patch | ||
|
||
from openhands.cli.main import run_setup_flow | ||
from openhands.core.config import OpenHandsConfig | ||
from openhands.storage.settings.file_settings_store import FileSettingsStore | ||
|
||
|
||
class TestCLISetupFlow(unittest.TestCase): | ||
"""Test the CLI setup flow.""" | ||
|
||
@patch('openhands.cli.settings.modify_llm_settings_basic') | ||
@patch('openhands.cli.main.print_formatted_text') | ||
async def test_run_setup_flow(self, mock_print, mock_modify_settings): | ||
"""Test that the setup flow calls the modify_llm_settings_basic function.""" | ||
# Setup | ||
config = MagicMock(spec=OpenHandsConfig) | ||
settings_store = MagicMock(spec=FileSettingsStore) | ||
mock_modify_settings.return_value = None | ||
|
||
# Mock settings_store.load to return a settings object | ||
settings = MagicMock() | ||
settings_store.load = AsyncMock(return_value=settings) | ||
|
||
# Execute | ||
result = await run_setup_flow(config, settings_store) | ||
|
||
# Verify | ||
mock_modify_settings.assert_called_once_with(config, settings_store) | ||
# Verify that print_formatted_text was called at least twice (for welcome message and instructions) | ||
self.assertGreaterEqual(mock_print.call_count, 2) | ||
# Verify that the function returns True when settings are found | ||
self.assertTrue(result) | ||
|
||
@patch('openhands.cli.main.print_formatted_text') | ||
@patch('openhands.cli.main.run_setup_flow') | ||
@patch('openhands.cli.main.FileSettingsStore.get_instance') | ||
@patch('openhands.cli.main.setup_config_from_args') | ||
@patch('openhands.cli.main.parse_arguments') | ||
async def test_main_calls_setup_flow_when_no_settings( | ||
self, | ||
mock_parse_args, | ||
mock_setup_config, | ||
mock_get_instance, | ||
mock_run_setup_flow, | ||
mock_print, | ||
): | ||
"""Test that main calls run_setup_flow when no settings are found and exits.""" | ||
# Setup | ||
mock_args = MagicMock() | ||
mock_config = MagicMock(spec=OpenHandsConfig) | ||
mock_settings_store = AsyncMock(spec=FileSettingsStore) | ||
|
||
# Settings load returns None (no settings) | ||
mock_settings_store.load = AsyncMock(return_value=None) | ||
|
||
mock_parse_args.return_value = mock_args | ||
mock_setup_config.return_value = mock_config | ||
mock_get_instance.return_value = mock_settings_store | ||
|
||
# Mock run_setup_flow to return True (settings configured successfully) | ||
mock_run_setup_flow.return_value = True | ||
|
||
# Import here to avoid circular imports during patching | ||
from openhands.cli.main import main | ||
|
||
# Execute | ||
loop = asyncio.get_event_loop() | ||
await main(loop) | ||
|
||
# Verify | ||
mock_run_setup_flow.assert_called_once_with(mock_config, mock_settings_store) | ||
# Verify that load was called once (before setup) | ||
self.assertEqual(mock_settings_store.load.call_count, 1) | ||
# Verify that print_formatted_text was called for success messages | ||
self.assertGreaterEqual(mock_print.call_count, 2) | ||
|
||
|
||
def run_async_test(coro): | ||
loop = asyncio.new_event_loop() | ||
asyncio.set_event_loop(loop) | ||
try: | ||
return loop.run_until_complete(coro) | ||
finally: | ||
loop.close() | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.