openhands-tools 1.53.0__tar.gz → 1.55.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.53.0 → openhands_tools-1.55.0}/PKG-INFO +2 -1
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/delegate/impl.py +6 -1
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/editor.py +25 -13
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/encoding.py +18 -2
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task/definition.py +4 -4
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task/manager.py +10 -2
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task_tracker/definition.py +21 -2
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/constants.py +15 -1
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/terminal_session.py +188 -51
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/tmux_pane_pool.py +7 -8
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/tmux_terminal.py +75 -7
- openhands_tools-1.55.0/openhands/tools/terminal/utils/command.py +195 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands_tools.egg-info/PKG-INFO +2 -1
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands_tools.egg-info/requires.txt +1 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/pyproject.toml +2 -1
- openhands_tools-1.53.0/openhands/tools/terminal/utils/command.py +0 -111
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/apply_patch/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/apply_patch/core.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/apply_patch/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/ask_oracle/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/ask_oracle/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/ask_oracle/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/event_storage.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/logging_fix.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/recording.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/browser_use/server.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/delegate/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/delegate/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/delegate/visualizer.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/exceptions.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/config.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/constants.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/diff.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/file_cache.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/history.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/shell.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/edit/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/edit/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/edit/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/file_change.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/list_directory/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/list_directory/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/list_directory/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/read_file/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/read_file/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/read_file/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/write_file/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/write_file/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/gemini/write_file/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/glob/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/glob/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/glob/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/grep/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/grep/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/grep/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/planning_file_editor/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/planning_file_editor/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/planning_file_editor/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/default.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/gemini.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/gpt5.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/planning.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/subagents/bash_runner.md +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/subagents/code_explorer.md +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/subagents/default.md +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/subagents/web_researcher.md +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/preset/task_outcome.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/py.typed +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task_tracker/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/descriptions.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/env.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/metadata.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/factory.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/interface.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/subprocess_terminal.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/terminal/windows_terminal.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/timeout_policy.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/utils/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/terminal/utils/escape_filter.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/tom_consult/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/tom_consult/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/tom_consult/executor.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/utils/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/utils/timeout.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/workflow/__init__.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/workflow/definition.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/workflow/impl.py +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands_tools.egg-info/SOURCES.txt +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands_tools.egg-info/dependency_links.txt +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands_tools.egg-info/top_level.txt +0 -0
- {openhands_tools-1.53.0 → openhands_tools-1.55.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.55.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
|
|
@@ -12,6 +12,7 @@ Requires-Dist: tree-sitter>=0.24
|
|
|
12
12
|
Requires-Dist: tree-sitter-bash>=0.23
|
|
13
13
|
Requires-Dist: binaryornot>=0.6.0
|
|
14
14
|
Requires-Dist: cachetools
|
|
15
|
+
Requires-Dist: filelock>=3.20.1
|
|
15
16
|
Requires-Dist: libtmux>=0.53.0
|
|
16
17
|
Requires-Dist: pydantic>=2.13.5
|
|
17
18
|
Requires-Dist: browser-use>=0.8.0
|
|
@@ -13,6 +13,7 @@ from openhands.sdk.conversation.state import (
|
|
|
13
13
|
)
|
|
14
14
|
from openhands.sdk.logger import get_logger
|
|
15
15
|
from openhands.sdk.subagent import get_agent_factory
|
|
16
|
+
from openhands.sdk.subagent.scope import inherit_mcp_config
|
|
16
17
|
from openhands.sdk.tool.tool import ToolExecutor
|
|
17
18
|
from openhands.tools.delegate.definition import DelegateObservation
|
|
18
19
|
|
|
@@ -188,7 +189,9 @@ class DelegateExecutor(ToolExecutor):
|
|
|
188
189
|
worker_agent = factory.factory_func(sub_agent_llm)
|
|
189
190
|
|
|
190
191
|
# ensuring that the sub-agent LLM has stream deactivated
|
|
191
|
-
worker_agent =
|
|
192
|
+
worker_agent = inherit_mcp_config(
|
|
193
|
+
parent_conversation.agent, worker_agent
|
|
194
|
+
).model_copy(
|
|
192
195
|
update={
|
|
193
196
|
"llm": worker_agent.llm.model_copy(update={"stream": False})
|
|
194
197
|
}
|
|
@@ -223,6 +226,8 @@ class DelegateExecutor(ToolExecutor):
|
|
|
223
226
|
"_parent_llm_call_context": (
|
|
224
227
|
parent_conversation.get_llm_call_context()
|
|
225
228
|
),
|
|
229
|
+
"mcp_tool_provider": parent_conversation._mcp_tool_provider,
|
|
230
|
+
"_mcp_config_from_parent": True,
|
|
226
231
|
}
|
|
227
232
|
|
|
228
233
|
if factory.definition.max_iteration_per_run is not None:
|
|
@@ -414,11 +414,9 @@ class FileEditor:
|
|
|
414
414
|
)
|
|
415
415
|
|
|
416
416
|
file_content = self.read_file(path, start_line=start_line, end_line=end_line)
|
|
417
|
+
file_content = self._normalize_lines(file_content)
|
|
417
418
|
|
|
418
|
-
|
|
419
|
-
output = self._make_output(
|
|
420
|
-
"\n".join(file_content.splitlines()), str(path), start_line
|
|
421
|
-
) # Remove extra newlines
|
|
419
|
+
output = self._make_output(file_content, str(path), start_line)
|
|
422
420
|
|
|
423
421
|
# Prepend warning if we truncated the end_line
|
|
424
422
|
if warning_message:
|
|
@@ -787,6 +785,17 @@ class FileEditor:
|
|
|
787
785
|
except Exception as e:
|
|
788
786
|
raise ToolError(f"Ran into {e} while trying to read {path}") from None
|
|
789
787
|
|
|
788
|
+
def _normalize_lines(self, content: str) -> str:
|
|
789
|
+
"""Rejoin a template snippet without folding exotic line separators.
|
|
790
|
+
|
|
791
|
+
``read_file`` returns a snippet whose lines are separated by ``\\n``. The
|
|
792
|
+
ranged ``view`` path used to round-trip it through ``str.splitlines()``,
|
|
793
|
+
which also breaks on form feeds and Unicode separators that the rest of
|
|
794
|
+
the editor treats as ordinary characters, shifting line numbers. Joining
|
|
795
|
+
on ``\\n`` instead keeps every other character intact.
|
|
796
|
+
"""
|
|
797
|
+
return "\n".join(content.split("\n"))
|
|
798
|
+
|
|
790
799
|
def _make_output(
|
|
791
800
|
self,
|
|
792
801
|
snippet_content: str,
|
|
@@ -815,14 +824,17 @@ class FileEditor:
|
|
|
815
824
|
truncate_notice=TEXT_FILE_CONTENT_TRUNCATED_NOTICE,
|
|
816
825
|
)
|
|
817
826
|
|
|
827
|
+
# Split on "\n" only, matching how read_file/_count_lines define lines, so that
|
|
828
|
+
# characters splitlines() treats as breaks (\x0c, \u2028, ...) keep line numbers
|
|
829
|
+
# consistent with insert/view_range. A terminating newline ends the last line
|
|
830
|
+
# rather than adding a blank one, so drop the empty field it produces.
|
|
831
|
+
lines = snippet_content.split("\n")
|
|
832
|
+
if lines[-1] == "":
|
|
833
|
+
lines.pop()
|
|
818
834
|
snippet_content = "\n".join(
|
|
819
|
-
[
|
|
820
|
-
f"{i + start_line:6}\t{line}"
|
|
821
|
-
for i, line in enumerate(snippet_content.split("\n"))
|
|
822
|
-
]
|
|
823
|
-
)
|
|
824
|
-
return (
|
|
825
|
-
f"Here's the result of running `cat -n` on {snippet_description}:\n"
|
|
826
|
-
+ snippet_content
|
|
827
|
-
+ "\n"
|
|
835
|
+
[f"{i + start_line:6}\t{line}" for i, line in enumerate(lines)]
|
|
828
836
|
)
|
|
837
|
+
output = f"Here's the result of running `cat -n` on {snippet_description}:\n"
|
|
838
|
+
if snippet_content:
|
|
839
|
+
output += snippet_content + "\n"
|
|
840
|
+
return output
|
{openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/file_editor/utils/encoding.py
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Encoding management for file operations."""
|
|
2
2
|
|
|
3
|
+
import codecs
|
|
3
4
|
import functools
|
|
4
5
|
import inspect
|
|
5
6
|
import os
|
|
@@ -22,7 +23,8 @@ BINARY_CONTROL_CHARS = re.compile(r"[\x00-\x08\x0e-\x1f\x7f]")
|
|
|
22
23
|
# file's encoding. Short non-UTF-8 files fall below the detector's confidence
|
|
23
24
|
# threshold and are reported as the default encoding, so the detected value
|
|
24
25
|
# alone is not enough to recover them. Ordered most to least likely for source
|
|
25
|
-
# files; the detector's own guess is tried
|
|
26
|
+
# files; the detector's own guess is tried right after UTF-8 when it is one of
|
|
27
|
+
# these.
|
|
26
28
|
TEXT_DECODE_CANDIDATES = ("utf-8", "cp1252", "latin-1", "cp1251")
|
|
27
29
|
|
|
28
30
|
# charset_normalizer reports some codecs under IANA names; map them to the
|
|
@@ -70,6 +72,16 @@ class EncodingManager:
|
|
|
70
72
|
with open(path, "rb") as f:
|
|
71
73
|
raw_data = f.read(sample_size)
|
|
72
74
|
|
|
75
|
+
if raw_data.startswith(codecs.BOM_UTF8):
|
|
76
|
+
return "utf-8-sig"
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
raw_data.decode(self.default_encoding)
|
|
80
|
+
except UnicodeDecodeError:
|
|
81
|
+
pass
|
|
82
|
+
else:
|
|
83
|
+
return self.default_encoding
|
|
84
|
+
|
|
73
85
|
# Use charset_normalizer instead of chardet
|
|
74
86
|
results = charset_normalizer.detect(raw_data)
|
|
75
87
|
|
|
@@ -116,7 +128,11 @@ class EncodingManager:
|
|
|
116
128
|
|
|
117
129
|
def _recover_encoding(self, path: Path) -> str | None:
|
|
118
130
|
"""Return a codec that decodes ``path`` to control-byte-free text."""
|
|
119
|
-
candidates = (
|
|
131
|
+
candidates = (
|
|
132
|
+
self.default_encoding,
|
|
133
|
+
self._best_guess_encoding(path),
|
|
134
|
+
*TEXT_DECODE_CANDIDATES,
|
|
135
|
+
)
|
|
120
136
|
for candidate in dict.fromkeys(c for c in candidates if c):
|
|
121
137
|
try:
|
|
122
138
|
text = path.read_text(encoding=candidate)
|
|
@@ -244,8 +244,9 @@ class TaskToolSet(ToolDefinition[TaskAction, TaskObservation]):
|
|
|
244
244
|
confirmation policy requires user approval. Receives
|
|
245
245
|
`(task_id, pending_actions)` and must return `True` to
|
|
246
246
|
approve or `False` to reject.
|
|
247
|
-
sub_agent_scope:
|
|
248
|
-
|
|
247
|
+
sub_agent_scope: Whether the sub-agents it offers and starts must
|
|
248
|
+
stay within this agent's tools. Sub-agents always inherit this
|
|
249
|
+
agent's MCP servers.
|
|
249
250
|
|
|
250
251
|
Returns:
|
|
251
252
|
List containing a single TaskTool.
|
|
@@ -264,8 +265,7 @@ class TaskToolSet(ToolDefinition[TaskAction, TaskObservation]):
|
|
|
264
265
|
agent_types_info = get_factory_info(lambda d: d.name in registered)
|
|
265
266
|
else:
|
|
266
267
|
agent_types_info = (
|
|
267
|
-
"- None: every registered agent uses tools
|
|
268
|
-
"this agent does not have."
|
|
268
|
+
"- None: every registered agent uses tools this agent does not have."
|
|
269
269
|
)
|
|
270
270
|
|
|
271
271
|
task_tool_examples = "\n".join(
|
|
@@ -35,7 +35,11 @@ from openhands.sdk.logger import get_logger
|
|
|
35
35
|
from openhands.sdk.observability.laminar import detached_delegate_context
|
|
36
36
|
from openhands.sdk.security import ConfirmationPolicyBase
|
|
37
37
|
from openhands.sdk.subagent.registry import AgentFactory, get_agent_factory
|
|
38
|
-
from openhands.sdk.subagent.scope import
|
|
38
|
+
from openhands.sdk.subagent.scope import (
|
|
39
|
+
SubAgentScope,
|
|
40
|
+
inherit_mcp_config,
|
|
41
|
+
scope_delegation_tools,
|
|
42
|
+
)
|
|
39
43
|
|
|
40
44
|
|
|
41
45
|
if TYPE_CHECKING:
|
|
@@ -225,6 +229,8 @@ class TaskManager:
|
|
|
225
229
|
_parent_llm_call_context=(
|
|
226
230
|
self.parent_conversation.get_llm_call_context()
|
|
227
231
|
),
|
|
232
|
+
mcp_tool_provider=self.parent_conversation._mcp_tool_provider,
|
|
233
|
+
_mcp_config_from_parent=True,
|
|
228
234
|
delete_on_close=True,
|
|
229
235
|
observability_metadata=self._delegate_observability_metadata(
|
|
230
236
|
task_id=resume, subagent_type=subagent_type, link=link
|
|
@@ -328,6 +334,8 @@ class TaskManager:
|
|
|
328
334
|
max_budget_per_run=max_budget_per_run,
|
|
329
335
|
hook_config=hook_config,
|
|
330
336
|
_parent_llm_call_context=parent.get_llm_call_context(),
|
|
337
|
+
mcp_tool_provider=parent._mcp_tool_provider,
|
|
338
|
+
_mcp_config_from_parent=True,
|
|
331
339
|
delete_on_close=True,
|
|
332
340
|
prompt_cache_key=str(parent.state.id),
|
|
333
341
|
observability_metadata=self._delegate_observability_metadata(
|
|
@@ -391,7 +399,7 @@ class TaskManager:
|
|
|
391
399
|
)
|
|
392
400
|
|
|
393
401
|
# ensuring that the sub-agent LLM has stream deactivated
|
|
394
|
-
sub_agent = sub_agent.model_copy(
|
|
402
|
+
sub_agent = inherit_mcp_config(parent.agent, sub_agent).model_copy(
|
|
395
403
|
update={
|
|
396
404
|
"llm": sub_agent.llm.model_copy(update={"stream": False}),
|
|
397
405
|
"tools": scope_delegation_tools(sub_agent.tools, self._sub_agent_scope),
|
{openhands_tools-1.53.0 → openhands_tools-1.55.0}/openhands/tools/task_tracker/definition.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from collections.abc import Sequence
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING, ClassVar, Literal
|
|
4
|
+
from typing import TYPE_CHECKING, ClassVar, Literal, get_args
|
|
5
5
|
|
|
6
|
-
from pydantic import BaseModel, Field, ValidationError
|
|
6
|
+
from pydantic import BaseModel, Field, ValidationError, field_validator
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
@@ -28,6 +28,14 @@ logger = get_logger(__name__)
|
|
|
28
28
|
# Type alias for task tracker status
|
|
29
29
|
TaskTrackerStatusType = Literal["todo", "in_progress", "done"]
|
|
30
30
|
|
|
31
|
+
# Models trained on other agents' todo tools send these names for our statuses.
|
|
32
|
+
_STATUS_ALIASES: dict[str, TaskTrackerStatusType] = {
|
|
33
|
+
"pending": "todo",
|
|
34
|
+
"to_do": "todo",
|
|
35
|
+
"completed": "done",
|
|
36
|
+
"complete": "done",
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
|
|
32
40
|
class TaskItem(BaseModel):
|
|
33
41
|
title: str = Field(..., description="A brief title for the task.")
|
|
@@ -38,6 +46,16 @@ class TaskItem(BaseModel):
|
|
|
38
46
|
"One of 'todo', 'in_progress', or 'done'.",
|
|
39
47
|
)
|
|
40
48
|
|
|
49
|
+
@field_validator("status", mode="before")
|
|
50
|
+
@classmethod
|
|
51
|
+
def _normalize_status(cls, value: object) -> object:
|
|
52
|
+
if not isinstance(value, str):
|
|
53
|
+
return value
|
|
54
|
+
normalized = value.strip().lower().replace("-", "_").replace(" ", "_")
|
|
55
|
+
if normalized in get_args(TaskTrackerStatusType):
|
|
56
|
+
return normalized
|
|
57
|
+
return _STATUS_ALIASES.get(normalized, value)
|
|
58
|
+
|
|
41
59
|
|
|
42
60
|
class TaskTrackerAction(Action):
|
|
43
61
|
"""An action where the agent writes or updates a task list for task management."""
|
|
@@ -406,6 +424,7 @@ class TaskTrackerTool(ToolDefinition[TaskTrackerAction, TaskTrackerObservation])
|
|
|
406
424
|
catalog_description: ClassVar[str] = (
|
|
407
425
|
"Keep a running task list to organise multi-step work."
|
|
408
426
|
)
|
|
427
|
+
conversation_local: ClassVar[bool] = True
|
|
409
428
|
|
|
410
429
|
@classmethod
|
|
411
430
|
def create(cls, conv_state: "ConversationState") -> Sequence["TaskTrackerTool"]:
|
|
@@ -30,12 +30,26 @@ TIMEOUT_MESSAGE_TEMPLATE: Final[str] = (
|
|
|
30
30
|
# How long to wait with no new output before considering it a no-change timeout
|
|
31
31
|
NO_CHANGE_TIMEOUT_SECONDS: Final[int] = 30
|
|
32
32
|
|
|
33
|
-
# How often to poll for new output in seconds
|
|
33
|
+
# How often to poll for new output in seconds, once a command has run for a while
|
|
34
34
|
POLL_INTERVAL: Final[float] = 0.5
|
|
35
|
+
# Shortest poll interval, used right after a command is sent
|
|
36
|
+
MIN_POLL_INTERVAL: Final[float] = 0.02
|
|
35
37
|
HISTORY_LIMIT: Final[int] = 10_000
|
|
36
38
|
|
|
37
39
|
TMUX_SOCKET_NAME: Final[str] = "openhands"
|
|
38
40
|
|
|
41
|
+
# tmux user option recording the PID of the process that created a socket.
|
|
42
|
+
# Startup cleanup reads it so it does not kill the live sessions of a sibling
|
|
43
|
+
# agent-server that shares one externally supplied TMUX_TMPDIR.
|
|
44
|
+
TMUX_SOCKET_OWNER_OPTION: Final[str] = "@openhands_socket_owner_pid"
|
|
45
|
+
|
|
46
|
+
# Cross-process lock file, inside the tmux socket directory, that serializes
|
|
47
|
+
# socket creation with the agent-server's startup cleanup. A socket only exists
|
|
48
|
+
# between creation and the recording of its owner, so both operations take this
|
|
49
|
+
# lock to keep cleanup from reclaiming a socket that a live process is still
|
|
50
|
+
# setting up.
|
|
51
|
+
TMUX_SOCKET_CREATION_LOCK: Final[str] = ".openhands-socket-creation.lock"
|
|
52
|
+
|
|
39
53
|
# Tmux session dimensions (columns x rows). Keep the viewport wide enough for
|
|
40
54
|
# common command output while leaving scrollback retention to HISTORY_LIMIT.
|
|
41
55
|
# Output wider than TMUX_SESSION_WIDTH columns will wrap; this is an accepted
|