Skip to content

Conversation

Saedbhati
Copy link
Collaborator

@Saedbhati Saedbhati commented Aug 25, 2025

Description

Describe your changes in detail (optional if the linked issue already contains a detailed description of the changes).
Fixes #2981

Checklist

Go over all the following points, and put an x in all the boxes that apply.

  • I have read the CONTRIBUTION guide (required)
  • I have linked this PR to an issue using the Development section on the right sidebar or by adding Fixes #issue-number in the PR description (required)
  • I have checked if any dependencies need to be added or updated in pyproject.toml and uv lock
  • I have updated the tests accordingly (required for a bug fix or a new feature)
  • I have updated the documentation if needed:
  • I have added examples if this is a new feature

If you are unsure about any of these, don't hesitate to ask. We are here to help!

Copy link
Contributor

coderabbitai bot commented Aug 25, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dynamic_file_editing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Saedbhati Saedbhati marked this pull request as draft August 25, 2025 10:15
@Wendong-Fan Wendong-Fan marked this pull request as ready for review August 29, 2025 21:56
Copy link
Member

@Wendong-Fan Wendong-Fan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @Saedbhati , left some comments below, we also need to add test code for new feature, one PR here for some quick enhancement: #3088

Comment on lines 1132 to 1136
except ImportError:
return (
"Error reading YAML file: PyYAML package not installed. "
"Please install with: pip install PyYAML"
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use decorator would be more tidy and unified: @dependencies_required('yaml'), same for other parts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got error below when i run the example code, I think in previous tasks we didn't mention that the created python file should be named as simple_flask_server.py

2025-08-31 02:38:07,434 - camel.camel.agents.chat_agent - WARNING - Error executing tool 'read_file': Execution of function read_file failed with arguments () and {'file_path': 'simple_flask_server.py'}. Error: [Errno 2] No such file or directory: '/Users/enrei/Desktop/repos/camel0829/camel/file_write_outputs/simple_flask_server.py' with result: Tool execution failed: Error executing tool 'read_file': Execution of function read_file failed with arguments () and {'file_path': 'simple_flask_server.py'}. Error: [Errno 2] No such file or directory: '/Users/enrei/Desktop/repos/camel0829/camel/file_write_outputs/simple_flask_server.py'

@@ -1072,4 +1445,7 @@ def get_tools(self) -> List[FunctionTool]:
"""
return [
FunctionTool(self.write_to_file),
FunctionTool(self.read_file),
FunctionTool(self.edit_file),
FunctionTool(self.insert_at_line),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried run this function, got

2025-08-31 02:52:04,460 - camel.camel.toolkits.file_write_toolkit - ERROR - Error inserting content in file /Users/enrei/Desktop/repos/camel0829/camel/examples/toolkits/mock_test_file.pdf: 'utf-8' codec can't decode byte 0x93 in position 10: invalid start byte

with test file: https://chatgpt.com/share/68b3489b-3ed4-8013-86e3-ad255bd018d9
and task: Please insert a new route '/contact' that returns 'Contact us at contact@example.com' to the /Users/enrei/Desktop/repos/camel0829/camel/examples/toolkits/mock_test_file.pdf file, you must use insert_at_line function

seems now we don't support binary files that can't be decoded as text?

logger.error(error_msg)
return error_msg

def insert_at_line(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the design of this function is confused

  1. why we need insert_at_line as we already have edit_file , what case is this function designed for, we need to specify this in docstring for the agent to understand better
  2. how could the agent know which line the content should insert? there's no function or design to provide the line number to the agent

Comment on lines 1391 to 1400
if extension in [".doc", ".docx"]:
self._edit_docx_file(resolved_path, old_content, new_content)
elif extension == ".json":
self._edit_json_file(resolved_path, old_content, new_content)
elif extension in [".yaml", ".yml"]:
self._edit_yaml_file(resolved_path, old_content, new_content)
else:
# For text files, use simple text replacement
return self._perform_text_replacement(
resolved_path, old_content, new_content
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the supported file format is limited, at least we also need support types like .pdf as we supported in write_to_file

Comment on lines 1255 to 1259
except ImportError as e:
raise ImportError(
"The python-docx package is required for DOCX file operations."
"Please install it with: pip install camel-ai[document_tools]"
) from e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not necessary, we could require the dependency to remove unnecessary except case to make code more tidy, same for other parts

Comment on lines 1090 to 1100
except ImportError:
try:
import pypdf

with open(file_path, 'rb') as file:
pdf_reader = pypdf.PdfReader(file) # type: ignore[assignment]
text = ""
for page in pdf_reader.pages:
text += page.extract_text() + "\n"
return text
except ImportError as e:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not necessary, we could require the dependency to remove unnecessary except case to make code more tidy, same for other parts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we update the class naming and the description since now we not only support file write, but also file editing?

@@ -1072,4 +1445,7 @@ def get_tools(self) -> List[FunctionTool]:
"""
return [
FunctionTool(self.write_to_file),
FunctionTool(self.read_file),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for read_file , we can use loaders like markitdown which has better performance, maybe later support user config the BaseLoader (after #2819 merged) when they initialize FileWriteToolkit

@Wendong-Fan Wendong-Fan added this to the Sprint 36 milestone Aug 30, 2025
@Wendong-Fan Wendong-Fan added New Feature Waiting for Update PR has been reviewed, need to be updated based on review comment labels Aug 30, 2025
Copy link
Collaborator

@waleedalzarooni waleedalzarooni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Saedbhati great integration!

I included some comments on function design that may be helpful to consider, otherwise awesome work!

# Simple string replacement
json_str = json.dumps(data, ensure_ascii=False)
if old_content in json_str:
updated_str = json_str.replace(old_content, new_content)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using str.replace() can cause some issues since we are altering json's

  • Replaces ALL occurrences of the search text, so {"message": "Hello", "user_message": "Hi"} becomes {"greeting": "Hello", "user_greeting": "Hi"} when searching for "message"

  • When str.replace() modifies JSON content, it can break the fundamental syntax rules. For example, if you accidentally replace a quote mark, bracket, or comma, the resulting string may no longer be valid JSON.

  • Replacing " with ' in{"name": "John"} creates {'name': 'John'} (invalid JSON - single quotes not allowed)

  • Replacing , with ; in {"a": 1, "b": 2} creates {"a": 1; "b": 2} (invalid JSON - semicolons not valid separators)

  • Replacing { with [ in {"data": {"nested": "value"}} creates ["data": {"nested": "value"}} (invalid JSON - mismatched brackets)

# Replace entire document content
for paragraph in doc.paragraphs[:]:
p = paragraph._element
p.getparent().remove(p)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p.getparent().remove(p) removes paragraph element from XML tree which will delete any font information, styling, alignment, indentation. This will result in new text additions being added with the default font settings, which may cause text replacements to look strange in the existing file

@a7m-1st
Copy link
Collaborator

a7m-1st commented Sep 4, 2025

@Saedbhati thanks for your PR, may I know what issues you are facing? In what conditions would you think that its ready for production.

Perhaps we can open an issue for contribution.

@Saedbhati
Copy link
Collaborator Author

Saedbhati commented Sep 4, 2025

@a7m-1st i think there are better approach than this like patching or using regex to replace text. Most AI code editor use Patching method

Copy link
Member

@Wendong-Fan Wendong-Fan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test code need to be updated

@Wendong-Fan Wendong-Fan closed this Sep 6, 2025
@Wendong-Fan Wendong-Fan deleted the dynamic_file_editing branch September 6, 2025 22:31
@Wendong-Fan Wendong-Fan restored the dynamic_file_editing branch September 6, 2025 22:31
@Wendong-Fan Wendong-Fan reopened this Sep 6, 2025
@Wendong-Fan
Copy link
Member

hey @Saedbhati @a7m-1st , I think adding optional regex/patch modes would make it more powerful for advanced scenarios, let's create another issue and PR for this

@Wendong-Fan Wendong-Fan changed the title enhance: Dynamic File Editing feat: Dynamic File Editing Sep 6, 2025
@Wendong-Fan
Copy link
Member

thanks @Saedbhati , @a7m-1st @waleedalzarooni ! added enhance PR: #3109

@Wendong-Fan Wendong-Fan merged commit a4acd7c into master Sep 6, 2025
12 of 13 checks passed
@Wendong-Fan Wendong-Fan deleted the dynamic_file_editing branch September 6, 2025 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Feature Waiting for Update PR has been reviewed, need to be updated based on review comment
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

[Feature Request] FileWrite Toolkit support dynamic file editing
4 participants