From 6558b4f97d7e9e8eae697fca95b76b945d5bffeb Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Wed, 29 Oct 2025 23:38:36 -0400 Subject: [PATCH] CLI: bump agent-sdk version (#11566) Co-authored-by: openhands --- openhands-cli/build.py | 7 +++---- openhands-cli/openhands_cli/runner.py | 1 + .../tui/settings/settings_screen.py | 6 ++---- .../openhands_cli/tui/settings/store.py | 2 +- .../openhands_cli/{llm_utils.py => utils.py} | 21 ++++++++++++++++++- openhands-cli/pyproject.toml | 4 ++-- .../tests/settings/test_settings_workflow.py | 4 ++-- .../tests/test_conversation_runner.py | 14 ++++++------- openhands-cli/uv.lock | 18 ++++++++-------- 9 files changed, 47 insertions(+), 30 deletions(-) rename openhands-cli/openhands_cli/{llm_utils.py => utils.py} (79%) diff --git a/openhands-cli/build.py b/openhands-cli/build.py index f4b3cd83b4..3b85de946a 100755 --- a/openhands-cli/build.py +++ b/openhands-cli/build.py @@ -15,13 +15,12 @@ import sys import time from pathlib import Path -from openhands_cli.llm_utils import get_llm_metadata -from openhands_cli.locations import AGENT_SETTINGS_PATH, PERSISTENCE_DIR, WORK_DIR +from openhands_cli.utils import get_llm_metadata, get_default_cli_agent +from openhands_cli.locations import AGENT_SETTINGS_PATH, PERSISTENCE_DIR from openhands.sdk import LLM -from openhands.tools.preset.default import get_default_agent -dummy_agent = get_default_agent( +dummy_agent = get_default_cli_agent( llm=LLM( model='dummy-model', api_key='dummy-key', diff --git a/openhands-cli/openhands_cli/runner.py b/openhands-cli/openhands_cli/runner.py index 816c3f4c2e..40be26c576 100644 --- a/openhands-cli/openhands_cli/runner.py +++ b/openhands-cli/openhands_cli/runner.py @@ -120,6 +120,7 @@ class ConversationRunner: else: raise Exception('Infinite loop') + def _handle_confirmation_request(self) -> UserConfirmation: """Handle confirmation request from user. diff --git a/openhands-cli/openhands_cli/tui/settings/settings_screen.py b/openhands-cli/openhands_cli/tui/settings/settings_screen.py index 35cd76e1de..983af5a39a 100644 --- a/openhands-cli/openhands_cli/tui/settings/settings_screen.py +++ b/openhands-cli/openhands_cli/tui/settings/settings_screen.py @@ -1,13 +1,11 @@ import os from openhands.sdk import LLM, BaseConversation, LocalFileStore -from openhands.sdk.security.confirmation_policy import NeverConfirm -from openhands.tools.preset.default import get_default_agent from prompt_toolkit import HTML, print_formatted_text from prompt_toolkit.shortcuts import print_container from prompt_toolkit.widgets import Frame, TextArea -from openhands_cli.llm_utils import get_llm_metadata +from openhands_cli.utils import get_llm_metadata, get_default_cli_agent from openhands_cli.locations import AGENT_SETTINGS_PATH, PERSISTENCE_DIR from openhands_cli.pt_style import COLOR_GREY from openhands_cli.tui.settings.store import AgentStore @@ -182,7 +180,7 @@ class SettingsScreen: agent = self.agent_store.load() if not agent: - agent = get_default_agent(llm=llm, cli_mode=True) + agent = get_default_cli_agent(llm=llm) agent = agent.model_copy(update={'llm': llm}) self.agent_store.save(agent) diff --git a/openhands-cli/openhands_cli/tui/settings/store.py b/openhands-cli/openhands_cli/tui/settings/store.py index 2a4f7f8321..1cd43fd74e 100644 --- a/openhands-cli/openhands_cli/tui/settings/store.py +++ b/openhands-cli/openhands_cli/tui/settings/store.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Any from fastmcp.mcp_config import MCPConfig -from openhands_cli.llm_utils import get_llm_metadata +from openhands_cli.utils import get_llm_metadata from openhands_cli.locations import ( AGENT_SETTINGS_PATH, MCP_CONFIG_FILE, diff --git a/openhands-cli/openhands_cli/llm_utils.py b/openhands-cli/openhands_cli/utils.py similarity index 79% rename from openhands-cli/openhands_cli/llm_utils.py rename to openhands-cli/openhands_cli/utils.py index 35a485575a..b5bbc44104 100644 --- a/openhands-cli/openhands_cli/llm_utils.py +++ b/openhands-cli/openhands_cli/utils.py @@ -2,7 +2,9 @@ import os from typing import Any - +from openhands.sdk.security.llm_analyzer import LLMSecurityAnalyzer +from openhands.tools.preset import get_default_agent +from openhands.sdk import LLM def get_llm_metadata( model_name: str, @@ -55,3 +57,20 @@ def get_llm_metadata( if user_id is not None: metadata['trace_user_id'] = user_id return metadata + + +def get_default_cli_agent( + llm: LLM +): + agent = get_default_agent( + llm=llm, + cli_mode=True + ) + + agent = agent.model_copy( + update={ + 'security_analyzer': LLMSecurityAnalyzer() + } + ) + + return agent diff --git a/openhands-cli/pyproject.toml b/openhands-cli/pyproject.toml index 17df247fd3..d365d98fc2 100644 --- a/openhands-cli/pyproject.toml +++ b/openhands-cli/pyproject.toml @@ -18,8 +18,8 @@ classifiers = [ # Using Git URLs for dependencies so installs from PyPI pull from GitHub # TODO: pin package versions once agent-sdk has published PyPI packages dependencies = [ - "openhands-sdk==1.0.0a3", - "openhands-tools==1.0.0a3", + "openhands-sdk==1.0.0a5", + "openhands-tools==1.0.0a5", "prompt-toolkit>=3", "typer>=0.17.4", ] diff --git a/openhands-cli/tests/settings/test_settings_workflow.py b/openhands-cli/tests/settings/test_settings_workflow.py index 891fe29ecd..940a9a802d 100644 --- a/openhands-cli/tests/settings/test_settings_workflow.py +++ b/openhands-cli/tests/settings/test_settings_workflow.py @@ -6,10 +6,10 @@ import pytest from openhands_cli.tui.settings.settings_screen import SettingsScreen from openhands_cli.tui.settings.store import AgentStore from openhands_cli.user_actions.settings_action import SettingsType +from openhands_cli.utils import get_default_cli_agent from pydantic import SecretStr from openhands.sdk import LLM, Conversation, LocalFileStore -from openhands.tools.preset.default import get_default_agent def read_json(path: Path) -> dict: @@ -30,7 +30,7 @@ def make_screen_with_conversation(model='openai/gpt-4o-mini', api_key='sk-xyz'): def seed_file(path: Path, model: str = 'openai/gpt-4o-mini', api_key: str = 'sk-old'): store = AgentStore() store.file_store = LocalFileStore(root=str(path)) - agent = get_default_agent( + agent = get_default_cli_agent( llm=LLM(model=model, api_key=SecretStr(api_key), service_id='test-service') ) store.save(agent) diff --git a/openhands-cli/tests/test_conversation_runner.py b/openhands-cli/tests/test_conversation_runner.py index 447c0edd17..cdedb3e552 100644 --- a/openhands-cli/tests/test_conversation_runner.py +++ b/openhands-cli/tests/test_conversation_runner.py @@ -6,13 +6,13 @@ from openhands_cli.runner import ConversationRunner from openhands_cli.user_actions.types import UserConfirmation from pydantic import ConfigDict, SecretStr, model_validator -from openhands.sdk import Conversation, ConversationCallbackType +from openhands.sdk import Conversation, ConversationCallbackType, LocalConversation from openhands.sdk.agent.base import AgentBase from openhands.sdk.conversation import ConversationState from openhands.sdk.conversation.state import AgentExecutionStatus from openhands.sdk.llm import LLM from openhands.sdk.security.confirmation_policy import AlwaysConfirm, NeverConfirm - +from unittest.mock import MagicMock class FakeLLM(LLM): @model_validator(mode='after') @@ -41,11 +41,11 @@ class FakeAgent(AgentBase): pass def step( - self, state: ConversationState, on_event: ConversationCallbackType + self, conversation: LocalConversation, on_event: ConversationCallbackType ) -> None: self.step_count += 1 if self.step_count == self.finish_on_step: - state.agent_status = AgentExecutionStatus.FINISHED + conversation.state.agent_status = AgentExecutionStatus.FINISHED @pytest.fixture() @@ -102,15 +102,15 @@ class TestConversationRunner: """ if final_status == AgentExecutionStatus.FINISHED: agent.finish_on_step = 1 - + # Add a mock security analyzer to enable confirmation mode - from unittest.mock import MagicMock agent.security_analyzer = MagicMock() - + convo = Conversation(agent) convo.state.agent_status = AgentExecutionStatus.WAITING_FOR_CONFIRMATION cr = ConversationRunner(convo) cr.set_confirmation_policy(AlwaysConfirm()) + with patch.object( cr, '_handle_confirmation_request', return_value=confirmation ) as mock_confirmation_request: diff --git a/openhands-cli/uv.lock b/openhands-cli/uv.lock index dc00353f9b..d24303f214 100644 --- a/openhands-cli/uv.lock +++ b/openhands-cli/uv.lock @@ -1828,7 +1828,7 @@ wheels = [ [[package]] name = "openhands" -version = "1.0.1" +version = "1.0.2" source = { editable = "." } dependencies = [ { name = "openhands-sdk" }, @@ -1855,8 +1855,8 @@ dev = [ [package.metadata] requires-dist = [ - { name = "openhands-sdk", specifier = "==1.0.0a3" }, - { name = "openhands-tools", specifier = "==1.0.0a3" }, + { name = "openhands-sdk", specifier = "==1.0.0a5" }, + { name = "openhands-tools", specifier = "==1.0.0a5" }, { name = "prompt-toolkit", specifier = ">=3" }, { name = "typer", specifier = ">=0.17.4" }, ] @@ -1879,7 +1879,7 @@ dev = [ [[package]] name = "openhands-sdk" -version = "1.0.0a3" +version = "1.0.0a5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastmcp" }, @@ -1891,14 +1891,14 @@ dependencies = [ { name = "tenacity" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7e/82/33b3e3560e259803b773eee9cb377fce63b56c4252f3036126e225171926/openhands_sdk-1.0.0a3.tar.gz", hash = "sha256:c2cf6ab2ac105d257a31fde0e502a81faa969c7e64e0b2364d0634d2ce8e93b4", size = 144940, upload-time = "2025-10-20T15:38:39.647Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/90/d40f6716641a95a61d2042f00855e0eadc0b2558167078324576cc5a3c22/openhands_sdk-1.0.0a5.tar.gz", hash = "sha256:8888d6892d58cf9b11a71fa80086156c0b6c9a0b50df6839c0a9cafffba2338c", size = 152810, upload-time = "2025-10-29T16:19:52.086Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/ab/4464d2470ef1e02334f9ade094dfefa2cfc5bb761b201663a3e4121e1892/openhands_sdk-1.0.0a3-py3-none-any.whl", hash = "sha256:c8ab45160b67e7de391211ae5607ccfdf44e39781f74d115a2a22df35a2f4311", size = 191937, upload-time = "2025-10-20T15:38:38.668Z" }, + { url = "https://files.pythonhosted.org/packages/00/6b/d3aa28019163f22f4b589ad818b83e3bea23d0a50b0c51ecc070ffdec139/openhands_sdk-1.0.0a5-py3-none-any.whl", hash = "sha256:db20272b04cf03627f9f7d1e87992078ac4ce15d188955a2962aa9e754d0af03", size = 204063, upload-time = "2025-10-29T16:19:50.684Z" }, ] [[package]] name = "openhands-tools" -version = "1.0.0a3" +version = "1.0.0a5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "bashlex" }, @@ -1910,9 +1910,9 @@ dependencies = [ { name = "openhands-sdk" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/93/53cf1a5ae97e0c23d7e024db5bbb1ba1da9855c6352cc91d6b65fc6f5e13/openhands_tools-1.0.0a3.tar.gz", hash = "sha256:2a15fff3749ee5856906ffce999fec49c8305e7f9911f05e01dbcf4ea772e385", size = 59103, upload-time = "2025-10-20T15:38:43.705Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/8d/d62bc5e6c986676363692743688f10b6a922fd24dd525e5c6e87bd6fc08e/openhands_tools-1.0.0a5.tar.gz", hash = "sha256:6c67454e612596e95c5151267659ddd3b633a5d4a1b70b348f7f913c62146562", size = 63012, upload-time = "2025-10-29T16:19:53.783Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/aa/251ce4ecd560cad295e1c81def9efadfd1009cec3b7e79bd41357c6a0670/openhands_tools-1.0.0a3-py3-none-any.whl", hash = "sha256:f4c81df682c2a1a1c0bfa450bfe25ba9de5a6a3b56d6bab90f7541bf149bb3ed", size = 78814, upload-time = "2025-10-20T15:38:42.795Z" }, + { url = "https://files.pythonhosted.org/packages/07/9d/4da48258f0af73d017b61ed3f12786fae4caccc7e7cd97d77ef2bb25f00c/openhands_tools-1.0.0a5-py3-none-any.whl", hash = "sha256:74c27e23e6adc9a0bad00e32448bd4872019ce0786474e8de2fbf2d7c0887e8e", size = 84724, upload-time = "2025-10-29T16:19:52.84Z" }, ] [[package]]