Files
strix/strix/tools/file_edit/tools.py
T
0xallam 49c38de3b2 refactor: dedupe `_dump` helper, collapse retry-policy plumbing, scrub test scars
Tools:
- Add a single ``dump_tool_result`` helper in ``tools/_decorator.py``
  and remove the eight identical ``_dump`` definitions from
  ``proxy/tools.py``, ``file_edit/tools.py``, ``python/tool.py``,
  ``terminal/tool.py``, ``todo/tools.py``, ``browser/tool.py``,
  ``notes/tools.py``, ``agents_graph/tools.py``. Imports trimmed.
  Net -50 LoC across the tool modules.

run_config_factory:
- Inline the four retry-policy plumbing pieces
  (``_RETRYABLE_HTTP_STATUSES``, ``_DEFAULT_MAX_RETRIES``,
  ``_DEFAULT_BACKOFF``, ``_default_retry_policy()``) into a single
  module-level ``_DEFAULT_RETRY`` ``ModelRetrySettings`` literal. The
  inputs were never overridden and the helper had one caller.

Tests:
- Drop migration scars from ``tests/test_run_config_factory.py``
  (``Phase 1`` / ``C1`` / ``C11`` / ``C21`` / ``HARNESS_WIKI`` / ``AUDIT``
  references). Replace the ``_RETRYABLE_HTTP_STATUSES``-touching test
  with a ``retry.policy is not None`` smoke check now that the constant
  has been inlined.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 12:54:44 -07:00

129 lines
4.2 KiB
Python

"""SDK function-tool wrappers for the legacy ``file_edit`` tools.
These three tools (``str_replace_editor``, ``list_files``, ``search_files``)
operate on files inside the sandbox container's ``/workspace`` filesystem.
The legacy harness marks them ``sandbox_execution=True`` (default) so the
executor POSTs them to the in-container tool server.
The host-side SDK wrappers therefore delegate to ``post_to_sandbox`` —
the legacy implementations live in the container image and we don't
import them on the host (they pull in ``openhands_aci``, which is a
sandbox-only dependency).
"""
from __future__ import annotations
from agents import RunContextWrapper
from strix.tools._decorator import dump_tool_result, strix_tool
from strix.tools._sandbox_dispatch import post_to_sandbox
@strix_tool(timeout=180)
async def str_replace_editor(
ctx: RunContextWrapper,
command: str,
path: str,
file_text: str | None = None,
view_range: list[int] | None = None,
old_str: str | None = None,
new_str: str | None = None,
insert_line: int | None = None,
) -> str:
"""View, create, or edit a file in the sandbox filesystem.
Commands:
- ``view`` — show file contents. Optionally restrict to a line range
via ``view_range`` (1-indexed; ``[start, -1]`` for "from start to
end of file").
- ``create`` — write a new file with ``file_text``. Use this for
exploit scripts, PoCs, helper modules, etc.
- ``str_replace`` — find ``old_str`` in the file and replace with
``new_str``. ``old_str`` must be unique in the file; include
enough surrounding context to make it so.
- ``insert`` — insert ``new_str`` after line ``insert_line``.
- ``undo_edit`` — revert the most recent edit to ``path``.
Multi-line ``new_str`` / ``old_str`` / ``file_text`` use real
newlines, not literal ``\\n``.
Args:
command: ``view`` / ``create`` / ``str_replace`` / ``insert`` /
``undo_edit``.
path: File path. Relative paths anchor at ``/workspace``.
file_text: Required for ``create``.
view_range: Optional ``[start, end]`` (1-indexed) for ``view``.
old_str: Required for ``str_replace`` — must be unique in file.
new_str: Required for ``str_replace`` and ``insert``.
insert_line: Required for ``insert``; new content goes AFTER
this line.
"""
return dump_tool_result(
await post_to_sandbox(
ctx,
"str_replace_editor",
{
"command": command,
"path": path,
"file_text": file_text,
"view_range": view_range,
"old_str": old_str,
"new_str": new_str,
"insert_line": insert_line,
},
),
)
@strix_tool(timeout=120)
async def list_files(
ctx: RunContextWrapper,
path: str,
recursive: bool = False,
) -> str:
"""List files and directories under a sandbox path.
Output is sorted alphabetically and capped at 500 entries to avoid
flooding the model with huge directory trees.
Args:
path: Directory path; relative paths anchor at ``/workspace``.
recursive: When True, walks subdirectories.
"""
return dump_tool_result(
await post_to_sandbox(
ctx,
"list_files",
{"path": path, "recursive": recursive},
),
)
@strix_tool(timeout=120)
async def search_files(
ctx: RunContextWrapper,
path: str,
regex: str,
file_pattern: str = "*",
) -> str:
"""Recursively regex-search files in the sandbox using ripgrep.
Fast — uses ``rg`` under the hood. Walks subdirectories. Use this
for code-pattern hunts (``def\\s+authenticate``, ``API_KEY``,
secrets, etc.) when you don't already know the file.
Args:
path: Root path to search. Relative paths anchor at ``/workspace``.
regex: Pattern to match (PCRE-style; passed straight to ``rg``).
file_pattern: Glob filter (e.g. ``"*.py"``, ``"*.{js,ts}"``).
Defaults to all files.
"""
return dump_tool_result(
await post_to_sandbox(
ctx,
"search_files",
{"path": path, "regex": regex, "file_pattern": file_pattern},
),
)