openhands-tools 1.58.2__tar.gz → 1.60.0__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.
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/PKG-INFO +3 -2
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/apply_patch/core.py +4 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/server.py +20 -2
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/child_conversation/definition.py +7 -4
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/editor.py +10 -1
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/glob/impl.py +7 -10
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task/definition.py +2 -1
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task_tracker/definition.py +3 -130
- openhands_tools-1.60.0/openhands/tools/terminal/env.py +88 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/tmux_pane_pool.py +3 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/tmux_terminal.py +3 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/windows_terminal.py +29 -45
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands_tools.egg-info/PKG-INFO +3 -2
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands_tools.egg-info/requires.txt +2 -1
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/pyproject.toml +3 -2
- openhands_tools-1.58.2/openhands/tools/terminal/env.py +0 -39
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/apply_patch/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/apply_patch/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/ask_oracle/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/ask_oracle/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/ask_oracle/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/event_storage.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/logging_fix.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/recording.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/child_conversation/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/child_conversation/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/delegate/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/delegate/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/delegate/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/delegate/visualizer.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/exceptions.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/config.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/constants.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/diff.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/encoding.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/file_cache.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/history.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/shell.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/edit/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/edit/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/edit/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/file_change.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/list_directory/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/list_directory/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/list_directory/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/read_file/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/read_file/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/read_file/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/write_file/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/write_file/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/write_file/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/glob/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/glob/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/grep/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/grep/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/grep/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/planning_file_editor/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/planning_file_editor/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/planning_file_editor/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/default.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/gemini.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/gpt5.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/planning.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/bash_runner.md +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/code_explorer.md +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/default.md +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/web_researcher.md +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/task_outcome.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/py.typed +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task/manager.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task_tracker/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/constants.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/descriptions.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/metadata.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/factory.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/interface.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/process_priority.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/subprocess_terminal.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/terminal_session.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/timeout_policy.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/utils/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/utils/command.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/utils/escape_filter.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/tom_consult/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/tom_consult/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/tom_consult/executor.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/utils/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/utils/timeout.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/workflow/__init__.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/workflow/definition.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/workflow/impl.py +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands_tools.egg-info/SOURCES.txt +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands_tools.egg-info/dependency_links.txt +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands_tools.egg-info/top_level.txt +0 -0
- {openhands_tools-1.58.2 → openhands_tools-1.60.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.60.0
|
|
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
|
|
@@ -14,7 +14,8 @@ Requires-Dist: tree-sitter-bash>=0.23
|
|
|
14
14
|
Requires-Dist: binaryornot>=0.6.0
|
|
15
15
|
Requires-Dist: cachetools
|
|
16
16
|
Requires-Dist: filelock>=3.20.1
|
|
17
|
-
Requires-Dist: libtmux>=0.
|
|
17
|
+
Requires-Dist: libtmux>=0.62.0
|
|
18
|
+
Requires-Dist: psutil>=7.2.2
|
|
18
19
|
Requires-Dist: pydantic>=2.13.5
|
|
19
20
|
Requires-Dist: browser-use>=0.8.0
|
|
20
21
|
Requires-Dist: func-timeout>=4.3.5
|
|
@@ -455,6 +455,10 @@ def load_files(paths: list[str], open_fn: Callable[[str], str]) -> dict[str, str
|
|
|
455
455
|
FileNotFoundError
|
|
456
456
|
) as exc: # pragma: no cover - exercised via higher-level tests
|
|
457
457
|
raise DiffError(f"Delete File Error: Missing File: {path}") from exc
|
|
458
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
459
|
+
# An unreadable path (a directory, a denied file, bytes that are not
|
|
460
|
+
# UTF-8 text) must surface as a tool error, not escape the executor.
|
|
461
|
+
raise DiffError(f"Cannot read {path}: {exc}") from exc
|
|
458
462
|
return orig
|
|
459
463
|
|
|
460
464
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from browser_use.dom.markdown_extractor import extract_clean_markdown
|
|
2
|
+
from browser_use.dom.service import DomService
|
|
2
3
|
|
|
3
4
|
from openhands.sdk import get_logger
|
|
4
5
|
from openhands.tools.browser_use.logging_fix import LogSafeBrowserUseServer
|
|
@@ -259,10 +260,27 @@ class CustomBrowserUseServer(LogSafeBrowserUseServer):
|
|
|
259
260
|
if not self.browser_session:
|
|
260
261
|
return "Error: No browser session active"
|
|
261
262
|
|
|
262
|
-
|
|
263
|
+
target_id = self.browser_session.agent_focus_target_id
|
|
264
|
+
if not target_id:
|
|
265
|
+
return "Error: No active page"
|
|
266
|
+
|
|
267
|
+
# Read a fresh DOM tree. The session path reuses the tree cached by the
|
|
268
|
+
# last browser_get_state, which is stale after clicks, timers or
|
|
269
|
+
# history navigation. A separate DomService leaves that cache and its
|
|
270
|
+
# element indices untouched.
|
|
271
|
+
profile = self.browser_session.browser_profile
|
|
272
|
+
dom_service = DomService(
|
|
273
|
+
browser_session=self.browser_session,
|
|
274
|
+
cross_origin_iframes=profile.cross_origin_iframes,
|
|
275
|
+
paint_order_filtering=profile.paint_order_filtering,
|
|
276
|
+
max_iframes=profile.max_iframes,
|
|
277
|
+
max_iframe_depth=profile.max_iframe_depth,
|
|
278
|
+
)
|
|
263
279
|
try:
|
|
264
280
|
content, content_stats = await extract_clean_markdown(
|
|
265
|
-
|
|
281
|
+
dom_service=dom_service,
|
|
282
|
+
target_id=target_id,
|
|
283
|
+
extract_links=extract_links,
|
|
266
284
|
)
|
|
267
285
|
except Exception as e:
|
|
268
286
|
logger.exception(
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/child_conversation/definition.py
RENAMED
|
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, ClassVar, Literal, Self
|
|
|
6
6
|
from pydantic import Field
|
|
7
7
|
from rich.text import Text
|
|
8
8
|
|
|
9
|
+
from openhands.sdk.event.types import UnmaskedID
|
|
9
10
|
from openhands.sdk.tool.registry import register_tool
|
|
10
11
|
from openhands.sdk.tool.tool import (
|
|
11
12
|
Action,
|
|
@@ -36,7 +37,8 @@ class StartChildConversationAction(Action):
|
|
|
36
37
|
default="worktree",
|
|
37
38
|
description=(
|
|
38
39
|
"'worktree' gives the child its own git worktree and branch when the "
|
|
39
|
-
"workspace
|
|
40
|
+
"workspace has a usable git base commit; otherwise it shares the "
|
|
41
|
+
"directory. 'shared' always runs it in the same directory."
|
|
40
42
|
),
|
|
41
43
|
)
|
|
42
44
|
|
|
@@ -54,8 +56,8 @@ class StartChildConversationAction(Action):
|
|
|
54
56
|
class StartChildConversationObservation(Observation):
|
|
55
57
|
"""Result of a child conversation launch."""
|
|
56
58
|
|
|
57
|
-
conversation_id:
|
|
58
|
-
parent_conversation_id:
|
|
59
|
+
conversation_id: UnmaskedID | None = None
|
|
60
|
+
parent_conversation_id: UnmaskedID | None = None
|
|
59
61
|
status: str | None = None
|
|
60
62
|
title: str | None = None
|
|
61
63
|
url: str | None = None
|
|
@@ -92,7 +94,8 @@ _DESCRIPTION = (
|
|
|
92
94
|
"conversation's history, so include the goal, relevant paths, constraints "
|
|
93
95
|
"and the expected deliverable. Use `title` to name it. `isolation` controls "
|
|
94
96
|
"the workspace: `worktree` (default) gives the child its own git worktree "
|
|
95
|
-
"and branch when the workspace
|
|
97
|
+
"and branch when the workspace has a usable git base commit; otherwise "
|
|
98
|
+
"it shares the directory and reports `shared` isolation. The worktree starts "
|
|
96
99
|
"from the repository's default branch, not from this conversation's branch "
|
|
97
100
|
"or uncommitted changes, so use `shared` when the child must see them. "
|
|
98
101
|
"`shared` runs it in the same directory; backends that manage workspaces "
|
|
@@ -486,8 +486,12 @@ class FileEditor:
|
|
|
486
486
|
content, fall back to UTF-8 so an edit may add characters (arrows, emoji,
|
|
487
487
|
CJK, ...) the original single-byte encoding lacks, instead of failing and
|
|
488
488
|
truncating the file. Note that the fallback transcodes the whole file to
|
|
489
|
-
UTF-8.
|
|
489
|
+
UTF-8. Editing through a symlink writes to the link's target: a rename
|
|
490
|
+
onto the link path would replace the link with a regular file.
|
|
490
491
|
"""
|
|
492
|
+
if path.is_symlink():
|
|
493
|
+
path = path.resolve()
|
|
494
|
+
|
|
491
495
|
default = self._encoding_manager.default_encoding
|
|
492
496
|
if encoding != default and not _is_encodable(file_text, encoding):
|
|
493
497
|
logger.warning(
|
|
@@ -572,6 +576,11 @@ class FileEditor:
|
|
|
572
576
|
new_lines.append(line)
|
|
573
577
|
history_lines.append(line)
|
|
574
578
|
|
|
579
|
+
# A final line without a trailing newline would fuse with the inserted
|
|
580
|
+
# content; terminate it first so the insert starts on its own line.
|
|
581
|
+
if new_lines and not new_lines[-1].endswith("\n"):
|
|
582
|
+
new_lines[-1] += "\n"
|
|
583
|
+
|
|
575
584
|
# Insert new content
|
|
576
585
|
for line in new_str_lines:
|
|
577
586
|
new_lines.append(line + "\n")
|
|
@@ -168,17 +168,14 @@ class GlobExecutor(ToolExecutor[GlobAction, GlobObservation]):
|
|
|
168
168
|
env=sanitized_env(),
|
|
169
169
|
)
|
|
170
170
|
|
|
171
|
-
# Parse output into file paths
|
|
172
|
-
|
|
171
|
+
# Parse output into file paths (ripgrep already sorted by --sortr=modified)
|
|
172
|
+
lines = []
|
|
173
173
|
if result.stdout:
|
|
174
|
-
for line in result.stdout.strip().split("\n")
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
break
|
|
180
|
-
|
|
181
|
-
truncated = len(file_paths) >= 100
|
|
174
|
+
lines = [line for line in result.stdout.strip().split("\n") if line]
|
|
175
|
+
|
|
176
|
+
# Limit to the first 100 files; truncated only if matches were actually dropped
|
|
177
|
+
truncated = len(lines) > 100
|
|
178
|
+
file_paths = [str(Path(line).resolve()) for line in lines[:100]]
|
|
182
179
|
|
|
183
180
|
return file_paths, truncated
|
|
184
181
|
|
|
@@ -17,6 +17,7 @@ from pydantic.json_schema import SkipJsonSchema
|
|
|
17
17
|
from rich.text import Text
|
|
18
18
|
|
|
19
19
|
from openhands.sdk import ImageContent, TextContent
|
|
20
|
+
from openhands.sdk.event.types import UnmaskedID
|
|
20
21
|
from openhands.sdk.logger import get_logger
|
|
21
22
|
from openhands.sdk.subagent import (
|
|
22
23
|
AgentDefinition,
|
|
@@ -75,7 +76,7 @@ class TaskAction(Action):
|
|
|
75
76
|
class TaskObservation(Observation):
|
|
76
77
|
"""Observation from a task execution."""
|
|
77
78
|
|
|
78
|
-
task_id:
|
|
79
|
+
task_id: UnmaskedID = Field(description="The unique identifier of the task.")
|
|
79
80
|
subagent: str = Field(description="The subagent of the task.")
|
|
80
81
|
status: str = Field(description="The status of the task.")
|
|
81
82
|
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/task_tracker/definition.py
RENAMED
|
@@ -284,138 +284,11 @@ class TaskTrackerExecutor(ToolExecutor[TaskTrackerAction, TaskTrackerObservation
|
|
|
284
284
|
pass
|
|
285
285
|
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
TASK_TRACKER_DESCRIPTION = """This tool provides structured task management capabilities for development workflows.
|
|
289
|
-
It enables systematic tracking of work items, progress monitoring, and efficient
|
|
290
|
-
organization of complex development activities.
|
|
287
|
+
TASK_TRACKER_DESCRIPTION = """Maintain a visible task list for complex, multi-phase work, multiple requirements, or an explicit request for a plan. Skip tracking for trivial, atomic, few-step tasks and informational discussion; implement those directly. When uncertain, favor tracking.
|
|
291
288
|
|
|
292
|
-
|
|
293
|
-
progress effectively to users.
|
|
289
|
+
At project start, capture requirements as precise, actionable tasks and break complex work into manageable units. View the current list before editing; plan replaces the full list, so preserve relevant tasks and progress. Update the list as work progresses, remove obsolete tasks, and add discovered issues or dependencies.
|
|
294
290
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
Utilize this tool in the following situations:
|
|
298
|
-
|
|
299
|
-
1. Multi-phase development work - When projects involve multiple sequential or
|
|
300
|
-
parallel activities
|
|
301
|
-
2. Complex implementation tasks - Work requiring systematic planning and
|
|
302
|
-
coordination across multiple components
|
|
303
|
-
3. Explicit user request for task organization - When users specifically ask
|
|
304
|
-
for structured task management
|
|
305
|
-
4. Multiple concurrent requirements - When users present several work items
|
|
306
|
-
that need coordination
|
|
307
|
-
5. Project initiation - Capture and organize user requirements at project start
|
|
308
|
-
6. Work commencement - Update task status to in_progress before beginning
|
|
309
|
-
implementation. Maintain focus by limiting active work to one task
|
|
310
|
-
7. Task completion - Update status to done and identify any additional work
|
|
311
|
-
that emerged during implementation
|
|
312
|
-
|
|
313
|
-
## Situations Where Tool Usage Is Unnecessary
|
|
314
|
-
|
|
315
|
-
Avoid using this tool when:
|
|
316
|
-
|
|
317
|
-
1. Single atomic tasks that require no decomposition
|
|
318
|
-
2. Trivial operations where tracking adds no organizational value
|
|
319
|
-
3. Simple activities completable in minimal steps
|
|
320
|
-
4. Pure information exchange or discussion
|
|
321
|
-
|
|
322
|
-
Note: For single straightforward tasks, proceed with direct implementation
|
|
323
|
-
rather than creating tracking overhead.
|
|
324
|
-
|
|
325
|
-
## Usage Scenarios
|
|
326
|
-
|
|
327
|
-
**Scenario A: Feature Development with Validation**
|
|
328
|
-
User request: "Build a user authentication system with login/logout functionality.
|
|
329
|
-
Don't forget to include input validation and error handling!"
|
|
330
|
-
|
|
331
|
-
Response approach: I'll implement a user authentication system with comprehensive
|
|
332
|
-
validation. Let me organize this work systematically.
|
|
333
|
-
|
|
334
|
-
*Task breakdown includes:*
|
|
335
|
-
1. Design authentication API endpoints and data models
|
|
336
|
-
2. Implement user login/logout controllers with session management
|
|
337
|
-
3. Add client-side form validation and error display
|
|
338
|
-
4. Create backend input sanitization and security checks
|
|
339
|
-
5. Implement comprehensive error handling for edge cases
|
|
340
|
-
6. Perform integration testing and fix any issues
|
|
341
|
-
|
|
342
|
-
**Scenario B: Codebase Refactoring**
|
|
343
|
-
User request: "I need to update all instances of the method 'fetchData' to
|
|
344
|
-
'retrieveInformation' throughout the entire project"
|
|
345
|
-
|
|
346
|
-
Response approach: Let me first analyze your codebase to identify all locations
|
|
347
|
-
where 'fetchData' appears.
|
|
348
|
-
|
|
349
|
-
*After code analysis*
|
|
350
|
-
|
|
351
|
-
I've located 12 occurrences of 'fetchData' across 6 files in your project.
|
|
352
|
-
I'll create a systematic plan to update these references.
|
|
353
|
-
|
|
354
|
-
*Organized task list includes specific file-by-file updates*
|
|
355
|
-
|
|
356
|
-
**Scenario C: Multi-feature Development**
|
|
357
|
-
User request: "Set up a blog platform with these components: admin dashboard,
|
|
358
|
-
article management, comment system, and user profiles."
|
|
359
|
-
|
|
360
|
-
Response approach: I'll help build your blog platform. Let me break down these
|
|
361
|
-
components into manageable implementation phases.
|
|
362
|
-
|
|
363
|
-
*Creates structured plan with each feature decomposed into specific development tasks*
|
|
364
|
-
|
|
365
|
-
## Counter-examples - Direct Implementation Preferred
|
|
366
|
-
|
|
367
|
-
**Counter-example A: Simple inquiry**
|
|
368
|
-
User request: "What's the syntax for a for loop in JavaScript?"
|
|
369
|
-
|
|
370
|
-
Response approach: Here's how to write a for loop in JavaScript:
|
|
371
|
-
|
|
372
|
-
```javascript
|
|
373
|
-
for (let i = 0; i < array.length; i++) {
|
|
374
|
-
console.log(array[i]);
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
*No task tracking needed - single informational response*
|
|
379
|
-
|
|
380
|
-
**Counter-example B: Minor modification**
|
|
381
|
-
User request: "Please add a docstring to the processPayment function explaining
|
|
382
|
-
its parameters."
|
|
383
|
-
|
|
384
|
-
Response approach: I'll add a docstring to explain the processPayment function.
|
|
385
|
-
|
|
386
|
-
*Direct edit without task tracking for simple modification*
|
|
387
|
-
|
|
388
|
-
## Status Management and Workflow
|
|
389
|
-
|
|
390
|
-
1. **Status Values**: Track work using these states:
|
|
391
|
-
- todo: Not yet initiated
|
|
392
|
-
- in_progress: Currently active (maintain single focus)
|
|
393
|
-
- done: Successfully completed
|
|
394
|
-
|
|
395
|
-
2. **Workflow Practices**:
|
|
396
|
-
- Update status dynamically as work progresses
|
|
397
|
-
- Mark completion immediately upon task finish
|
|
398
|
-
- Limit active work to ONE task at any given time
|
|
399
|
-
- Complete current activities before initiating new ones
|
|
400
|
-
- Remove obsolete tasks from tracking entirely
|
|
401
|
-
|
|
402
|
-
3. **Completion Criteria**:
|
|
403
|
-
- Mark tasks as done only when fully achieved
|
|
404
|
-
- Keep status as in_progress if errors, blocks, or partial completion exist
|
|
405
|
-
- Create new tasks for discovered issues or dependencies
|
|
406
|
-
- Never mark done when:
|
|
407
|
-
- Test suites are failing
|
|
408
|
-
- Implementation remains incomplete
|
|
409
|
-
- Unresolved errors persist
|
|
410
|
-
- Required resources are unavailable
|
|
411
|
-
|
|
412
|
-
4. **Task Organization**:
|
|
413
|
-
- Write precise, actionable descriptions
|
|
414
|
-
- Decompose complex work into manageable units
|
|
415
|
-
- Use descriptive, clear naming conventions
|
|
416
|
-
|
|
417
|
-
When uncertain, favor using this tool. Proactive task management demonstrates
|
|
418
|
-
systematic approach and ensures comprehensive requirement fulfillment.""" # noqa: E501
|
|
291
|
+
Statuses: todo = not started; in_progress = active; done = fully achieved. Mark a task in_progress before starting, keep at most one task in_progress, and finish it before starting another. Mark it done promptly only when completely successful. Leave incomplete, blocked, or failing work in_progress; never mark done while tests fail, errors remain, implementation is partial, or required resources are unavailable.""" # noqa: E501
|
|
419
292
|
|
|
420
293
|
|
|
421
294
|
class TaskTrackerTool(ToolDefinition[TaskTrackerAction, TaskTrackerObservation]):
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Environment helpers for terminal backends."""
|
|
2
|
+
|
|
3
|
+
import codecs
|
|
4
|
+
import locale
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from collections.abc import Mapping
|
|
8
|
+
|
|
9
|
+
from openhands.sdk.logger import get_logger
|
|
10
|
+
from openhands.sdk.utils import sanitized_env
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
logger = get_logger(__name__)
|
|
14
|
+
|
|
15
|
+
ENV_VAR_NAME_RE = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
|
|
16
|
+
UTF8_FALLBACK_LOCALE = "C.UTF-8"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def normalize_terminal_env(
|
|
20
|
+
extra_env: Mapping[str, str] | None,
|
|
21
|
+
) -> dict[str, str] | None:
|
|
22
|
+
"""Validate and copy client-provided terminal environment variables."""
|
|
23
|
+
if extra_env is None:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
normalized: dict[str, str] = {}
|
|
27
|
+
for key, value in extra_env.items():
|
|
28
|
+
if not isinstance(key, str) or not ENV_VAR_NAME_RE.match(key):
|
|
29
|
+
raise ValueError(f"Invalid terminal environment variable name: {key!r}")
|
|
30
|
+
if not isinstance(value, str):
|
|
31
|
+
raise TypeError(
|
|
32
|
+
"Terminal environment variable values must be strings: "
|
|
33
|
+
f"{key!r}={value!r}"
|
|
34
|
+
)
|
|
35
|
+
normalized[key] = value
|
|
36
|
+
return normalized
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def build_terminal_env(extra_env: Mapping[str, str] | None = None) -> dict[str, str]:
|
|
40
|
+
"""Return the sanitized process environment plus client-provided overrides."""
|
|
41
|
+
env = sanitized_env()
|
|
42
|
+
normalized = normalize_terminal_env(extra_env)
|
|
43
|
+
if normalized:
|
|
44
|
+
env.update(normalized)
|
|
45
|
+
env = sanitized_env(env)
|
|
46
|
+
return env
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def has_utf8_locale(environ: Mapping[str, str]) -> bool:
|
|
50
|
+
"""Apply tmux's check: TMUX is set, or the first non-empty of LC_ALL,
|
|
51
|
+
LC_CTYPE, LANG names UTF-8."""
|
|
52
|
+
if "TMUX" in environ:
|
|
53
|
+
return True
|
|
54
|
+
for name in ("LC_ALL", "LC_CTYPE", "LANG"):
|
|
55
|
+
value = environ.get(name)
|
|
56
|
+
if value:
|
|
57
|
+
return "utf-8" in value.lower() or "utf8" in value.lower()
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def ensure_utf8_locale() -> tuple[str, str | None] | None:
|
|
62
|
+
"""Fall back to a UTF-8 locale when the process has none.
|
|
63
|
+
|
|
64
|
+
Outside a UTF-8 locale, tmux replaces non-ASCII characters in format output
|
|
65
|
+
with ``_``, which breaks libtmux's parsing of the ``␞`` separator. As in
|
|
66
|
+
PEP 538, only LC_CTYPE is set unless LC_ALL overrides it.
|
|
67
|
+
|
|
68
|
+
Return the variable that was set and its previous value, or None.
|
|
69
|
+
"""
|
|
70
|
+
if has_utf8_locale(os.environ):
|
|
71
|
+
return None
|
|
72
|
+
# libtmux decodes tmux output with the encoding Python picked at startup,
|
|
73
|
+
# so a locale set now cannot help if that encoding is not UTF-8.
|
|
74
|
+
encoding = locale.getpreferredencoding(False)
|
|
75
|
+
if codecs.lookup(encoding).name != "utf-8":
|
|
76
|
+
logger.warning(
|
|
77
|
+
"tmux needs a UTF-8 locale, but Python decodes %s; start the "
|
|
78
|
+
"process with a UTF-8 locale or PYTHONUTF8=1",
|
|
79
|
+
encoding,
|
|
80
|
+
)
|
|
81
|
+
return None
|
|
82
|
+
name = "LC_ALL" if os.environ.get("LC_ALL") else "LC_CTYPE"
|
|
83
|
+
previous = os.environ.get(name)
|
|
84
|
+
os.environ[name] = UTF8_FALLBACK_LOCALE
|
|
85
|
+
logger.warning(
|
|
86
|
+
"No UTF-8 locale set; using %s=%s for tmux", name, UTF8_FALLBACK_LOCALE
|
|
87
|
+
)
|
|
88
|
+
return name, previous
|
|
@@ -26,6 +26,7 @@ from openhands.tools.terminal.constants import (
|
|
|
26
26
|
)
|
|
27
27
|
from openhands.tools.terminal.env import (
|
|
28
28
|
build_terminal_env,
|
|
29
|
+
ensure_utf8_locale,
|
|
29
30
|
normalize_terminal_env,
|
|
30
31
|
)
|
|
31
32
|
from openhands.tools.terminal.terminal.process_priority import (
|
|
@@ -123,6 +124,8 @@ class TmuxPanePool:
|
|
|
123
124
|
if self._initialized:
|
|
124
125
|
return
|
|
125
126
|
|
|
127
|
+
# Before building env, so the shells get the same locale as tmux.
|
|
128
|
+
ensure_utf8_locale()
|
|
126
129
|
env = build_terminal_env(self.env)
|
|
127
130
|
session_name = f"openhands-pool-{self.username}-{uuid.uuid4()}"
|
|
128
131
|
# Stale handles must not reach another pool after tmux restarts.
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/tmux_terminal.py
RENAMED
|
@@ -25,6 +25,7 @@ from openhands.tools.terminal.constants import (
|
|
|
25
25
|
)
|
|
26
26
|
from openhands.tools.terminal.env import (
|
|
27
27
|
build_terminal_env,
|
|
28
|
+
ensure_utf8_locale,
|
|
28
29
|
normalize_terminal_env,
|
|
29
30
|
)
|
|
30
31
|
from openhands.tools.terminal.metadata import CmdOutputMetadata
|
|
@@ -214,6 +215,8 @@ class TmuxTerminal(TerminalInterface):
|
|
|
214
215
|
if self._initialized:
|
|
215
216
|
return
|
|
216
217
|
|
|
218
|
+
# Before building env, so the shell gets the same locale as tmux.
|
|
219
|
+
ensure_utf8_locale()
|
|
217
220
|
env = build_terminal_env(self._env)
|
|
218
221
|
# Disable interactive pagers (git, man, systemctl, ...) so commands that
|
|
219
222
|
# auto-launch `less` on a TTY don't capture the pane and wedge the session.
|
|
@@ -12,6 +12,8 @@ import time
|
|
|
12
12
|
from collections import deque
|
|
13
13
|
from collections.abc import Mapping
|
|
14
14
|
|
|
15
|
+
import psutil
|
|
16
|
+
|
|
15
17
|
from openhands.sdk.logger import get_logger
|
|
16
18
|
from openhands.tools.terminal.constants import (
|
|
17
19
|
CMD_OUTPUT_PS1_BEGIN,
|
|
@@ -348,7 +350,13 @@ class WindowsTerminal(TerminalInterface):
|
|
|
348
350
|
self._command_running_event.clear()
|
|
349
351
|
|
|
350
352
|
def _terminate_child_processes(self) -> bool:
|
|
351
|
-
"""Terminate descendants of the persistent PowerShell process.
|
|
353
|
+
"""Terminate descendants of the persistent PowerShell process.
|
|
354
|
+
|
|
355
|
+
Enumerating descendants and killing them through ``psutil`` avoids the
|
|
356
|
+
WMI query (``Get-CimInstance``) that used to back this method: on a
|
|
357
|
+
loaded Windows runner that query can exceed the subprocess timeout, so
|
|
358
|
+
the child that kept a timed-out command alive was never terminated.
|
|
359
|
+
"""
|
|
352
360
|
if (
|
|
353
361
|
platform.system() != "Windows"
|
|
354
362
|
or self.process is None
|
|
@@ -356,53 +364,29 @@ class WindowsTerminal(TerminalInterface):
|
|
|
356
364
|
):
|
|
357
365
|
return False
|
|
358
366
|
|
|
359
|
-
script = f"""
|
|
360
|
-
$root = {self.process.pid}
|
|
361
|
-
$childrenByParent = @{{}}
|
|
362
|
-
Get-CimInstance Win32_Process | ForEach-Object {{
|
|
363
|
-
$parentId = [int]$_.ParentProcessId
|
|
364
|
-
if (-not $childrenByParent.ContainsKey($parentId)) {{
|
|
365
|
-
$childrenByParent[$parentId] = New-Object System.Collections.Generic.List[int]
|
|
366
|
-
}}
|
|
367
|
-
$childrenByParent[$parentId].Add([int]$_.ProcessId)
|
|
368
|
-
}}
|
|
369
|
-
$toStop = New-Object System.Collections.Generic.List[int]
|
|
370
|
-
function Add-Descendants([int]$processId) {{
|
|
371
|
-
if (-not $childrenByParent.ContainsKey($processId)) {{ return }}
|
|
372
|
-
foreach ($childId in $childrenByParent[$processId]) {{
|
|
373
|
-
if ($childId -eq $PID) {{ continue }}
|
|
374
|
-
$toStop.Add($childId)
|
|
375
|
-
Add-Descendants $childId
|
|
376
|
-
}}
|
|
377
|
-
}}
|
|
378
|
-
Add-Descendants $root
|
|
379
|
-
for ($i = $toStop.Count - 1; $i -ge 0; $i--) {{
|
|
380
|
-
Stop-Process -Id $toStop[$i] -Force -ErrorAction SilentlyContinue
|
|
381
|
-
}}
|
|
382
|
-
if ($toStop.Count -gt 0) {{ exit 0 }} else {{ exit 1 }}
|
|
383
|
-
"""
|
|
384
|
-
startupinfo = None
|
|
385
|
-
startupinfo_cls = getattr(subprocess, "STARTUPINFO", None)
|
|
386
|
-
if startupinfo_cls is not None:
|
|
387
|
-
startupinfo = startupinfo_cls()
|
|
388
|
-
startupinfo.dwFlags |= getattr(subprocess, "STARTF_USESHOWWINDOW", 0)
|
|
389
|
-
creationflags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
|
390
|
-
|
|
391
367
|
try:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
check=False,
|
|
397
|
-
timeout=5.0,
|
|
398
|
-
startupinfo=startupinfo,
|
|
399
|
-
creationflags=creationflags,
|
|
400
|
-
)
|
|
401
|
-
return result.returncode == 0
|
|
402
|
-
except (subprocess.TimeoutExpired, OSError) as exc:
|
|
403
|
-
logger.debug("Failed to terminate PowerShell child processes: %s", exc)
|
|
368
|
+
root = psutil.Process(self.process.pid)
|
|
369
|
+
children = root.children(recursive=True)
|
|
370
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied) as exc:
|
|
371
|
+
logger.debug("Failed to enumerate PowerShell descendants: %s", exc)
|
|
404
372
|
return False
|
|
405
373
|
|
|
374
|
+
if not children:
|
|
375
|
+
return False
|
|
376
|
+
|
|
377
|
+
# Kill leaves first so parents cannot reparent surviving grandchildren
|
|
378
|
+
# before they are terminated.
|
|
379
|
+
terminated = False
|
|
380
|
+
for child in reversed(children):
|
|
381
|
+
try:
|
|
382
|
+
child.kill()
|
|
383
|
+
terminated = True
|
|
384
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied) as exc:
|
|
385
|
+
logger.debug("Failed to terminate child %s: %s", child.pid, exc)
|
|
386
|
+
|
|
387
|
+
psutil.wait_procs(children, timeout=_INTERRUPT_GRACE_SECONDS)
|
|
388
|
+
return terminated
|
|
389
|
+
|
|
406
390
|
def interrupt(self) -> bool:
|
|
407
391
|
"""Interrupt the active command if the process is still alive."""
|
|
408
392
|
if self.process is None or self.process.poll() is not None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.60.0
|
|
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
|
|
@@ -14,7 +14,8 @@ Requires-Dist: tree-sitter-bash>=0.23
|
|
|
14
14
|
Requires-Dist: binaryornot>=0.6.0
|
|
15
15
|
Requires-Dist: cachetools
|
|
16
16
|
Requires-Dist: filelock>=3.20.1
|
|
17
|
-
Requires-Dist: libtmux>=0.
|
|
17
|
+
Requires-Dist: libtmux>=0.62.0
|
|
18
|
+
Requires-Dist: psutil>=7.2.2
|
|
18
19
|
Requires-Dist: pydantic>=2.13.5
|
|
19
20
|
Requires-Dist: browser-use>=0.8.0
|
|
20
21
|
Requires-Dist: func-timeout>=4.3.5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "openhands-tools"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.60.0"
|
|
4
4
|
description = "OpenHands Tools - Runtime tools for AI agents"
|
|
5
5
|
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -12,7 +12,8 @@ dependencies = [
|
|
|
12
12
|
"binaryornot>=0.6.0",
|
|
13
13
|
"cachetools",
|
|
14
14
|
"filelock>=3.20.1",
|
|
15
|
-
"libtmux>=0.
|
|
15
|
+
"libtmux>=0.62.0",
|
|
16
|
+
"psutil>=7.2.2",
|
|
16
17
|
"pydantic>=2.13.5",
|
|
17
18
|
"browser-use>=0.8.0",
|
|
18
19
|
"func-timeout>=4.3.5",
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"""Environment helpers for terminal backends."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from collections.abc import Mapping
|
|
5
|
-
|
|
6
|
-
from openhands.sdk.utils import sanitized_env
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
ENV_VAR_NAME_RE = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def normalize_terminal_env(
|
|
13
|
-
extra_env: Mapping[str, str] | None,
|
|
14
|
-
) -> dict[str, str] | None:
|
|
15
|
-
"""Validate and copy client-provided terminal environment variables."""
|
|
16
|
-
if extra_env is None:
|
|
17
|
-
return None
|
|
18
|
-
|
|
19
|
-
normalized: dict[str, str] = {}
|
|
20
|
-
for key, value in extra_env.items():
|
|
21
|
-
if not isinstance(key, str) or not ENV_VAR_NAME_RE.match(key):
|
|
22
|
-
raise ValueError(f"Invalid terminal environment variable name: {key!r}")
|
|
23
|
-
if not isinstance(value, str):
|
|
24
|
-
raise TypeError(
|
|
25
|
-
"Terminal environment variable values must be strings: "
|
|
26
|
-
f"{key!r}={value!r}"
|
|
27
|
-
)
|
|
28
|
-
normalized[key] = value
|
|
29
|
-
return normalized
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def build_terminal_env(extra_env: Mapping[str, str] | None = None) -> dict[str, str]:
|
|
33
|
-
"""Return the sanitized process environment plus client-provided overrides."""
|
|
34
|
-
env = sanitized_env()
|
|
35
|
-
normalized = normalize_terminal_env(extra_env)
|
|
36
|
-
if normalized:
|
|
37
|
-
env.update(normalized)
|
|
38
|
-
env = sanitized_env(env)
|
|
39
|
-
return env
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/event_storage.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/browser_use/logging_fix.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/child_conversation/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/child_conversation/impl.py
RENAMED
|
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
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/config.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/encoding.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/file_cache.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/history.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/file_editor/utils/shell.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/list_directory/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/list_directory/impl.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/read_file/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/read_file/definition.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/write_file/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/gemini/write_file/definition.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/planning_file_editor/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/planning_file_editor/definition.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/planning_file_editor/impl.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/bash_runner.md
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/code_explorer.md
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/default.md
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/preset/subagents/web_researcher.md
RENAMED
|
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
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/factory.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/terminal/interface.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/timeout_policy.py
RENAMED
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands/tools/terminal/utils/escape_filter.py
RENAMED
|
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
|
{openhands_tools-1.58.2 → openhands_tools-1.60.0}/openhands_tools.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|