openhands-tools 1.10.0__py3-none-any.whl → 1.11.1__py3-none-any.whl
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.
- openhands/tools/planning_file_editor/definition.py +41 -3
- openhands/tools/preset/planning.py +11 -2
- openhands/tools/terminal/terminal/terminal_session.py +15 -0
- openhands/tools/terminal/utils/command.py +1 -1
- {openhands_tools-1.10.0.dist-info → openhands_tools-1.11.1.dist-info}/METADATA +1 -1
- {openhands_tools-1.10.0.dist-info → openhands_tools-1.11.1.dist-info}/RECORD +8 -8
- {openhands_tools-1.10.0.dist-info → openhands_tools-1.11.1.dist-info}/WHEEL +0 -0
- {openhands_tools-1.10.0.dist-info → openhands_tools-1.11.1.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from openhands.sdk.conversation.state import ConversationState
|
|
10
10
|
|
|
11
|
+
from openhands.sdk.logger import get_logger
|
|
11
12
|
from openhands.sdk.tool import (
|
|
12
13
|
ToolAnnotations,
|
|
13
14
|
ToolDefinition,
|
|
@@ -20,7 +21,12 @@ from openhands.tools.file_editor.definition import (
|
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
logger = get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
# Default config directory and plan filename
|
|
27
|
+
# PLAN.md is now stored in .agents_tmp/ to keep workspace root clean
|
|
28
|
+
# and separate agent temporary files from user content
|
|
29
|
+
DEFAULT_CONFIG_DIR = ".agents_tmp"
|
|
24
30
|
PLAN_FILENAME = "PLAN.md"
|
|
25
31
|
|
|
26
32
|
|
|
@@ -62,11 +68,17 @@ class PlanningFileEditorTool(
|
|
|
62
68
|
def create(
|
|
63
69
|
cls,
|
|
64
70
|
conv_state: "ConversationState",
|
|
71
|
+
plan_path: str | None = None,
|
|
65
72
|
) -> Sequence["PlanningFileEditorTool"]:
|
|
66
73
|
"""Initialize PlanningFileEditorTool.
|
|
67
74
|
|
|
68
75
|
Args:
|
|
69
76
|
conv_state: Conversation state to get working directory from.
|
|
77
|
+
plan_path: Optional absolute path to PLAN.md file. If not provided,
|
|
78
|
+
defaults to {working_dir}/.agents_tmp/PLAN.md.
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
ValueError: If plan_path is provided but is not an absolute path.
|
|
70
82
|
"""
|
|
71
83
|
# Import here to avoid circular imports
|
|
72
84
|
from openhands.tools.planning_file_editor.impl import (
|
|
@@ -74,8 +86,31 @@ class PlanningFileEditorTool(
|
|
|
74
86
|
)
|
|
75
87
|
|
|
76
88
|
working_dir = conv_state.workspace.working_dir
|
|
77
|
-
|
|
78
|
-
plan_path
|
|
89
|
+
|
|
90
|
+
# Validate plan_path is absolute if provided
|
|
91
|
+
if plan_path is not None and not Path(plan_path).is_absolute():
|
|
92
|
+
raise ValueError(f"plan_path must be an absolute path, got: {plan_path}")
|
|
93
|
+
|
|
94
|
+
# Use provided plan_path or fall back to .agents_tmp/PLAN.md at workspace root
|
|
95
|
+
if plan_path is None:
|
|
96
|
+
workspace_root = Path(working_dir).resolve()
|
|
97
|
+
|
|
98
|
+
# Check for legacy PLAN.md at workspace root
|
|
99
|
+
legacy_plan_path = workspace_root / PLAN_FILENAME
|
|
100
|
+
if legacy_plan_path.exists():
|
|
101
|
+
# Use legacy location for backward compatibility
|
|
102
|
+
new_recommended_path = (
|
|
103
|
+
workspace_root / DEFAULT_CONFIG_DIR / PLAN_FILENAME
|
|
104
|
+
)
|
|
105
|
+
logger.warning(
|
|
106
|
+
f"Found PLAN.md at legacy location {legacy_plan_path}. "
|
|
107
|
+
f"Consider moving it to {new_recommended_path} "
|
|
108
|
+
f"for consistency with OpenHands conventions."
|
|
109
|
+
)
|
|
110
|
+
plan_path = str(legacy_plan_path)
|
|
111
|
+
else:
|
|
112
|
+
# Use new default location
|
|
113
|
+
plan_path = str(workspace_root / DEFAULT_CONFIG_DIR / PLAN_FILENAME)
|
|
79
114
|
|
|
80
115
|
# Initialize PLAN.md with headers if it doesn't exist
|
|
81
116
|
plan_file = Path(plan_path)
|
|
@@ -83,7 +118,10 @@ class PlanningFileEditorTool(
|
|
|
83
118
|
# Import here to avoid circular imports
|
|
84
119
|
from openhands.tools.preset.planning import get_plan_headers
|
|
85
120
|
|
|
121
|
+
# Ensure parent directory exists
|
|
122
|
+
plan_file.parent.mkdir(parents=True, exist_ok=True)
|
|
86
123
|
plan_file.write_text(get_plan_headers())
|
|
124
|
+
logger.info(f"Created new PLAN.md at {plan_path}")
|
|
87
125
|
|
|
88
126
|
# Create executor with restricted edit access to PLAN.md only
|
|
89
127
|
executor = PlanningFileEditorExecutor(
|
|
@@ -102,9 +102,13 @@ def register_planning_tools() -> None:
|
|
|
102
102
|
logger.debug("Tool: PlanningFileEditorTool registered.")
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
def get_planning_tools() -> list[Tool]:
|
|
105
|
+
def get_planning_tools(plan_path: str | None = None) -> list[Tool]:
|
|
106
106
|
"""Get the planning agent tool specifications.
|
|
107
107
|
|
|
108
|
+
Args:
|
|
109
|
+
plan_path: Optional absolute path to PLAN.md file. If provided, will be
|
|
110
|
+
passed to PlanningFileEditorTool via params.
|
|
111
|
+
|
|
108
112
|
Returns:
|
|
109
113
|
List of tools optimized for planning and analysis tasks, including
|
|
110
114
|
file viewing and PLAN.md editing capabilities for advanced
|
|
@@ -117,10 +121,15 @@ def get_planning_tools() -> list[Tool]:
|
|
|
117
121
|
from openhands.tools.grep import GrepTool
|
|
118
122
|
from openhands.tools.planning_file_editor import PlanningFileEditorTool
|
|
119
123
|
|
|
124
|
+
# Build params for PlanningFileEditorTool if plan_path is provided
|
|
125
|
+
planning_tool_params = {}
|
|
126
|
+
if plan_path:
|
|
127
|
+
planning_tool_params["plan_path"] = plan_path
|
|
128
|
+
|
|
120
129
|
return [
|
|
121
130
|
Tool(name=GlobTool.name),
|
|
122
131
|
Tool(name=GrepTool.name),
|
|
123
|
-
Tool(name=PlanningFileEditorTool.name),
|
|
132
|
+
Tool(name=PlanningFileEditorTool.name, params=planning_tool_params),
|
|
124
133
|
]
|
|
125
134
|
|
|
126
135
|
|
|
@@ -5,8 +5,10 @@ import time
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
|
|
7
7
|
from openhands.sdk.logger import get_logger
|
|
8
|
+
from openhands.sdk.utils import maybe_truncate
|
|
8
9
|
from openhands.tools.terminal.constants import (
|
|
9
10
|
CMD_OUTPUT_PS1_END,
|
|
11
|
+
MAX_CMD_OUTPUT_SIZE,
|
|
10
12
|
NO_CHANGE_TIMEOUT_SECONDS,
|
|
11
13
|
POLL_INTERVAL,
|
|
12
14
|
TIMEOUT_MESSAGE_TEMPLATE,
|
|
@@ -183,6 +185,10 @@ class TerminalSession(TerminalSessionBase):
|
|
|
183
185
|
raw_command_output,
|
|
184
186
|
metadata,
|
|
185
187
|
)
|
|
188
|
+
command_output = maybe_truncate(
|
|
189
|
+
command_output, truncate_after=MAX_CMD_OUTPUT_SIZE
|
|
190
|
+
)
|
|
191
|
+
|
|
186
192
|
self.prev_status = TerminalCommandStatus.COMPLETED
|
|
187
193
|
self.prev_output = "" # Reset previous command output
|
|
188
194
|
self._ready_for_next_command()
|
|
@@ -221,6 +227,9 @@ class TerminalSession(TerminalSessionBase):
|
|
|
221
227
|
metadata,
|
|
222
228
|
continue_prefix="[Below is the output of the previous command.]\n",
|
|
223
229
|
)
|
|
230
|
+
command_output = maybe_truncate(
|
|
231
|
+
command_output, truncate_after=MAX_CMD_OUTPUT_SIZE
|
|
232
|
+
)
|
|
224
233
|
return TerminalObservation.from_text(
|
|
225
234
|
command=command,
|
|
226
235
|
text=command_output,
|
|
@@ -257,6 +266,9 @@ class TerminalSession(TerminalSessionBase):
|
|
|
257
266
|
metadata,
|
|
258
267
|
continue_prefix="[Below is the output of the previous command.]\n",
|
|
259
268
|
)
|
|
269
|
+
command_output = maybe_truncate(
|
|
270
|
+
command_output, truncate_after=MAX_CMD_OUTPUT_SIZE
|
|
271
|
+
)
|
|
260
272
|
return TerminalObservation.from_text(
|
|
261
273
|
command=command,
|
|
262
274
|
exit_code=metadata.exit_code,
|
|
@@ -391,6 +403,9 @@ class TerminalSession(TerminalSessionBase):
|
|
|
391
403
|
metadata,
|
|
392
404
|
continue_prefix="[Below is the output of the previous command.]\n",
|
|
393
405
|
)
|
|
406
|
+
command_output = maybe_truncate(
|
|
407
|
+
command_output, truncate_after=MAX_CMD_OUTPUT_SIZE
|
|
408
|
+
)
|
|
394
409
|
obs = TerminalObservation.from_text(
|
|
395
410
|
command=command,
|
|
396
411
|
text=command_output,
|
|
@@ -141,7 +141,7 @@ def escape_bash_special_chars(command: str) -> str:
|
|
|
141
141
|
remaining = command[last_pos:]
|
|
142
142
|
parts.append(remaining)
|
|
143
143
|
return "".join(parts)
|
|
144
|
-
except (ParsingError, NotImplementedError, TypeError):
|
|
144
|
+
except (ParsingError, NotImplementedError, TypeError, AttributeError):
|
|
145
145
|
logger.debug(
|
|
146
146
|
f"Failed to parse bash commands for special characters escape\n[input]: "
|
|
147
147
|
f"{command}\n[warning]: {traceback.format_exc()}\nThe original command "
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.11.1
|
|
4
4
|
Summary: OpenHands Tools - Runtime tools for AI agents
|
|
5
5
|
Project-URL: Source, https://github.com/OpenHands/software-agent-sdk
|
|
6
6
|
Project-URL: Homepage, https://github.com/OpenHands/software-agent-sdk
|
|
@@ -48,13 +48,13 @@ openhands/tools/grep/__init__.py,sha256=XJscA-rP35sCCpILkcCF36sd_RG8XdTx6X3N12W7
|
|
|
48
48
|
openhands/tools/grep/definition.py,sha256=Nok-GtLv39a93y6s6BnJdL6nRERpPvk9LVX30lg6yHA,3970
|
|
49
49
|
openhands/tools/grep/impl.py,sha256=mCib7eZi_nKCOBFMWv5-d1jSz3N7VpGOVnAs3KDf3PY,8647
|
|
50
50
|
openhands/tools/planning_file_editor/__init__.py,sha256=edIuvR5ZnEXXsYfRt8xbrq15Z6vtdUq4AMguuuk1grI,197
|
|
51
|
-
openhands/tools/planning_file_editor/definition.py,sha256=
|
|
51
|
+
openhands/tools/planning_file_editor/definition.py,sha256=1llmMozk0STSgIc-9GKc02MfEDb7YC0oLaRMCRG0Xko,5723
|
|
52
52
|
openhands/tools/planning_file_editor/impl.py,sha256=W8Mdy7Qjbz90iKSmisw23-TcFtXwe7Vk373WvrScCS8,2218
|
|
53
53
|
openhands/tools/preset/__init__.py,sha256=KougtVUTSj9D6AjR78EXmYRdITY6ZIaodCQuWfViXc0,913
|
|
54
54
|
openhands/tools/preset/default.py,sha256=r6lAqHD-4ntjiOSfNvSxuAJtJqqTTik_mBIFZOE1w7Q,2686
|
|
55
55
|
openhands/tools/preset/gemini.py,sha256=FG3BcJjnm6tDLIjg6EiDFTksx5lVVBInh_Jpza0mHpU,3136
|
|
56
56
|
openhands/tools/preset/gpt5.py,sha256=44LOv6MncP9X9QU7pn1UfdjYl8ec8zKU9jUU7tUYR5I,2615
|
|
57
|
-
openhands/tools/preset/planning.py,sha256=
|
|
57
|
+
openhands/tools/preset/planning.py,sha256=SOe2A5Nr-jkgQAouCKGCyo3UfRKaUB8xbAFA59m69xA,5682
|
|
58
58
|
openhands/tools/task_tracker/__init__.py,sha256=NVm3CE_CkIAUSjFexh7HLXMpibJ_Dh8J8OOow2SlE1I,302
|
|
59
59
|
openhands/tools/task_tracker/definition.py,sha256=yGN_wks_-QpjRlfYiv5uOYyRTshaFuBwog0P62m5x0w,15772
|
|
60
60
|
openhands/tools/terminal/__init__.py,sha256=L5iQMMVhQbB_p2DESxGKo67D9kvjU0XIVR8LBuQ7HiY,657
|
|
@@ -66,15 +66,15 @@ openhands/tools/terminal/terminal/__init__.py,sha256=UL08nepNd-k4jWBglQAKtg4aPjg
|
|
|
66
66
|
openhands/tools/terminal/terminal/factory.py,sha256=Q9w-6AV-2aRpcTrKotdDDEKq1_7zc7I0MFb3sxXU374,4475
|
|
67
67
|
openhands/tools/terminal/terminal/interface.py,sha256=g0nyhMzVsIGptfBnBdv6FESUtv7k-EnRI32KYYl2VO0,6854
|
|
68
68
|
openhands/tools/terminal/terminal/subprocess_terminal.py,sha256=vKvcX_0H7ck3_BHWbir41NTI6srH4hCymOt48doq8js,16269
|
|
69
|
-
openhands/tools/terminal/terminal/terminal_session.py,sha256=
|
|
69
|
+
openhands/tools/terminal/terminal/terminal_session.py,sha256=Mast2NgG5gW7Yefl61AFUf_HAMYaShZMQ_AQCUowuS4,20700
|
|
70
70
|
openhands/tools/terminal/terminal/tmux_terminal.py,sha256=QMXeTs45WWeM6VzbHN3eCAYu9xXsHpFa6prsfNkOG3M,6187
|
|
71
|
-
openhands/tools/terminal/utils/command.py,sha256=
|
|
71
|
+
openhands/tools/terminal/utils/command.py,sha256=RWmBsiXvEuDNQP4s52FvbWcTbm_vxdXYvI2aZHu0H_E,5450
|
|
72
72
|
openhands/tools/tom_consult/__init__.py,sha256=av9VYJRWHmP4_5Eu2840PARtgOTRP84jZjqJ3zs8sRs,581
|
|
73
73
|
openhands/tools/tom_consult/definition.py,sha256=MTdOCOJaEGgOXhlJ9-x0HdhD6JiKNT2DodEOdsB4RBg,8224
|
|
74
74
|
openhands/tools/tom_consult/executor.py,sha256=LkWeltj-7ZgLhVZKZP4cuhxqg2YuyRnqSz5S0U9WElk,16656
|
|
75
75
|
openhands/tools/utils/__init__.py,sha256=AgJX59QLQTulZqIvJnUqM7LxAgsFhtqmgol-lKLc7Wc,1253
|
|
76
76
|
openhands/tools/utils/timeout.py,sha256=AjKNLZa8NqQ0HllZzqWZwZMj-8PEWHHBXwOlMjTygpA,399
|
|
77
|
-
openhands_tools-1.
|
|
78
|
-
openhands_tools-1.
|
|
79
|
-
openhands_tools-1.
|
|
80
|
-
openhands_tools-1.
|
|
77
|
+
openhands_tools-1.11.1.dist-info/METADATA,sha256=QPPoOi1v8U7qcTc2JPjH9_mH4c8ExxCdxs_PfuE6_Dg,699
|
|
78
|
+
openhands_tools-1.11.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
79
|
+
openhands_tools-1.11.1.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
|
|
80
|
+
openhands_tools-1.11.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|