Spaces:
Runtime error
Runtime error
File size: 3,938 Bytes
670dd87 |
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 |
import os
from enum import Enum
from typing import List, Literal, Optional
from pydantic import BaseModel, Field, field_validator, model_validator
from agency_swarm import BaseTool
class LineChange(BaseModel):
"""
Line changes to be made.
"""
line_number: int = Field(
..., description="Line number to change.", examples=[1, 2, 3]
)
new_line: Optional[str] = Field(
None,
description="New line to replace the old line. Not required only for delete mode.",
examples=["This is a new line"],
)
mode: Literal["replace", "insert", "delete"] = Field(
"replace",
description='Mode to use for the line change. "replace" replaces the line with the new line. '
'"insert" inserts the new line at the specified line number, moving the previous line down.'
' "delete" deletes the specified line number.',
)
@model_validator(mode="after")
def validate_new_line(self):
mode, new_line = self.mode, self.new_line
if mode == "delete" and new_line is not None:
raise ValueError("new_line should not be specified for delete mode.")
elif mode in ["replace", "insert"] and new_line is None:
raise ValueError(
"new_line should be specified for replace and insert modes."
)
return self
class ChangeFile(BaseTool):
"""
This tool changes specified lines in a file. Returns the new file contents with line numbers at the start of each line.
"""
chain_of_thought: str = Field(
...,
description="Please think step-by-step about the required changes to the file in order to construct a fully functioning and correct program according to the requirements.",
exclude=True,
)
file_path: str = Field(
...,
description="Path to the file with extension.",
examples=["./file.txt", "./file.json", "../../file.py"],
)
changes: List[LineChange] = Field(
...,
description="Line changes to be made to the file.",
examples=[
{"line_number": 1, "new_line": "This is a new line", "mode": "replace"}
],
)
def run(self):
# read file
with open(self.file_path, "r") as f:
file_contents = f.readlines()
# Process changes in a way that accounts for modifications affecting line numbers
for change in sorted(
self.changes, key=lambda x: x.line_number, reverse=True
):
try:
if change.mode == "replace" and 0 < change.line_number <= len(
file_contents
):
file_contents[change.line_number - 1] = change.new_line + "\n"
elif change.mode == "insert":
file_contents.insert(
change.line_number - 1, change.new_line + "\n"
)
elif change.mode == "delete" and 0 < change.line_number <= len(
file_contents
):
file_contents.pop(change.line_number - 1)
except IndexError:
return f"Error: Line number {change.line_number} is out of the file's range."
# write file
with open(self.file_path, "w") as f:
f.writelines(file_contents)
with open(self.file_path, "r") as f:
file_contents = f.readlines()
# return file contents with line numbers
return "\n".join([f"{i + 1}. {line}" for i, line in enumerate(file_contents)])
# use field validation to ensure that the file path is valid
@field_validator("file_path", mode="after")
@classmethod
def validate_file_path(cls, v: str):
if not os.path.exists(v):
raise ValueError("File path does not exist.")
return v
|