openhands 1.0.2__tar.gz → 1.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of openhands might be problematic. Click here for more details.
- {openhands-1.0.2 → openhands-1.0.3}/PKG-INFO +5 -5
- {openhands-1.0.2 → openhands-1.0.3}/README.md +2 -2
- {openhands-1.0.2 → openhands-1.0.3}/build.py +3 -4
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/gui_launcher.py +2 -2
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/pt_style.py +1 -1
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/runner.py +1 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/settings/settings_screen.py +3 -5
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/settings/store.py +1 -1
- openhands-1.0.2/openhands_cli/llm_utils.py → openhands-1.0.3/openhands_cli/utils.py +20 -1
- {openhands-1.0.2 → openhands-1.0.3}/pyproject.toml +3 -3
- openhands-1.0.3/tests/settings/test_default_agent_security_analyzer.py +104 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/settings/test_settings_workflow.py +4 -4
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_conversation_runner.py +8 -8
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_directory_separation.py +1 -1
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_gui_launcher.py +1 -1
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_mcp_config_validation.py +1 -1
- {openhands-1.0.2 → openhands-1.0.3}/uv.lock +9 -9
- {openhands-1.0.2 → openhands-1.0.3}/.gitignore +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/Makefile +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/build.sh +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/hooks/rthook_profile_imports.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands.spec +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/__init__.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/agent_chat.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/argparsers/main_parser.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/argparsers/serve_parser.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/listeners/__init__.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/listeners/loading_listener.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/listeners/pause_listener.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/locations.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/setup.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/simple_main.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/__init__.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/settings/mcp_screen.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/status.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/tui.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/tui/utils.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/user_actions/__init__.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/user_actions/agent_action.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/user_actions/exit_session.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/user_actions/settings_action.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/user_actions/types.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/openhands_cli/user_actions/utils.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/__init__.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/commands/test_confirm_command.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/commands/test_new_command.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/commands/test_status_command.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/conftest.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/settings/test_api_key_preservation.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/settings/test_first_time_user_settings.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/settings/test_settings_input.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_confirmation_mode.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_exit_session_confirmation.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_loading.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_main.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_pause_listener.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_session_prompter.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/test_tui.py +0 -0
- {openhands-1.0.2 → openhands-1.0.3}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: OpenHands CLI - Terminal User Interface for OpenHands AI Agent
|
|
5
5
|
Author-email: OpenHands Team <contact@all-hands.dev>
|
|
6
6
|
License: MIT
|
|
@@ -8,17 +8,17 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3.12
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.13
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
|
-
Requires-Dist: openhands-sdk==1.0.
|
|
12
|
-
Requires-Dist: openhands-tools==1.0.
|
|
11
|
+
Requires-Dist: openhands-sdk==1.0.0a5
|
|
12
|
+
Requires-Dist: openhands-tools==1.0.0a5
|
|
13
13
|
Requires-Dist: prompt-toolkit>=3
|
|
14
14
|
Requires-Dist: typer>=0.17.4
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
17
17
|
# OpenHands V1 CLI
|
|
18
18
|
|
|
19
|
-
A **lightweight, modern CLI** to interact with the OpenHands agent (powered by [agent-sdk](https://github.com/
|
|
19
|
+
A **lightweight, modern CLI** to interact with the OpenHands agent (powered by [agent-sdk](https://github.com/OpenHands/agent-sdk)).
|
|
20
20
|
|
|
21
|
-
The [OpenHands V0 CLI (legacy)](https://github.com/
|
|
21
|
+
The [OpenHands V0 CLI (legacy)](https://github.com/OpenHands/OpenHands/tree/main/openhands/cli) is being deprecated.
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# OpenHands V1 CLI
|
|
2
2
|
|
|
3
|
-
A **lightweight, modern CLI** to interact with the OpenHands agent (powered by [agent-sdk](https://github.com/
|
|
3
|
+
A **lightweight, modern CLI** to interact with the OpenHands agent (powered by [agent-sdk](https://github.com/OpenHands/agent-sdk)).
|
|
4
4
|
|
|
5
|
-
The [OpenHands V0 CLI (legacy)](https://github.com/
|
|
5
|
+
The [OpenHands V0 CLI (legacy)](https://github.com/OpenHands/OpenHands/tree/main/openhands/cli) is being deprecated.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -15,13 +15,12 @@ import sys
|
|
|
15
15
|
import time
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
|
-
from openhands_cli.
|
|
19
|
-
from openhands_cli.locations import AGENT_SETTINGS_PATH, PERSISTENCE_DIR
|
|
18
|
+
from openhands_cli.utils import get_llm_metadata, get_default_cli_agent
|
|
19
|
+
from openhands_cli.locations import AGENT_SETTINGS_PATH, PERSISTENCE_DIR
|
|
20
20
|
|
|
21
21
|
from openhands.sdk import LLM
|
|
22
|
-
from openhands.tools.preset.default import get_default_agent
|
|
23
22
|
|
|
24
|
-
dummy_agent =
|
|
23
|
+
dummy_agent = get_default_cli_agent(
|
|
25
24
|
llm=LLM(
|
|
26
25
|
model='dummy-model',
|
|
27
26
|
api_key='dummy-key',
|
|
@@ -104,8 +104,8 @@ def launch_gui_server(mount_cwd: bool = False, gpu: bool = False) -> None:
|
|
|
104
104
|
|
|
105
105
|
# Get the current version for the Docker image
|
|
106
106
|
version = get_openhands_version()
|
|
107
|
-
runtime_image = f'docker.all-hands.dev/
|
|
108
|
-
app_image = f'docker.all-hands.dev/
|
|
107
|
+
runtime_image = f'docker.all-hands.dev/openhands/runtime:{version}-nikolaik'
|
|
108
|
+
app_image = f'docker.all-hands.dev/openhands/openhands:{version}'
|
|
109
109
|
|
|
110
110
|
print_formatted_text(HTML('<grey>Pulling required Docker images...</grey>'))
|
|
111
111
|
|
|
@@ -20,7 +20,7 @@ def get_cli_style() -> BaseStyle:
|
|
|
20
20
|
'prompt': f'{COLOR_GOLD} bold',
|
|
21
21
|
# Ensure good contrast for fuzzy matches on the selected completion row
|
|
22
22
|
# across terminals/themes (e.g., Ubuntu GNOME, Alacritty, Kitty).
|
|
23
|
-
# See https://github.com/
|
|
23
|
+
# See https://github.com/OpenHands/OpenHands/issues/10330
|
|
24
24
|
'completion-menu.completion.current fuzzymatch.outside': 'fg:#ffffff bg:#888888',
|
|
25
25
|
'selected': COLOR_GOLD,
|
|
26
26
|
'risk-high': '#FF0000 bold', # Red bold for HIGH risk
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
3
|
from openhands.sdk import LLM, BaseConversation, LocalFileStore
|
|
4
|
-
from openhands.sdk.security.confirmation_policy import NeverConfirm
|
|
5
|
-
from openhands.tools.preset.default import get_default_agent
|
|
6
4
|
from prompt_toolkit import HTML, print_formatted_text
|
|
7
5
|
from prompt_toolkit.shortcuts import print_container
|
|
8
6
|
from prompt_toolkit.widgets import Frame, TextArea
|
|
9
7
|
|
|
10
|
-
from openhands_cli.
|
|
8
|
+
from openhands_cli.utils import get_llm_metadata, get_default_cli_agent
|
|
11
9
|
from openhands_cli.locations import AGENT_SETTINGS_PATH, PERSISTENCE_DIR
|
|
12
10
|
from openhands_cli.pt_style import COLOR_GREY
|
|
13
11
|
from openhands_cli.tui.settings.store import AgentStore
|
|
@@ -176,13 +174,13 @@ class SettingsScreen:
|
|
|
176
174
|
model=model,
|
|
177
175
|
api_key=api_key,
|
|
178
176
|
base_url=base_url,
|
|
179
|
-
|
|
177
|
+
usage_id='agent',
|
|
180
178
|
metadata=get_llm_metadata(model_name=model, llm_type='agent'),
|
|
181
179
|
)
|
|
182
180
|
|
|
183
181
|
agent = self.agent_store.load()
|
|
184
182
|
if not agent:
|
|
185
|
-
agent =
|
|
183
|
+
agent = get_default_cli_agent(llm=llm)
|
|
186
184
|
|
|
187
185
|
agent = agent.model_copy(update={'llm': llm})
|
|
188
186
|
self.agent_store.save(agent)
|
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from fastmcp.mcp_config import MCPConfig
|
|
8
|
-
from openhands_cli.
|
|
8
|
+
from openhands_cli.utils import get_llm_metadata
|
|
9
9
|
from openhands_cli.locations import (
|
|
10
10
|
AGENT_SETTINGS_PATH,
|
|
11
11
|
MCP_CONFIG_FILE,
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
from typing import Any
|
|
5
|
-
|
|
5
|
+
from openhands.sdk.security.llm_analyzer import LLMSecurityAnalyzer
|
|
6
|
+
from openhands.tools.preset import get_default_agent
|
|
7
|
+
from openhands.sdk import LLM
|
|
6
8
|
|
|
7
9
|
def get_llm_metadata(
|
|
8
10
|
model_name: str,
|
|
@@ -55,3 +57,20 @@ def get_llm_metadata(
|
|
|
55
57
|
if user_id is not None:
|
|
56
58
|
metadata['trace_user_id'] = user_id
|
|
57
59
|
return metadata
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_default_cli_agent(
|
|
63
|
+
llm: LLM
|
|
64
|
+
):
|
|
65
|
+
agent = get_default_agent(
|
|
66
|
+
llm=llm,
|
|
67
|
+
cli_mode=True
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
agent = agent.model_copy(
|
|
71
|
+
update={
|
|
72
|
+
'security_analyzer': LLMSecurityAnalyzer()
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return agent
|
|
@@ -4,7 +4,7 @@ requires = [ "hatchling>=1.25" ]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openhands"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.3"
|
|
8
8
|
description = "OpenHands CLI - Terminal User Interface for OpenHands AI Agent"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -18,8 +18,8 @@ classifiers = [
|
|
|
18
18
|
# Using Git URLs for dependencies so installs from PyPI pull from GitHub
|
|
19
19
|
# TODO: pin package versions once agent-sdk has published PyPI packages
|
|
20
20
|
dependencies = [
|
|
21
|
-
"openhands-sdk==1.0.
|
|
22
|
-
"openhands-tools==1.0.
|
|
21
|
+
"openhands-sdk==1.0.0a5",
|
|
22
|
+
"openhands-tools==1.0.0a5",
|
|
23
23
|
"prompt-toolkit>=3",
|
|
24
24
|
"typer>=0.17.4",
|
|
25
25
|
]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Test that first-time settings screen usage creates a default agent with security analyzer."""
|
|
2
|
+
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
import pytest
|
|
5
|
+
from openhands_cli.tui.settings.settings_screen import SettingsScreen
|
|
6
|
+
from openhands_cli.user_actions.settings_action import SettingsType
|
|
7
|
+
from openhands.sdk import LLM
|
|
8
|
+
from pydantic import SecretStr
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_first_time_settings_creates_default_agent_with_security_analyzer():
|
|
12
|
+
"""Test that using the settings screen for the first time creates a default agent with a non-None security analyzer."""
|
|
13
|
+
|
|
14
|
+
# Create a settings screen instance (no conversation initially)
|
|
15
|
+
screen = SettingsScreen(conversation=None)
|
|
16
|
+
|
|
17
|
+
# Mock all the user interaction steps to simulate first-time setup
|
|
18
|
+
with (
|
|
19
|
+
patch(
|
|
20
|
+
'openhands_cli.tui.settings.settings_screen.settings_type_confirmation',
|
|
21
|
+
return_value=SettingsType.BASIC,
|
|
22
|
+
),
|
|
23
|
+
patch(
|
|
24
|
+
'openhands_cli.tui.settings.settings_screen.choose_llm_provider',
|
|
25
|
+
return_value='openai',
|
|
26
|
+
),
|
|
27
|
+
patch(
|
|
28
|
+
'openhands_cli.tui.settings.settings_screen.choose_llm_model',
|
|
29
|
+
return_value='gpt-4o-mini',
|
|
30
|
+
),
|
|
31
|
+
patch(
|
|
32
|
+
'openhands_cli.tui.settings.settings_screen.prompt_api_key',
|
|
33
|
+
return_value='sk-test-key-123',
|
|
34
|
+
),
|
|
35
|
+
patch(
|
|
36
|
+
'openhands_cli.tui.settings.settings_screen.save_settings_confirmation',
|
|
37
|
+
return_value=True,
|
|
38
|
+
),
|
|
39
|
+
):
|
|
40
|
+
# Run the settings configuration workflow
|
|
41
|
+
screen.configure_settings(first_time=True)
|
|
42
|
+
|
|
43
|
+
# Load the saved agent from the store
|
|
44
|
+
saved_agent = screen.agent_store.load()
|
|
45
|
+
|
|
46
|
+
# Verify that an agent was created and saved
|
|
47
|
+
assert saved_agent is not None, "Agent should be created and saved after first-time settings configuration"
|
|
48
|
+
|
|
49
|
+
# Verify that the agent has the expected LLM configuration
|
|
50
|
+
assert saved_agent.llm.model == 'openai/gpt-4o-mini', f"Expected model 'openai/gpt-4o-mini', got '{saved_agent.llm.model}'"
|
|
51
|
+
assert saved_agent.llm.api_key.get_secret_value() == 'sk-test-key-123', "API key should match the provided value"
|
|
52
|
+
|
|
53
|
+
# Verify that the agent has a security analyzer and it's not None
|
|
54
|
+
assert hasattr(saved_agent, 'security_analyzer'), "Agent should have a security_analyzer attribute"
|
|
55
|
+
assert saved_agent.security_analyzer is not None, "Security analyzer should not be None"
|
|
56
|
+
|
|
57
|
+
# Verify the security analyzer has the expected type/kind
|
|
58
|
+
assert hasattr(saved_agent.security_analyzer, 'kind'), "Security analyzer should have a 'kind' attribute"
|
|
59
|
+
assert saved_agent.security_analyzer.kind == 'LLMSecurityAnalyzer', f"Expected security analyzer kind 'LLMSecurityAnalyzer', got '{saved_agent.security_analyzer.kind}'"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_first_time_settings_with_advanced_configuration():
|
|
63
|
+
"""Test that advanced settings also create a default agent with security analyzer."""
|
|
64
|
+
|
|
65
|
+
screen = SettingsScreen(conversation=None)
|
|
66
|
+
|
|
67
|
+
with (
|
|
68
|
+
patch(
|
|
69
|
+
'openhands_cli.tui.settings.settings_screen.settings_type_confirmation',
|
|
70
|
+
return_value=SettingsType.ADVANCED,
|
|
71
|
+
),
|
|
72
|
+
patch(
|
|
73
|
+
'openhands_cli.tui.settings.settings_screen.prompt_custom_model',
|
|
74
|
+
return_value='anthropic/claude-3-5-sonnet',
|
|
75
|
+
),
|
|
76
|
+
patch(
|
|
77
|
+
'openhands_cli.tui.settings.settings_screen.prompt_base_url',
|
|
78
|
+
return_value='https://api.anthropic.com',
|
|
79
|
+
),
|
|
80
|
+
patch(
|
|
81
|
+
'openhands_cli.tui.settings.settings_screen.prompt_api_key',
|
|
82
|
+
return_value='sk-ant-test-key',
|
|
83
|
+
),
|
|
84
|
+
patch(
|
|
85
|
+
'openhands_cli.tui.settings.settings_screen.choose_memory_condensation',
|
|
86
|
+
return_value=True,
|
|
87
|
+
),
|
|
88
|
+
patch(
|
|
89
|
+
'openhands_cli.tui.settings.settings_screen.save_settings_confirmation',
|
|
90
|
+
return_value=True,
|
|
91
|
+
),
|
|
92
|
+
):
|
|
93
|
+
screen.configure_settings(first_time=True)
|
|
94
|
+
|
|
95
|
+
saved_agent = screen.agent_store.load()
|
|
96
|
+
|
|
97
|
+
# Verify agent creation and security analyzer
|
|
98
|
+
assert saved_agent is not None, "Agent should be created with advanced settings"
|
|
99
|
+
assert saved_agent.security_analyzer is not None, "Security analyzer should not be None in advanced settings"
|
|
100
|
+
assert saved_agent.security_analyzer.kind == 'LLMSecurityAnalyzer', "Security analyzer should be LLMSecurityAnalyzer"
|
|
101
|
+
|
|
102
|
+
# Verify advanced settings were applied
|
|
103
|
+
assert saved_agent.llm.model == 'anthropic/claude-3-5-sonnet', "Custom model should be set"
|
|
104
|
+
assert saved_agent.llm.base_url == 'https://api.anthropic.com', "Base URL should be set"
|
|
@@ -6,10 +6,10 @@ import pytest
|
|
|
6
6
|
from openhands_cli.tui.settings.settings_screen import SettingsScreen
|
|
7
7
|
from openhands_cli.tui.settings.store import AgentStore
|
|
8
8
|
from openhands_cli.user_actions.settings_action import SettingsType
|
|
9
|
+
from openhands_cli.utils import get_default_cli_agent
|
|
9
10
|
from pydantic import SecretStr
|
|
10
11
|
|
|
11
12
|
from openhands.sdk import LLM, Conversation, LocalFileStore
|
|
12
|
-
from openhands.tools.preset.default import get_default_agent
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def read_json(path: Path) -> dict:
|
|
@@ -18,7 +18,7 @@ def read_json(path: Path) -> dict:
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def make_screen_with_conversation(model='openai/gpt-4o-mini', api_key='sk-xyz'):
|
|
21
|
-
llm = LLM(model=model, api_key=SecretStr(api_key),
|
|
21
|
+
llm = LLM(model=model, api_key=SecretStr(api_key), usage_id='test-service')
|
|
22
22
|
# Conversation(agent) signature may vary across versions; adapt if needed:
|
|
23
23
|
from openhands.sdk.agent import Agent
|
|
24
24
|
|
|
@@ -30,8 +30,8 @@ def make_screen_with_conversation(model='openai/gpt-4o-mini', api_key='sk-xyz'):
|
|
|
30
30
|
def seed_file(path: Path, model: str = 'openai/gpt-4o-mini', api_key: str = 'sk-old'):
|
|
31
31
|
store = AgentStore()
|
|
32
32
|
store.file_store = LocalFileStore(root=str(path))
|
|
33
|
-
agent =
|
|
34
|
-
llm=LLM(model=model, api_key=SecretStr(api_key),
|
|
33
|
+
agent = get_default_cli_agent(
|
|
34
|
+
llm=LLM(model=model, api_key=SecretStr(api_key), usage_id='test-service')
|
|
35
35
|
)
|
|
36
36
|
store.save(agent)
|
|
37
37
|
|
|
@@ -6,13 +6,13 @@ from openhands_cli.runner import ConversationRunner
|
|
|
6
6
|
from openhands_cli.user_actions.types import UserConfirmation
|
|
7
7
|
from pydantic import ConfigDict, SecretStr, model_validator
|
|
8
8
|
|
|
9
|
-
from openhands.sdk import Conversation, ConversationCallbackType
|
|
9
|
+
from openhands.sdk import Conversation, ConversationCallbackType, LocalConversation
|
|
10
10
|
from openhands.sdk.agent.base import AgentBase
|
|
11
11
|
from openhands.sdk.conversation import ConversationState
|
|
12
12
|
from openhands.sdk.conversation.state import AgentExecutionStatus
|
|
13
13
|
from openhands.sdk.llm import LLM
|
|
14
14
|
from openhands.sdk.security.confirmation_policy import AlwaysConfirm, NeverConfirm
|
|
15
|
-
|
|
15
|
+
from unittest.mock import MagicMock
|
|
16
16
|
|
|
17
17
|
class FakeLLM(LLM):
|
|
18
18
|
@model_validator(mode='after')
|
|
@@ -41,16 +41,16 @@ class FakeAgent(AgentBase):
|
|
|
41
41
|
pass
|
|
42
42
|
|
|
43
43
|
def step(
|
|
44
|
-
self,
|
|
44
|
+
self, conversation: LocalConversation, on_event: ConversationCallbackType
|
|
45
45
|
) -> None:
|
|
46
46
|
self.step_count += 1
|
|
47
47
|
if self.step_count == self.finish_on_step:
|
|
48
|
-
state.agent_status = AgentExecutionStatus.FINISHED
|
|
48
|
+
conversation.state.agent_status = AgentExecutionStatus.FINISHED
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
@pytest.fixture()
|
|
52
52
|
def agent() -> FakeAgent:
|
|
53
|
-
llm = LLM(**default_config(),
|
|
53
|
+
llm = LLM(**default_config(), usage_id='test-service')
|
|
54
54
|
return FakeAgent(llm=llm, tools=[])
|
|
55
55
|
|
|
56
56
|
|
|
@@ -102,15 +102,15 @@ class TestConversationRunner:
|
|
|
102
102
|
"""
|
|
103
103
|
if final_status == AgentExecutionStatus.FINISHED:
|
|
104
104
|
agent.finish_on_step = 1
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
# Add a mock security analyzer to enable confirmation mode
|
|
107
|
-
from unittest.mock import MagicMock
|
|
108
107
|
agent.security_analyzer = MagicMock()
|
|
109
|
-
|
|
108
|
+
|
|
110
109
|
convo = Conversation(agent)
|
|
111
110
|
convo.state.agent_status = AgentExecutionStatus.WAITING_FOR_CONFIRMATION
|
|
112
111
|
cr = ConversationRunner(convo)
|
|
113
112
|
cr.set_confirmation_policy(AlwaysConfirm())
|
|
113
|
+
|
|
114
114
|
with patch.object(
|
|
115
115
|
cr, '_handle_confirmation_request', return_value=confirmation
|
|
116
116
|
) as mock_confirmation_request:
|
|
@@ -37,7 +37,7 @@ class TestToolFix:
|
|
|
37
37
|
"""Test that entire tools list is replaced with default tools when loading agent."""
|
|
38
38
|
# Create a mock agent with different tools and working directories
|
|
39
39
|
mock_agent = Agent(
|
|
40
|
-
llm=LLM(model='test/model', api_key='test-key',
|
|
40
|
+
llm=LLM(model='test/model', api_key='test-key', usage_id='test-service'),
|
|
41
41
|
tools=[
|
|
42
42
|
Tool(name='BashTool'),
|
|
43
43
|
Tool(name='FileEditorTool'),
|
|
@@ -182,7 +182,7 @@ class TestLaunchGuiServer:
|
|
|
182
182
|
# Check pull command
|
|
183
183
|
pull_call = mock_run.call_args_list[0]
|
|
184
184
|
pull_cmd = pull_call[0][0]
|
|
185
|
-
assert pull_cmd[0:3] == ['docker', 'pull', 'docker.all-hands.dev/
|
|
185
|
+
assert pull_cmd[0:3] == ['docker', 'pull', 'docker.all-hands.dev/openhands/runtime:latest-nikolaik']
|
|
186
186
|
|
|
187
187
|
# Check run command
|
|
188
188
|
run_call = mock_run.call_args_list[1]
|
|
@@ -26,7 +26,7 @@ def _create_agent(mcp_config=None) -> Agent:
|
|
|
26
26
|
if mcp_config is None:
|
|
27
27
|
mcp_config = {}
|
|
28
28
|
return Agent(
|
|
29
|
-
llm=LLM(model='test-model', api_key='test-key',
|
|
29
|
+
llm=LLM(model='test-model', api_key='test-key', usage_id='test-service'),
|
|
30
30
|
tools=[],
|
|
31
31
|
mcp_config=mcp_config,
|
|
32
32
|
)
|
|
@@ -1828,7 +1828,7 @@ wheels = [
|
|
|
1828
1828
|
|
|
1829
1829
|
[[package]]
|
|
1830
1830
|
name = "openhands"
|
|
1831
|
-
version = "1.0.
|
|
1831
|
+
version = "1.0.3"
|
|
1832
1832
|
source = { editable = "." }
|
|
1833
1833
|
dependencies = [
|
|
1834
1834
|
{ name = "openhands-sdk" },
|
|
@@ -1855,8 +1855,8 @@ dev = [
|
|
|
1855
1855
|
|
|
1856
1856
|
[package.metadata]
|
|
1857
1857
|
requires-dist = [
|
|
1858
|
-
{ name = "openhands-sdk", specifier = "==1.0.
|
|
1859
|
-
{ name = "openhands-tools", specifier = "==1.0.
|
|
1858
|
+
{ name = "openhands-sdk", specifier = "==1.0.0a5" },
|
|
1859
|
+
{ name = "openhands-tools", specifier = "==1.0.0a5" },
|
|
1860
1860
|
{ name = "prompt-toolkit", specifier = ">=3" },
|
|
1861
1861
|
{ name = "typer", specifier = ">=0.17.4" },
|
|
1862
1862
|
]
|
|
@@ -1879,7 +1879,7 @@ dev = [
|
|
|
1879
1879
|
|
|
1880
1880
|
[[package]]
|
|
1881
1881
|
name = "openhands-sdk"
|
|
1882
|
-
version = "1.0.
|
|
1882
|
+
version = "1.0.0a5"
|
|
1883
1883
|
source = { registry = "https://pypi.org/simple" }
|
|
1884
1884
|
dependencies = [
|
|
1885
1885
|
{ name = "fastmcp" },
|
|
@@ -1891,14 +1891,14 @@ dependencies = [
|
|
|
1891
1891
|
{ name = "tenacity" },
|
|
1892
1892
|
{ name = "websockets" },
|
|
1893
1893
|
]
|
|
1894
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1894
|
+
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" }
|
|
1895
1895
|
wheels = [
|
|
1896
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1896
|
+
{ 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" },
|
|
1897
1897
|
]
|
|
1898
1898
|
|
|
1899
1899
|
[[package]]
|
|
1900
1900
|
name = "openhands-tools"
|
|
1901
|
-
version = "1.0.
|
|
1901
|
+
version = "1.0.0a5"
|
|
1902
1902
|
source = { registry = "https://pypi.org/simple" }
|
|
1903
1903
|
dependencies = [
|
|
1904
1904
|
{ name = "bashlex" },
|
|
@@ -1910,9 +1910,9 @@ dependencies = [
|
|
|
1910
1910
|
{ name = "openhands-sdk" },
|
|
1911
1911
|
{ name = "pydantic" },
|
|
1912
1912
|
]
|
|
1913
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1913
|
+
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" }
|
|
1914
1914
|
wheels = [
|
|
1915
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1915
|
+
{ 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" },
|
|
1916
1916
|
]
|
|
1917
1917
|
|
|
1918
1918
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|