File size: 5,458 Bytes
51ff9e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from dataclasses import dataclass
from typing import ClassVar

from openhands.core.schema import ActionType
from openhands.events.action.action import Action, ActionSecurityRisk
from openhands.events.event import FileEditSource, FileReadSource


@dataclass
class FileReadAction(Action):
    """Reads a file from a given path.
    Can be set to read specific lines using start and end
    Default lines 0:-1 (whole file)
    """

    path: str
    start: int = 0
    end: int = -1
    thought: str = ''
    action: str = ActionType.READ
    runnable: ClassVar[bool] = True
    security_risk: ActionSecurityRisk | None = None
    impl_source: FileReadSource = FileReadSource.DEFAULT
    view_range: list[int] | None = None  # ONLY used in OH_ACI mode

    @property
    def message(self) -> str:
        return f'Reading file: {self.path}'


@dataclass
class FileWriteAction(Action):
    """Writes a file to a given path.
    Can be set to write specific lines using start and end
    Default lines 0:-1 (whole file)
    """

    path: str
    content: str
    start: int = 0
    end: int = -1
    thought: str = ''
    action: str = ActionType.WRITE
    runnable: ClassVar[bool] = True
    security_risk: ActionSecurityRisk | None = None

    @property
    def message(self) -> str:
        return f'Writing file: {self.path}'

    def __repr__(self) -> str:
        return (
            f'**FileWriteAction**\n'
            f'Path: {self.path}\n'
            f'Range: [L{self.start}:L{self.end}]\n'
            f'Thought: {self.thought}\n'
            f'Content:\n```\n{self.content}\n```\n'
        )


@dataclass
class FileEditAction(Action):
    """Edits a file using various commands including view, create, str_replace, insert, and undo_edit.

    This class supports two main modes of operation:
    1. LLM-based editing (impl_source = FileEditSource.LLM_BASED_EDIT)
    2. ACI-based editing (impl_source = FileEditSource.OH_ACI)

    Attributes:
        path (str): The path to the file being edited. Works for both LLM-based and OH_ACI editing.
        OH_ACI only arguments:
            command (str): The editing command to be performed (view, create, str_replace, insert, undo_edit, write).
            file_text (str): The content of the file to be created (used with 'create' command in OH_ACI mode).
            old_str (str): The string to be replaced (used with 'str_replace' command in OH_ACI mode).
            new_str (str): The string to replace old_str (used with 'str_replace' and 'insert' commands in OH_ACI mode).
            insert_line (int): The line number after which to insert new_str (used with 'insert' command in OH_ACI mode).
        LLM-based editing arguments:
            content (str): The content to be written or edited in the file (used in LLM-based editing and 'write' command).
            start (int): The starting line for editing (1-indexed, inclusive). Default is 1.
            end (int): The ending line for editing (1-indexed, inclusive). Default is -1 (end of file).
            thought (str): The reasoning behind the edit action.
            action (str): The type of action being performed (always ActionType.EDIT).
        runnable (bool): Indicates if the action can be executed (always True).
        security_risk (ActionSecurityRisk | None): Indicates any security risks associated with the action.
        impl_source (FileEditSource): The source of the implementation (LLM_BASED_EDIT or OH_ACI).

    Usage:
        - For LLM-based editing: Use path, content, start, and end attributes.
        - For ACI-based editing: Use path, command, and the appropriate attributes for the specific command.

    Note:
        - If start is set to -1 in LLM-based editing, the content will be appended to the file.
        - The 'write' command behaves similarly to LLM-based editing, using content, start, and end attributes.
    """

    path: str

    # OH_ACI arguments
    command: str = ''
    file_text: str | None = None
    old_str: str | None = None
    new_str: str | None = None
    insert_line: int | None = None

    # LLM-based editing arguments
    content: str = ''
    start: int = 1
    end: int = -1

    # Shared arguments
    thought: str = ''
    action: str = ActionType.EDIT
    runnable: ClassVar[bool] = True
    security_risk: ActionSecurityRisk | None = None
    impl_source: FileEditSource = FileEditSource.OH_ACI

    def __repr__(self) -> str:
        ret = '**FileEditAction**\n'
        ret += f'Path: [{self.path}]\n'
        ret += f'Thought: {self.thought}\n'

        if self.impl_source == FileEditSource.LLM_BASED_EDIT:
            ret += f'Range: [L{self.start}:L{self.end}]\n'
            ret += f'Content:\n```\n{self.content}\n```\n'
        else:  # OH_ACI mode
            ret += f'Command: {self.command}\n'
            if self.command == 'create':
                ret += f'Created File with Text:\n```\n{self.file_text}\n```\n'
            elif self.command == 'str_replace':
                ret += f'Old String: ```\n{self.old_str}\n```\n'
                ret += f'New String: ```\n{self.new_str}\n```\n'
            elif self.command == 'insert':
                ret += f'Insert Line: {self.insert_line}\n'
                ret += f'New String: ```\n{self.new_str}\n```\n'
            elif self.command == 'undo_edit':
                ret += 'Undo Edit\n'
            # We ignore "view" command because it will be mapped to a FileReadAction
        return ret