openhands-tools 1.29.2__tar.gz → 1.29.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/PKG-INFO +1 -1
  2. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/apply_patch/core.py +34 -11
  3. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/apply_patch/definition.py +1 -1
  4. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/edit/impl.py +1 -6
  5. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands_tools.egg-info/PKG-INFO +1 -1
  6. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands_tools.egg-info/SOURCES.txt +0 -2
  7. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/pyproject.toml +1 -1
  8. openhands_tools-1.29.2/openhands/tools/delegate/templates/delegate_tool_description.j2 +0 -27
  9. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/__init__.py +0 -0
  10. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/apply_patch/__init__.py +0 -0
  11. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/__init__.py +0 -0
  12. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/definition.py +0 -0
  13. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/event_storage.py +0 -0
  14. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/impl.py +0 -0
  15. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/logging_fix.py +0 -0
  16. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/recording.py +0 -0
  17. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/browser_use/server.py +0 -0
  18. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/delegate/__init__.py +0 -0
  19. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/delegate/definition.py +0 -0
  20. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/delegate/impl.py +0 -0
  21. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/delegate/visualizer.py +0 -0
  22. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/__init__.py +0 -0
  23. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/definition.py +0 -0
  24. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/editor.py +0 -0
  25. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/exceptions.py +0 -0
  26. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/impl.py +0 -0
  27. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/__init__.py +0 -0
  28. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/config.py +0 -0
  29. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/constants.py +0 -0
  30. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/diff.py +0 -0
  31. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/encoding.py +0 -0
  32. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/file_cache.py +0 -0
  33. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/history.py +0 -0
  34. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/file_editor/utils/shell.py +0 -0
  35. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/__init__.py +0 -0
  36. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/edit/__init__.py +0 -0
  37. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/edit/definition.py +0 -0
  38. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/list_directory/__init__.py +0 -0
  39. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/list_directory/definition.py +0 -0
  40. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/list_directory/impl.py +0 -0
  41. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/read_file/__init__.py +0 -0
  42. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/read_file/definition.py +0 -0
  43. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/read_file/impl.py +0 -0
  44. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/write_file/__init__.py +0 -0
  45. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/write_file/definition.py +0 -0
  46. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/gemini/write_file/impl.py +0 -0
  47. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/glob/__init__.py +0 -0
  48. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/glob/definition.py +0 -0
  49. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/glob/impl.py +0 -0
  50. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/grep/__init__.py +0 -0
  51. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/grep/definition.py +0 -0
  52. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/grep/impl.py +0 -0
  53. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/planning_file_editor/__init__.py +0 -0
  54. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/planning_file_editor/definition.py +0 -0
  55. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/planning_file_editor/impl.py +0 -0
  56. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/__init__.py +0 -0
  57. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/default.py +0 -0
  58. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/gemini.py +0 -0
  59. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/gpt5.py +0 -0
  60. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/planning.py +0 -0
  61. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/subagents/bash_runner.md +0 -0
  62. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/subagents/code_explorer.md +0 -0
  63. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/subagents/default.md +0 -0
  64. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/preset/subagents/web_researcher.md +0 -0
  65. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/py.typed +0 -0
  66. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/task/__init__.py +0 -0
  67. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/task/definition.py +0 -0
  68. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/task/impl.py +0 -0
  69. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/task/manager.py +0 -0
  70. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/task_tracker/__init__.py +0 -0
  71. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/task_tracker/definition.py +0 -0
  72. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/__init__.py +0 -0
  73. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/constants.py +0 -0
  74. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/definition.py +0 -0
  75. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/descriptions.py +0 -0
  76. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/impl.py +0 -0
  77. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/metadata.py +0 -0
  78. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/__init__.py +0 -0
  79. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/factory.py +0 -0
  80. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/interface.py +0 -0
  81. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/subprocess_terminal.py +0 -0
  82. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/terminal_session.py +0 -0
  83. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/tmux_pane_pool.py +0 -0
  84. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/tmux_terminal.py +0 -0
  85. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/terminal/windows_terminal.py +0 -0
  86. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/timeout_policy.py +0 -0
  87. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/utils/__init__.py +0 -0
  88. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/utils/command.py +0 -0
  89. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/terminal/utils/escape_filter.py +0 -0
  90. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/tom_consult/__init__.py +0 -0
  91. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/tom_consult/definition.py +0 -0
  92. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/tom_consult/executor.py +0 -0
  93. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/utils/__init__.py +0 -0
  94. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/utils/timeout.py +0 -0
  95. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/workflow/__init__.py +0 -0
  96. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/workflow/definition.py +0 -0
  97. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands/tools/workflow/impl.py +0 -0
  98. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands_tools.egg-info/dependency_links.txt +0 -0
  99. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands_tools.egg-info/requires.txt +0 -0
  100. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/openhands_tools.egg-info/top_level.txt +0 -0
  101. {openhands_tools-1.29.2 → openhands_tools-1.29.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-tools
3
- Version: 1.29.2
3
+ Version: 1.29.3
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
@@ -59,7 +59,9 @@ def assemble_changes(
59
59
  old_content=old_content,
60
60
  )
61
61
  else:
62
- assert False
62
+ raise DiffError(
63
+ f"Unexpected state: path '{path}' exists in neither orig nor dest"
64
+ )
63
65
  return commit
64
66
 
65
67
 
@@ -95,13 +97,15 @@ class Parser(BaseModel):
95
97
  return False
96
98
 
97
99
  def startswith(self, prefix: str | tuple[str, ...]) -> bool:
98
- assert self.index < len(self.lines), f"Index: {self.index} >= {len(self.lines)}"
100
+ if self.index >= len(self.lines):
101
+ raise DiffError(f"Unexpected end of patch at index {self.index}")
99
102
  if self.lines[self.index].startswith(prefix):
100
103
  return True
101
104
  return False
102
105
 
103
106
  def read_str(self, prefix: str = "", return_everything: bool = False) -> str:
104
- assert self.index < len(self.lines), f"Index: {self.index} >= {len(self.lines)}"
107
+ if self.index >= len(self.lines):
108
+ raise DiffError(f"Unexpected end of patch at index {self.index}")
105
109
  line = self.lines[self.index]
106
110
  if line.startswith(prefix):
107
111
  text = line if return_everything else line[len(prefix) :]
@@ -116,11 +120,15 @@ class Parser(BaseModel):
116
120
  if path in self.patch.actions:
117
121
  raise DiffError(f"Update File Error: Duplicate Path: {path}")
118
122
  move_to = self.read_str("*** Move to: ")
123
+ if move_to and (".." in move_to.split("/") or move_to.startswith("/")):
124
+ raise DiffError(
125
+ f"Update File Error: Invalid move path '{move_to}': "
126
+ "must be a relative path without '..' components"
127
+ )
119
128
  if path not in self.current_files:
120
129
  raise DiffError(f"Update File Error: Missing File: {path}")
121
130
  text = self.current_files[path]
122
131
  action = self.parse_update_file(text)
123
- # TODO: Check move_to is valid
124
132
  action.move_path = move_to
125
133
  self.patch.actions[path] = action
126
134
  continue
@@ -359,7 +367,10 @@ def identify_files_needed(text: str) -> list[str]:
359
367
 
360
368
 
361
369
  def _get_updated_file(text: str, action: PatchAction, path: str) -> str:
362
- assert action.type == ActionType.UPDATE
370
+ if action.type != ActionType.UPDATE:
371
+ raise DiffError(
372
+ f"_get_updated_file: expected UPDATE action for '{path}', got {action.type}"
373
+ )
363
374
  orig_lines = text.split("\n")
364
375
  dest_lines = []
365
376
  orig_index = 0
@@ -375,7 +386,6 @@ def _get_updated_file(text: str, action: PatchAction, path: str) -> str:
375
386
  f"_get_updated_file: {path}: orig_index {orig_index} > "
376
387
  f"chunk.orig_index {chunk.orig_index}"
377
388
  )
378
- assert orig_index <= chunk.orig_index
379
389
  dest_lines.extend(orig_lines[orig_index : chunk.orig_index])
380
390
  delta = chunk.orig_index - orig_index
381
391
  orig_index += delta
@@ -389,8 +399,16 @@ def _get_updated_file(text: str, action: PatchAction, path: str) -> str:
389
399
  delta = len(orig_lines) - orig_index
390
400
  orig_index += delta
391
401
  dest_index += delta
392
- assert orig_index == len(orig_lines)
393
- assert dest_index == len(dest_lines)
402
+ if orig_index != len(orig_lines):
403
+ raise DiffError(
404
+ f"_get_updated_file: {path}: did not consume all original lines "
405
+ f"(orig_index={orig_index}, len={len(orig_lines)})"
406
+ )
407
+ if dest_index != len(dest_lines):
408
+ raise DiffError(
409
+ f"_get_updated_file: {path}: dest line count mismatch "
410
+ f"(dest_index={dest_index}, len={len(dest_lines)})"
411
+ )
394
412
  return "\n".join(dest_lines)
395
413
 
396
414
 
@@ -449,10 +467,14 @@ def apply_commit(
449
467
  if change.type == ActionType.DELETE:
450
468
  remove_fn(path)
451
469
  elif change.type == ActionType.ADD:
452
- assert change.new_content is not None
470
+ if change.new_content is None:
471
+ raise DiffError(f"apply_commit: ADD change for '{path}' has no content")
453
472
  write_fn(path, change.new_content)
454
473
  elif change.type == ActionType.UPDATE:
455
- assert change.new_content is not None
474
+ if change.new_content is None:
475
+ raise DiffError(
476
+ f"apply_commit: UPDATE change for '{path}' has no content"
477
+ )
456
478
  if change.move_path:
457
479
  write_fn(change.move_path, change.new_content)
458
480
  remove_fn(path)
@@ -470,7 +492,8 @@ def process_patch(
470
492
 
471
493
  Returns (message, fuzz, commit)
472
494
  """
473
- assert text.startswith("*** Begin Patch")
495
+ if not text.startswith("*** Begin Patch"):
496
+ raise DiffError("Invalid patch: must start with '*** Begin Patch'")
474
497
  paths = identify_files_needed(text)
475
498
  orig = load_files(paths, open_fn)
476
499
  patch, fuzz = text_to_patch(text, orig)
@@ -77,7 +77,7 @@ class ApplyPatchExecutor(ToolExecutor[ApplyPatchAction, ApplyPatchObservation]):
77
77
  if not p.startswith("/")
78
78
  else Path(p).resolve()
79
79
  )
80
- if not str(pth).startswith(str(self.workspace_root)):
80
+ if not pth.is_relative_to(self.workspace_root):
81
81
  raise DiffError("Absolute or escaping paths are not allowed")
82
82
  return pth
83
83
 
@@ -1,6 +1,5 @@
1
1
  """Edit tool executor implementation."""
2
2
 
3
- import os
4
3
  from pathlib import Path
5
4
  from typing import TYPE_CHECKING
6
5
 
@@ -43,11 +42,7 @@ class EditExecutor(ToolExecutor[EditAction, EditObservation]):
43
42
  new_string = action.new_string
44
43
  expected_replacements = action.expected_replacements
45
44
 
46
- # Resolve path relative to workspace
47
- if not os.path.isabs(file_path):
48
- resolved_path = self.workspace_root / file_path
49
- else:
50
- resolved_path = Path(file_path)
45
+ resolved_path = (self.workspace_root / file_path).resolve()
51
46
 
52
47
  # Handle file creation (old_string is empty)
53
48
  if old_string == "":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-tools
3
- Version: 1.29.2
3
+ Version: 1.29.3
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
@@ -15,7 +15,6 @@ pyproject.toml
15
15
  ./openhands/tools/delegate/definition.py
16
16
  ./openhands/tools/delegate/impl.py
17
17
  ./openhands/tools/delegate/visualizer.py
18
- ./openhands/tools/delegate/templates/delegate_tool_description.j2
19
18
  ./openhands/tools/file_editor/__init__.py
20
19
  ./openhands/tools/file_editor/definition.py
21
20
  ./openhands/tools/file_editor/editor.py
@@ -108,7 +107,6 @@ openhands/tools/delegate/__init__.py
108
107
  openhands/tools/delegate/definition.py
109
108
  openhands/tools/delegate/impl.py
110
109
  openhands/tools/delegate/visualizer.py
111
- openhands/tools/delegate/templates/delegate_tool_description.j2
112
110
  openhands/tools/file_editor/__init__.py
113
111
  openhands/tools/file_editor/definition.py
114
112
  openhands/tools/file_editor/editor.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "openhands-tools"
3
- version = "1.29.2"
3
+ version = "1.29.3"
4
4
  description = "OpenHands Tools - Runtime tools for AI agents"
5
5
 
6
6
  requires-python = ">=3.12"
@@ -1,27 +0,0 @@
1
- Delegation tool for spawning sub-agents and delegating tasks to them.
2
-
3
- This tool provides two commands:
4
-
5
- **spawn**: Initialize sub-agents with meaningful identifiers and optional types
6
- - Use descriptive identifiers that make sense for your use case (e.g., 'refactoring', 'run_tests', 'research')
7
- - Optionally specify agent types for specialized capabilities
8
- - Each identifier creates a separate sub-agent conversation
9
- - Examples:
10
- {% raw %} - Default agents: {"command": "spawn", "ids": ["research", "implementation"]}
11
- - Specialized agents: {"command": "spawn", "ids": ["research", "code"], "agent_types": ["researcher", "programmer"]}
12
- - Mixed types: {"command": "spawn", "ids": ["research", "generic"], "agent_types": ["researcher"]} # unspecified entries fall back to the default agent{% endraw %}
13
-
14
- **delegate**: Send tasks to specific sub-agents and wait for results
15
- - Use a dictionary mapping sub-agent identifiers to task descriptions
16
- - This is a blocking operation - waits for all sub-agents to complete
17
- - Returns a single observation containing results from all sub-agents
18
- - Example: {% raw %}{"command": "delegate", "tasks": {"research": "Find best practices for async code", "implementation": "Refactor the MyClass class"}}{% endraw %}
19
-
20
- **Available agent types:**
21
- {{ agent_types_info }}
22
-
23
- **Important Notes:**
24
- - Identifiers used in delegate must match those used in spawn
25
- - All operations are blocking and return comprehensive results
26
- - Sub-agents work in the same workspace as the main agent: {{ workspace_path }}
27
- - If you omit an agent type for an ID, a default general-purpose agent is used