Repository: All-Hands-AI/OpenHands
File: openhands/agenthub/codeact_agent/tools/str_replace_editor.py (Python)

Code before:
* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!
* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique
* The `new_str` parameter should contain the edited lines that should replace the `old_str`
"""


def _get_workspace_mount_path_from_env() -> str:
    """Get the workspace mount path from SANDBOX_VOLUMES environment variable.

    Returns:
        The workspace mount path in sandbox, defaults to '/workspace' if not found.
    """
    sandbox_volumes = os.environ.get('SANDBOX_VOLUMES')
    if not sandbox_volumes:
        return DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX

    # Split by commas to handle multiple mounts
    mounts = sandbox_volumes.split(',')

    # Check if any mount explicitly targets /workspace or another path
    for mount in mounts:
        parts = mount.split(':')
        if len(parts) >= 2:
            container_path = parts[1]
            # Return the first container path found, which is likely the workspace
            return container_path

    return DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX


def create_str_replace_editor_tool(
    use_short_description: bool = False,
    workspace_mount_path_in_sandbox: str | None = None,
) -> ChatCompletionToolParam:
    # If no workspace path is provided, try to get it from environment
    if workspace_mount_path_in_sandbox is None:
        workspace_mount_path_in_sandbox = _get_workspace_mount_path_from_env()

    description = (
        _SHORT_STR_REPLACE_EDITOR_DESCRIPTION
        if use_short_description
        else _DETAILED_STR_REPLACE_EDITOR_DESCRIPTION
    )
    return ChatCompletionToolParam(
        type='function',
        function=ChatCompletionToolParamFunctionChunk(
            name=STR_REPLACE_EDITOR_TOOL_NAME,
            description=description,
            parameters={
                'type': 'object',
                'properties': {

Review comment (suggestion):
```suggestion
        parts = mount.split(':')
        if parts:
            return parts[0]
```

Code after:
* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!
* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique
* The `new_str` parameter should contain the edited lines that should replace the `old_str`
"""


def _get_workspace_mount_path_from_env(runtime_type: str | None = None) -> str:
    """Get the workspace mount path from SANDBOX_VOLUMES environment variable.

    For LocalRuntime and CLIRuntime, returns the host path from SANDBOX_VOLUMES.
    For other runtimes, returns the default container path (/workspace).

    Args:
        runtime_type: The runtime type ('local', 'cli', 'docker', etc.)

    Returns:
        The workspace mount path in sandbox, defaults to '/workspace' if not found.
    """
    # For LocalRuntime/CLIRuntime, try to get host path from SANDBOX_VOLUMES
    if runtime_type in ('local', 'cli'):
        sandbox_volumes = os.environ.get('SANDBOX_VOLUMES')
        if sandbox_volumes:
            # Split by commas to handle multiple mounts
            mounts = sandbox_volumes.split(',')

            # Check if any mount explicitly targets /workspace
            for mount in mounts:
                parts = mount.split(':')
                if len(parts) >= 2 and parts[1] == '/workspace':
                    host_path = os.path.abspath(parts[0])
                    return host_path

        # Fallback for local/CLI runtimes when SANDBOX_VOLUMES is not set:
        # Use current working directory as it's likely the workspace root
        return os.getcwd()

    # For all other runtimes (docker, remote, etc.), use default container path
    return DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX


def create_str_replace_editor_tool(
    use_short_description: bool = False,
    workspace_mount_path_in_sandbox: str | None = None,
    runtime_type: str | None = None,
) -> ChatCompletionToolParam:
    # If no workspace path is provided, try to get it from environment
    if workspace_mount_path_in_sandbox is None:
        workspace_mount_path_in_sandbox = _get_workspace_mount_path_from_env(
            runtime_type
        )