openhands-tools 1.55.1__tar.gz → 1.57.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.55.1 → openhands_tools-1.57.0}/PKG-INFO +1 -1
- openhands_tools-1.57.0/openhands/tools/child_conversation/__init__.py +36 -0
- openhands_tools-1.57.0/openhands/tools/child_conversation/definition.py +162 -0
- openhands_tools-1.57.0/openhands/tools/child_conversation/impl.py +155 -0
- openhands_tools-1.57.0/openhands/tools/terminal/terminal/process_priority.py +39 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/subprocess_terminal.py +4 -1
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/tmux_pane_pool.py +8 -3
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/tmux_terminal.py +30 -7
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/windows_terminal.py +10 -4
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands_tools.egg-info/PKG-INFO +1 -1
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands_tools.egg-info/SOURCES.txt +8 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/pyproject.toml +1 -1
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/apply_patch/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/apply_patch/core.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/apply_patch/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/ask_oracle/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/ask_oracle/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/ask_oracle/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/event_storage.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/logging_fix.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/recording.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/server.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/delegate/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/delegate/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/delegate/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/delegate/visualizer.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/editor.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/exceptions.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/config.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/constants.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/diff.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/encoding.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/file_cache.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/history.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/shell.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/edit/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/edit/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/edit/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/file_change.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/list_directory/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/list_directory/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/list_directory/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/read_file/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/read_file/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/read_file/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/write_file/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/write_file/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/write_file/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/glob/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/glob/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/glob/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/grep/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/grep/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/grep/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/planning_file_editor/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/planning_file_editor/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/planning_file_editor/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/default.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/gemini.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/gpt5.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/planning.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/bash_runner.md +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/code_explorer.md +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/default.md +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/web_researcher.md +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/task_outcome.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/py.typed +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task/manager.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task_tracker/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task_tracker/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/constants.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/descriptions.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/env.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/metadata.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/factory.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/interface.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/terminal_session.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/timeout_policy.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/utils/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/utils/command.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/utils/escape_filter.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/tom_consult/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/tom_consult/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/tom_consult/executor.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/utils/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/utils/timeout.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/workflow/__init__.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/workflow/definition.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/workflow/impl.py +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands_tools.egg-info/dependency_links.txt +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands_tools.egg-info/requires.txt +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands_tools.egg-info/top_level.txt +0 -0
- {openhands_tools-1.55.1 → openhands_tools-1.57.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.57.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
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Child-conversation tool package.
|
|
2
|
+
|
|
3
|
+
Provides the ``start_child_conversation`` tool: a server-executed tool that
|
|
4
|
+
starts a child conversation on the same backend as its parent and returns the
|
|
5
|
+
child's id and launch status to the parent agent. The launch itself is
|
|
6
|
+
delegated over HTTP to a child-launch endpoint, which defaults to the
|
|
7
|
+
agent-server running the tool (``POST /api/conversations/{id}/children``) and
|
|
8
|
+
can be pointed elsewhere via the ``launch_url`` tool parameter so a hosting
|
|
9
|
+
backend can run its own provisioning lifecycle.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
from openhands.tools.child_conversation import StartChildConversationTool
|
|
13
|
+
|
|
14
|
+
agent = Agent(
|
|
15
|
+
llm=llm,
|
|
16
|
+
tools=[Tool(name=StartChildConversationTool.name)],
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
The tool is registered by the agent-server; it is not part of the default
|
|
20
|
+
tool preset because it requires a server to create the child on.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from openhands.tools.child_conversation.definition import (
|
|
24
|
+
StartChildConversationAction,
|
|
25
|
+
StartChildConversationObservation,
|
|
26
|
+
StartChildConversationTool,
|
|
27
|
+
)
|
|
28
|
+
from openhands.tools.child_conversation.impl import StartChildConversationExecutor
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"StartChildConversationAction",
|
|
33
|
+
"StartChildConversationExecutor",
|
|
34
|
+
"StartChildConversationObservation",
|
|
35
|
+
"StartChildConversationTool",
|
|
36
|
+
]
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Action, observation, and tool definitions for start_child_conversation."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import TYPE_CHECKING, ClassVar, Literal, Self
|
|
5
|
+
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
|
|
9
|
+
from openhands.sdk.tool.registry import register_tool
|
|
10
|
+
from openhands.sdk.tool.tool import (
|
|
11
|
+
Action,
|
|
12
|
+
Observation,
|
|
13
|
+
ToolAnnotations,
|
|
14
|
+
ToolDefinition,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from openhands.sdk.conversation.state import ConversationState
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class StartChildConversationAction(Action):
|
|
23
|
+
"""Action that starts a child conversation on the parent's backend."""
|
|
24
|
+
|
|
25
|
+
task: str = Field(
|
|
26
|
+
description=(
|
|
27
|
+
"Self-contained brief for the child: the goal, relevant files or "
|
|
28
|
+
"paths, constraints, and the expected deliverable. The child cannot "
|
|
29
|
+
"see this conversation's history."
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
title: str | None = Field(
|
|
33
|
+
default=None, description="Optional short title for the child conversation."
|
|
34
|
+
)
|
|
35
|
+
isolation: Literal["worktree", "shared"] = Field(
|
|
36
|
+
default="worktree",
|
|
37
|
+
description=(
|
|
38
|
+
"'worktree' gives the child its own git worktree and branch when the "
|
|
39
|
+
"workspace is a git repository; 'shared' runs it in the same directory."
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def visualize(self) -> Text:
|
|
45
|
+
content = Text()
|
|
46
|
+
content.append("Start child conversation", style="bold cyan")
|
|
47
|
+
if self.title:
|
|
48
|
+
content.append(f": {self.title}")
|
|
49
|
+
content.append(f" [{self.isolation}]\n")
|
|
50
|
+
content.append(self.task)
|
|
51
|
+
return content
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class StartChildConversationObservation(Observation):
|
|
55
|
+
"""Result of a child conversation launch."""
|
|
56
|
+
|
|
57
|
+
conversation_id: str | None = None
|
|
58
|
+
parent_conversation_id: str | None = None
|
|
59
|
+
status: str | None = None
|
|
60
|
+
title: str | None = None
|
|
61
|
+
url: str | None = None
|
|
62
|
+
workspace: str | None = None
|
|
63
|
+
isolation: Literal["worktree", "shared"] | None = None
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def visualize(self) -> Text:
|
|
67
|
+
content = Text()
|
|
68
|
+
if self.is_error:
|
|
69
|
+
content.append("Child conversation launch failed", style="bold red")
|
|
70
|
+
content.append("\n")
|
|
71
|
+
content.append(self.text)
|
|
72
|
+
return content
|
|
73
|
+
content.append("Started child conversation", style="bold green")
|
|
74
|
+
if self.title:
|
|
75
|
+
content.append(f" '{self.title}'")
|
|
76
|
+
if self.conversation_id:
|
|
77
|
+
content.append(f" ({self.conversation_id})")
|
|
78
|
+
if self.status:
|
|
79
|
+
content.append(f" - {self.status}")
|
|
80
|
+
if self.url:
|
|
81
|
+
content.append("\n")
|
|
82
|
+
content.append(self.url, style="underline")
|
|
83
|
+
return content
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
_DESCRIPTION = (
|
|
87
|
+
"Start a child conversation that runs on the same backend as this "
|
|
88
|
+
"conversation, with its own agent and history, to work on a delegated task "
|
|
89
|
+
"in parallel.\n\n"
|
|
90
|
+
"The child inherits this conversation's configuration and workspace. `task` "
|
|
91
|
+
"must be a self-contained brief: the child has no access to this "
|
|
92
|
+
"conversation's history, so include the goal, relevant paths, constraints "
|
|
93
|
+
"and the expected deliverable. Use `title` to name it. `isolation` controls "
|
|
94
|
+
"the workspace: `worktree` (default) gives the child its own git worktree "
|
|
95
|
+
"and branch when the workspace is a git repository; the worktree starts "
|
|
96
|
+
"from the repository's default branch, not from this conversation's branch "
|
|
97
|
+
"or uncommitted changes, so use `shared` when the child must see them. "
|
|
98
|
+
"`shared` runs it in the same directory; backends that manage workspaces "
|
|
99
|
+
"themselves may ignore this and report what was applied.\n\n"
|
|
100
|
+
"The result contains the child's conversation id, its initial status and, "
|
|
101
|
+
"when available, a URL. Report the id and URL to the user. A launch is not "
|
|
102
|
+
"idempotent: call this once per task and do not retry a launch that already "
|
|
103
|
+
"returned a conversation id."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class StartChildConversationTool(
|
|
108
|
+
ToolDefinition[StartChildConversationAction, StartChildConversationObservation]
|
|
109
|
+
):
|
|
110
|
+
"""Tool that launches a same-backend child conversation."""
|
|
111
|
+
|
|
112
|
+
# Attached by the host that provides the launcher (the agent-server, or a
|
|
113
|
+
# hosting backend through ``launch_url``), not picked from the catalog.
|
|
114
|
+
user_selectable: ClassVar[bool] = False
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def create(
|
|
118
|
+
cls,
|
|
119
|
+
conv_state: "ConversationState",
|
|
120
|
+
launch_url: str | None = None,
|
|
121
|
+
**params,
|
|
122
|
+
) -> Sequence[Self]:
|
|
123
|
+
"""Create the tool bound to the current conversation.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
conv_state: State of the conversation that becomes the parent.
|
|
127
|
+
launch_url: Optional child-launch endpoint. Defaults to the
|
|
128
|
+
agent-server running this tool; a hosting backend can point it
|
|
129
|
+
at its own launcher.
|
|
130
|
+
"""
|
|
131
|
+
if params:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
"StartChildConversationTool does not accept parameters: "
|
|
134
|
+
f"{sorted(params)}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Import here to keep module import light and avoid import cycles.
|
|
138
|
+
from openhands.tools.child_conversation.impl import (
|
|
139
|
+
StartChildConversationExecutor,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
executor = StartChildConversationExecutor(
|
|
143
|
+
parent_conversation_id=conv_state.id, launch_url=launch_url
|
|
144
|
+
)
|
|
145
|
+
return [
|
|
146
|
+
cls(
|
|
147
|
+
description=_DESCRIPTION,
|
|
148
|
+
action_type=StartChildConversationAction,
|
|
149
|
+
observation_type=StartChildConversationObservation,
|
|
150
|
+
executor=executor,
|
|
151
|
+
annotations=ToolAnnotations(
|
|
152
|
+
readOnlyHint=False,
|
|
153
|
+
destructiveHint=False,
|
|
154
|
+
idempotentHint=False,
|
|
155
|
+
openWorldHint=True,
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# Automatically register when this module is imported.
|
|
162
|
+
register_tool(StartChildConversationTool.name, StartChildConversationTool)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Executor for the start_child_conversation tool."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
from pydantic import ValidationError
|
|
10
|
+
|
|
11
|
+
from openhands.sdk.conversation.request import (
|
|
12
|
+
StartChildConversationRequest,
|
|
13
|
+
StartChildConversationResponse,
|
|
14
|
+
)
|
|
15
|
+
from openhands.sdk.logger import get_logger
|
|
16
|
+
from openhands.sdk.tool.tool import ToolExecutor
|
|
17
|
+
from openhands.tools.child_conversation.definition import (
|
|
18
|
+
StartChildConversationAction,
|
|
19
|
+
StartChildConversationObservation,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from openhands.sdk.conversation.impl.local_conversation import LocalConversation
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
logger = get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
# Same seam ``LookupSecret`` uses to reach the agent-server that runs this tool.
|
|
30
|
+
INTERNAL_SERVER_URL_ENV = "OH_INTERNAL_SERVER_URL"
|
|
31
|
+
DEFAULT_INTERNAL_SERVER_URL = "http://127.0.0.1:8000"
|
|
32
|
+
# v1 and v0 names of the agent-server session key, as exported by the server.
|
|
33
|
+
SESSION_API_KEY_ENVS = ("OH_SESSION_API_KEYS_0", "SESSION_API_KEY")
|
|
34
|
+
SESSION_API_KEY_HEADER = "X-Session-API-Key"
|
|
35
|
+
# A launch may include worktree or sandbox provisioning; mirror the MCP tool
|
|
36
|
+
# timeout rather than httpx's 5 second default.
|
|
37
|
+
CHILD_LAUNCH_TIMEOUT_SECONDS = 300.0
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def default_launch_url(parent_conversation_id: UUID) -> str:
|
|
41
|
+
"""Child-launch endpoint of the agent-server running this tool."""
|
|
42
|
+
base = os.getenv(INTERNAL_SERVER_URL_ENV, DEFAULT_INTERNAL_SERVER_URL).rstrip("/")
|
|
43
|
+
return f"{base}/api/conversations/{parent_conversation_id}/children"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def session_api_key_headers() -> dict[str, str]:
|
|
47
|
+
"""Auth header for the launcher, taken from the agent-server's own env.
|
|
48
|
+
|
|
49
|
+
The key identifies this server to its launcher, as it does for the
|
|
50
|
+
server's webhook subscribers. ``launch_url`` is chosen by whoever assembles
|
|
51
|
+
the conversation's agent, and the header grants that party nothing new: a
|
|
52
|
+
hosting backend minted the key, and a direct caller had to present one to
|
|
53
|
+
create the conversation.
|
|
54
|
+
"""
|
|
55
|
+
for env_name in SESSION_API_KEY_ENVS:
|
|
56
|
+
value = os.getenv(env_name)
|
|
57
|
+
if value:
|
|
58
|
+
return {SESSION_API_KEY_HEADER: value}
|
|
59
|
+
return {}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _response_detail(response: httpx.Response) -> str:
|
|
63
|
+
try:
|
|
64
|
+
detail = response.json().get("detail")
|
|
65
|
+
except (ValueError, AttributeError):
|
|
66
|
+
detail = None
|
|
67
|
+
if isinstance(detail, str) and detail:
|
|
68
|
+
return detail
|
|
69
|
+
if detail is not None:
|
|
70
|
+
return json.dumps(detail)
|
|
71
|
+
return response.text[:500]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class StartChildConversationExecutor(
|
|
75
|
+
ToolExecutor[StartChildConversationAction, StartChildConversationObservation]
|
|
76
|
+
):
|
|
77
|
+
"""POST the launch request to the child-launch endpoint and report back.
|
|
78
|
+
|
|
79
|
+
The executor is deliberately backend-agnostic: it only knows the wire
|
|
80
|
+
contract (``StartChildConversationRequest`` in,
|
|
81
|
+
``StartChildConversationResponse`` out) and where to send it. By default it
|
|
82
|
+
targets the agent-server that runs this tool, authenticated with that
|
|
83
|
+
server's own session API key from the environment.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
parent_conversation_id: UUID,
|
|
89
|
+
launch_url: str | None = None,
|
|
90
|
+
timeout: float = CHILD_LAUNCH_TIMEOUT_SECONDS,
|
|
91
|
+
transport: httpx.BaseTransport | None = None,
|
|
92
|
+
):
|
|
93
|
+
self.parent_conversation_id = parent_conversation_id
|
|
94
|
+
self.launch_url = launch_url
|
|
95
|
+
self.timeout = timeout
|
|
96
|
+
self._transport = transport
|
|
97
|
+
|
|
98
|
+
def __call__(
|
|
99
|
+
self,
|
|
100
|
+
action: StartChildConversationAction,
|
|
101
|
+
conversation: "LocalConversation | None" = None, # noqa: ARG002
|
|
102
|
+
) -> StartChildConversationObservation:
|
|
103
|
+
url = self.launch_url or default_launch_url(self.parent_conversation_id)
|
|
104
|
+
try:
|
|
105
|
+
payload = StartChildConversationRequest(
|
|
106
|
+
task=action.task, title=action.title, isolation=action.isolation
|
|
107
|
+
).model_dump(mode="json")
|
|
108
|
+
except ValidationError as exc:
|
|
109
|
+
return self._error(f"Invalid child conversation request: {exc}")
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
with httpx.Client(
|
|
113
|
+
timeout=self.timeout, transport=self._transport
|
|
114
|
+
) as client:
|
|
115
|
+
response = client.post(
|
|
116
|
+
url, json=payload, headers=session_api_key_headers()
|
|
117
|
+
)
|
|
118
|
+
response.raise_for_status()
|
|
119
|
+
result = StartChildConversationResponse.model_validate(response.json())
|
|
120
|
+
except httpx.HTTPStatusError as exc:
|
|
121
|
+
return self._error(
|
|
122
|
+
"Child conversation launch failed "
|
|
123
|
+
f"({exc.response.status_code}): {_response_detail(exc.response)}"
|
|
124
|
+
)
|
|
125
|
+
except httpx.TimeoutException:
|
|
126
|
+
return self._error(
|
|
127
|
+
"Child conversation launch timed out after "
|
|
128
|
+
f"{self.timeout:.0f} seconds. The child may still have been "
|
|
129
|
+
"created; check with the user before retrying."
|
|
130
|
+
)
|
|
131
|
+
except (httpx.HTTPError, ValueError, ValidationError) as exc:
|
|
132
|
+
logger.warning("start_child_conversation failed against %s: %s", url, exc)
|
|
133
|
+
return self._error(
|
|
134
|
+
f"Child conversation launch failed: {type(exc).__name__}: {exc}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
summary = (
|
|
138
|
+
f"Started child conversation {result.conversation_id} "
|
|
139
|
+
f"(status: {result.status}).\n"
|
|
140
|
+
f"{json.dumps(result.model_dump(mode='json'), indent=2)}"
|
|
141
|
+
)
|
|
142
|
+
return StartChildConversationObservation.from_text(
|
|
143
|
+
text=summary,
|
|
144
|
+
conversation_id=str(result.conversation_id),
|
|
145
|
+
parent_conversation_id=str(result.parent_conversation_id),
|
|
146
|
+
status=result.status,
|
|
147
|
+
title=result.title,
|
|
148
|
+
url=result.url,
|
|
149
|
+
workspace=result.workspace,
|
|
150
|
+
isolation=result.isolation,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def _error(message: str) -> StartChildConversationObservation:
|
|
155
|
+
return StartChildConversationObservation.from_text(text=message, is_error=True)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Lower the CPU priority of agent terminals so they cannot starve the server."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import shutil
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from typing import Final
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
TERMINAL_PROCESS_PRIORITY_ENV: Final[str] = "OH_TERMINAL_PROCESS_PRIORITY"
|
|
11
|
+
|
|
12
|
+
# macOS largely ignores nice; the utility QoS clamp is what keeps the server
|
|
13
|
+
# responsive. Avoid the background clamp: it also throttles I/O heavily.
|
|
14
|
+
_TASKPOLICY_PATH: Final[str] = "/usr/sbin/taskpolicy"
|
|
15
|
+
_LINUX_NICE_INCREMENT: Final[str] = "10"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def should_lower_process_priority(env: Mapping[str, str]) -> bool:
|
|
19
|
+
"""Return False when the terminal env opts out with ``none``."""
|
|
20
|
+
value = env.get(TERMINAL_PROCESS_PRIORITY_ENV, "")
|
|
21
|
+
return value.strip().lower() != "none"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def process_priority_prefix(env: Mapping[str, str]) -> list[str]:
|
|
25
|
+
"""Return an argv prefix that runs the shell at lower CPU priority.
|
|
26
|
+
|
|
27
|
+
This must be an argv prefix rather than a ``preexec_fn``: a macOS QoS class
|
|
28
|
+
set on the calling thread does not survive ``exec``. Both ``taskpolicy``
|
|
29
|
+
and ``nice`` are inherited by every process the shell starts.
|
|
30
|
+
"""
|
|
31
|
+
if not should_lower_process_priority(env):
|
|
32
|
+
return []
|
|
33
|
+
|
|
34
|
+
system = platform.system()
|
|
35
|
+
if system == "Darwin" and os.path.exists(_TASKPOLICY_PATH):
|
|
36
|
+
return [_TASKPOLICY_PATH, "-c", "utility"]
|
|
37
|
+
if system == "Linux" and (nice_path := shutil.which("nice")) is not None:
|
|
38
|
+
return [nice_path, "-n", _LINUX_NICE_INCREMENT]
|
|
39
|
+
return []
|
|
@@ -35,6 +35,9 @@ from openhands.tools.terminal.env import (
|
|
|
35
35
|
from openhands.tools.terminal.metadata import CmdOutputMetadata
|
|
36
36
|
from openhands.tools.terminal.terminal import TerminalInterface
|
|
37
37
|
from openhands.tools.terminal.terminal.interface import parse_ctrl_key
|
|
38
|
+
from openhands.tools.terminal.terminal.process_priority import (
|
|
39
|
+
process_priority_prefix,
|
|
40
|
+
)
|
|
38
41
|
|
|
39
42
|
|
|
40
43
|
logger = get_logger(__name__)
|
|
@@ -151,7 +154,7 @@ class SubprocessTerminal(TerminalInterface):
|
|
|
151
154
|
env["PS2"] = ""
|
|
152
155
|
env["TERM"] = "xterm-256color"
|
|
153
156
|
|
|
154
|
-
bash_cmd = [resolved_shell_path, "-i"]
|
|
157
|
+
bash_cmd = [*process_priority_prefix(env), resolved_shell_path, "-i"]
|
|
155
158
|
|
|
156
159
|
# Create a PTY; give the slave to the child, keep the master
|
|
157
160
|
master_fd, slave_fd = pty.openpty()
|
|
@@ -6,6 +6,7 @@ tmux session, enabling concurrent command execution across panes.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import shlex
|
|
9
10
|
import threading
|
|
10
11
|
import time
|
|
11
12
|
import uuid
|
|
@@ -27,6 +28,9 @@ from openhands.tools.terminal.env import (
|
|
|
27
28
|
build_terminal_env,
|
|
28
29
|
normalize_terminal_env,
|
|
29
30
|
)
|
|
31
|
+
from openhands.tools.terminal.terminal.process_priority import (
|
|
32
|
+
process_priority_prefix,
|
|
33
|
+
)
|
|
30
34
|
from openhands.tools.terminal.terminal.tmux_terminal import (
|
|
31
35
|
TmuxTerminal,
|
|
32
36
|
_new_owned_session,
|
|
@@ -169,13 +173,14 @@ class TmuxPanePool:
|
|
|
169
173
|
"""Create a new PooledTmuxTerminal within the shared session."""
|
|
170
174
|
assert self._session is not None
|
|
171
175
|
|
|
172
|
-
shell_command = "/bin/bash"
|
|
176
|
+
shell_command = ["/bin/bash"]
|
|
173
177
|
if self.username in ["root", "openhands"]:
|
|
174
|
-
shell_command =
|
|
178
|
+
shell_command = ["su", self.username, "-"]
|
|
179
|
+
priority_prefix = process_priority_prefix(build_terminal_env(self.env))
|
|
175
180
|
|
|
176
181
|
window = self._session.new_window(
|
|
177
182
|
window_name=f"pane-{len(self._all_panes)}",
|
|
178
|
-
window_shell=shell_command,
|
|
183
|
+
window_shell=shlex.join([*priority_prefix, *shell_command]),
|
|
179
184
|
start_directory=self.work_dir,
|
|
180
185
|
)
|
|
181
186
|
active_pane = window.active_pane
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/tmux_terminal.py
RENAMED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
+
import shlex
|
|
6
|
+
import sys
|
|
5
7
|
import time
|
|
6
8
|
import uuid
|
|
7
9
|
from collections.abc import Iterator, Mapping
|
|
@@ -28,6 +30,9 @@ from openhands.tools.terminal.env import (
|
|
|
28
30
|
from openhands.tools.terminal.metadata import CmdOutputMetadata
|
|
29
31
|
from openhands.tools.terminal.terminal import TerminalInterface
|
|
30
32
|
from openhands.tools.terminal.terminal.interface import parse_ctrl_key
|
|
33
|
+
from openhands.tools.terminal.terminal.process_priority import (
|
|
34
|
+
process_priority_prefix,
|
|
35
|
+
)
|
|
31
36
|
|
|
32
37
|
|
|
33
38
|
logger = get_logger(__name__)
|
|
@@ -75,7 +80,7 @@ def _install_libtmux_redaction_filter() -> None:
|
|
|
75
80
|
|
|
76
81
|
|
|
77
82
|
@contextmanager
|
|
78
|
-
def _socket_creation_lock() -> Iterator[None]:
|
|
83
|
+
def _socket_creation_lock(socket_dir: Path | None = None) -> Iterator[None]:
|
|
79
84
|
"""Serialize socket creation with the agent-server's startup cleanup.
|
|
80
85
|
|
|
81
86
|
A tmux socket exists between ``new-session`` and the recording of its owner
|
|
@@ -85,7 +90,8 @@ def _socket_creation_lock() -> Iterator[None]:
|
|
|
85
90
|
directory, which is the one path every process sharing ``TMUX_TMPDIR``
|
|
86
91
|
agrees on even while tmux has not created any socket yet.
|
|
87
92
|
"""
|
|
88
|
-
socket_dir
|
|
93
|
+
if socket_dir is None:
|
|
94
|
+
socket_dir = Path(os.environ.get("TMUX_TMPDIR", "/tmp")) / f"tmux-{os.getuid()}"
|
|
89
95
|
# tmux refuses a socket directory that is group/world accessible, and
|
|
90
96
|
# FileLock would create it with the umask default, so create it 0700 first.
|
|
91
97
|
socket_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -124,9 +130,26 @@ def _new_owned_session(
|
|
|
124
130
|
lock. Startup cleanup in another process takes the same lock, so it can
|
|
125
131
|
never observe the socket before its owner is published.
|
|
126
132
|
"""
|
|
127
|
-
|
|
133
|
+
socket_name = f"{TMUX_SOCKET_NAME}-{uuid.uuid4().hex}"
|
|
134
|
+
socket_dir = Path(os.environ.get("TMUX_TMPDIR", "/tmp")) / f"tmux-{os.getuid()}"
|
|
135
|
+
socket_path = socket_dir / socket_name
|
|
136
|
+
# sun_path includes a NUL byte; limits are 108 on Linux and 104 on macOS/BSD.
|
|
137
|
+
max_socket_path = 107 if sys.platform.startswith("linux") else 103
|
|
138
|
+
fallback = (
|
|
139
|
+
os.name == "posix"
|
|
140
|
+
and len(os.fsencode(os.path.realpath(socket_path))) > max_socket_path
|
|
141
|
+
)
|
|
142
|
+
if fallback:
|
|
143
|
+
socket_dir = Path("/tmp") / f"tmux-{os.getuid()}"
|
|
144
|
+
# libtmux resolves socket_name using the process-wide TMUX_TMPDIR, so
|
|
145
|
+
# use an explicit path without changing other sessions' environment.
|
|
146
|
+
logger.warning("tmux socket path is too long; using %s", socket_dir)
|
|
147
|
+
|
|
148
|
+
with _socket_creation_lock(socket_dir):
|
|
128
149
|
server = libtmux.Server(
|
|
129
|
-
socket_name=
|
|
150
|
+
socket_name=None if fallback else socket_name,
|
|
151
|
+
socket_path=str(socket_dir / socket_name) if fallback else None,
|
|
152
|
+
environment=dict(env),
|
|
130
153
|
)
|
|
131
154
|
session = server.new_session(
|
|
132
155
|
session_name=session_name,
|
|
@@ -193,12 +216,12 @@ class TmuxTerminal(TerminalInterface):
|
|
|
193
216
|
# auto-launch `less` on a TTY don't capture the pane and wedge the session.
|
|
194
217
|
env.setdefault("GIT_PAGER", "cat")
|
|
195
218
|
env.setdefault("PAGER", "cat")
|
|
196
|
-
|
|
219
|
+
shell_command = ["/bin/bash"]
|
|
197
220
|
if self.username in ["root", "openhands"]:
|
|
198
221
|
# This starts a non-login (new) shell for the given user
|
|
199
|
-
|
|
222
|
+
shell_command = ["su", self.username, "-"]
|
|
200
223
|
|
|
201
|
-
window_command =
|
|
224
|
+
window_command = shlex.join([*process_priority_prefix(env), *shell_command])
|
|
202
225
|
|
|
203
226
|
logger.debug(f"Initializing tmux terminal with command: {window_command}")
|
|
204
227
|
# Never reuse a socket: tmux numeric IDs restart at zero after server exit.
|
|
@@ -26,6 +26,9 @@ from openhands.tools.terminal.terminal.interface import (
|
|
|
26
26
|
TerminalInterface,
|
|
27
27
|
parse_ctrl_key,
|
|
28
28
|
)
|
|
29
|
+
from openhands.tools.terminal.terminal.process_priority import (
|
|
30
|
+
should_lower_process_priority,
|
|
31
|
+
)
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
logger = get_logger(__name__)
|
|
@@ -92,6 +95,10 @@ class WindowsTerminal(TerminalInterface):
|
|
|
92
95
|
if self._initialized:
|
|
93
96
|
return
|
|
94
97
|
|
|
98
|
+
env = build_terminal_env(self._env)
|
|
99
|
+
env.setdefault("PYTHONIOENCODING", "utf-8")
|
|
100
|
+
env.setdefault("PYTHONUTF8", "1")
|
|
101
|
+
|
|
95
102
|
startupinfo = None
|
|
96
103
|
creationflags = 0
|
|
97
104
|
if platform.system() == "Windows":
|
|
@@ -101,10 +108,9 @@ class WindowsTerminal(TerminalInterface):
|
|
|
101
108
|
startupinfo.dwFlags |= getattr(subprocess, "STARTF_USESHOWWINDOW", 0)
|
|
102
109
|
creationflags = getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0)
|
|
103
110
|
creationflags |= getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
env.setdefault("PYTHONUTF8", "1")
|
|
111
|
+
# Not PROCESS_MODE_BACKGROUND_BEGIN: it also throttles disk I/O.
|
|
112
|
+
if should_lower_process_priority(env):
|
|
113
|
+
creationflags |= getattr(subprocess, "BELOW_NORMAL_PRIORITY_CLASS", 0)
|
|
108
114
|
|
|
109
115
|
self.process = subprocess.Popen(
|
|
110
116
|
[self.shell_path, "-NoLogo", "-NoProfile"],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.57.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,6 +14,9 @@ pyproject.toml
|
|
|
14
14
|
./openhands/tools/browser_use/logging_fix.py
|
|
15
15
|
./openhands/tools/browser_use/recording.py
|
|
16
16
|
./openhands/tools/browser_use/server.py
|
|
17
|
+
./openhands/tools/child_conversation/__init__.py
|
|
18
|
+
./openhands/tools/child_conversation/definition.py
|
|
19
|
+
./openhands/tools/child_conversation/impl.py
|
|
17
20
|
./openhands/tools/delegate/__init__.py
|
|
18
21
|
./openhands/tools/delegate/definition.py
|
|
19
22
|
./openhands/tools/delegate/impl.py
|
|
@@ -81,6 +84,7 @@ pyproject.toml
|
|
|
81
84
|
./openhands/tools/terminal/terminal/__init__.py
|
|
82
85
|
./openhands/tools/terminal/terminal/factory.py
|
|
83
86
|
./openhands/tools/terminal/terminal/interface.py
|
|
87
|
+
./openhands/tools/terminal/terminal/process_priority.py
|
|
84
88
|
./openhands/tools/terminal/terminal/subprocess_terminal.py
|
|
85
89
|
./openhands/tools/terminal/terminal/terminal_session.py
|
|
86
90
|
./openhands/tools/terminal/terminal/tmux_pane_pool.py
|
|
@@ -112,6 +116,9 @@ openhands/tools/browser_use/impl.py
|
|
|
112
116
|
openhands/tools/browser_use/logging_fix.py
|
|
113
117
|
openhands/tools/browser_use/recording.py
|
|
114
118
|
openhands/tools/browser_use/server.py
|
|
119
|
+
openhands/tools/child_conversation/__init__.py
|
|
120
|
+
openhands/tools/child_conversation/definition.py
|
|
121
|
+
openhands/tools/child_conversation/impl.py
|
|
115
122
|
openhands/tools/delegate/__init__.py
|
|
116
123
|
openhands/tools/delegate/definition.py
|
|
117
124
|
openhands/tools/delegate/impl.py
|
|
@@ -179,6 +186,7 @@ openhands/tools/terminal/timeout_policy.py
|
|
|
179
186
|
openhands/tools/terminal/terminal/__init__.py
|
|
180
187
|
openhands/tools/terminal/terminal/factory.py
|
|
181
188
|
openhands/tools/terminal/terminal/interface.py
|
|
189
|
+
openhands/tools/terminal/terminal/process_priority.py
|
|
182
190
|
openhands/tools/terminal/terminal/subprocess_terminal.py
|
|
183
191
|
openhands/tools/terminal/terminal/terminal_session.py
|
|
184
192
|
openhands/tools/terminal/terminal/tmux_pane_pool.py
|
|
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.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/event_storage.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/browser_use/logging_fix.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
|
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/config.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/encoding.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/file_cache.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/file_editor/utils/history.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.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.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/list_directory/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/list_directory/impl.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/read_file/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/read_file/definition.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/gemini/write_file/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.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
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/planning_file_editor/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/planning_file_editor/definition.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.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.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/bash_runner.md
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/code_explorer.md
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/preset/subagents/default.md
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.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
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/task_tracker/definition.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
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/__init__.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/factory.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/terminal/interface.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/timeout_policy.py
RENAMED
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands/tools/terminal/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_tools-1.55.1 → openhands_tools-1.57.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
|
{openhands_tools-1.55.1 → openhands_tools-1.57.0}/openhands_tools.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|