janito 2.2.0__py3-none-any.whl → 2.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. janito/__init__.py +6 -6
  2. janito/agent/setup_agent.py +14 -5
  3. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +3 -1
  4. janito/cli/chat_mode/bindings.py +6 -0
  5. janito/cli/chat_mode/session.py +16 -0
  6. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  7. janito/cli/chat_mode/shell/commands/__init__.py +3 -0
  8. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  9. janito/cli/chat_mode/shell/commands/exec.py +27 -0
  10. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  11. janito/cli/chat_mode/shell/commands/tools.py +17 -6
  12. janito/cli/chat_mode/shell/input_history.py +62 -62
  13. janito/cli/chat_mode/shell/session/manager.py +1 -0
  14. janito/cli/chat_mode/toolbar.py +1 -0
  15. janito/cli/cli_commands/list_models.py +35 -35
  16. janito/cli/cli_commands/list_providers.py +9 -9
  17. janito/cli/cli_commands/list_tools.py +53 -53
  18. janito/cli/cli_commands/model_selection.py +50 -50
  19. janito/cli/cli_commands/model_utils.py +13 -2
  20. janito/cli/cli_commands/set_api_key.py +19 -19
  21. janito/cli/cli_commands/show_config.py +51 -51
  22. janito/cli/cli_commands/show_system_prompt.py +62 -62
  23. janito/cli/config.py +2 -1
  24. janito/cli/core/__init__.py +4 -4
  25. janito/cli/core/event_logger.py +59 -59
  26. janito/cli/core/getters.py +3 -1
  27. janito/cli/core/runner.py +165 -148
  28. janito/cli/core/setters.py +5 -1
  29. janito/cli/core/unsetters.py +54 -54
  30. janito/cli/main_cli.py +12 -1
  31. janito/cli/prompt_core.py +5 -2
  32. janito/cli/rich_terminal_reporter.py +22 -3
  33. janito/cli/single_shot_mode/__init__.py +6 -6
  34. janito/cli/single_shot_mode/handler.py +11 -1
  35. janito/cli/verbose_output.py +1 -1
  36. janito/config.py +5 -5
  37. janito/config_manager.py +2 -0
  38. janito/driver_events.py +14 -0
  39. janito/drivers/anthropic/driver.py +113 -113
  40. janito/drivers/azure_openai/driver.py +38 -3
  41. janito/drivers/driver_registry.py +0 -2
  42. janito/drivers/openai/driver.py +196 -36
  43. janito/formatting_token.py +54 -54
  44. janito/i18n/__init__.py +35 -35
  45. janito/i18n/messages.py +23 -23
  46. janito/i18n/pt.py +47 -47
  47. janito/llm/__init__.py +5 -5
  48. janito/llm/agent.py +443 -443
  49. janito/llm/auth.py +1 -0
  50. janito/llm/driver.py +7 -1
  51. janito/llm/driver_config.py +1 -0
  52. janito/llm/driver_config_builder.py +34 -34
  53. janito/llm/driver_input.py +12 -12
  54. janito/llm/message_parts.py +60 -60
  55. janito/llm/model.py +38 -38
  56. janito/llm/provider.py +196 -196
  57. janito/provider_config.py +7 -3
  58. janito/provider_registry.py +176 -158
  59. janito/providers/__init__.py +1 -0
  60. janito/providers/anthropic/model_info.py +22 -22
  61. janito/providers/anthropic/provider.py +2 -2
  62. janito/providers/azure_openai/model_info.py +7 -6
  63. janito/providers/azure_openai/provider.py +30 -2
  64. janito/providers/deepseek/__init__.py +1 -1
  65. janito/providers/deepseek/model_info.py +16 -16
  66. janito/providers/deepseek/provider.py +91 -91
  67. janito/providers/google/model_info.py +21 -29
  68. janito/providers/google/provider.py +49 -38
  69. janito/providers/mistralai/provider.py +2 -2
  70. janito/providers/provider_static_info.py +2 -3
  71. janito/tools/adapters/__init__.py +1 -1
  72. janito/tools/adapters/local/adapter.py +33 -11
  73. janito/tools/adapters/local/ask_user.py +102 -102
  74. janito/tools/adapters/local/copy_file.py +84 -84
  75. janito/tools/adapters/local/create_directory.py +69 -69
  76. janito/tools/adapters/local/create_file.py +82 -82
  77. janito/tools/adapters/local/delete_text_in_file.py +4 -7
  78. janito/tools/adapters/local/fetch_url.py +97 -97
  79. janito/tools/adapters/local/find_files.py +138 -138
  80. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  81. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  82. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  83. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  84. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  85. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  86. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  87. janito/tools/adapters/local/move_file.py +3 -13
  88. janito/tools/adapters/local/python_code_run.py +166 -166
  89. janito/tools/adapters/local/python_command_run.py +164 -164
  90. janito/tools/adapters/local/python_file_run.py +163 -163
  91. janito/tools/adapters/local/remove_directory.py +6 -17
  92. janito/tools/adapters/local/remove_file.py +4 -10
  93. janito/tools/adapters/local/replace_text_in_file.py +6 -9
  94. janito/tools/adapters/local/run_bash_command.py +176 -176
  95. janito/tools/adapters/local/run_powershell_command.py +219 -219
  96. janito/tools/adapters/local/search_text/__init__.py +1 -1
  97. janito/tools/adapters/local/search_text/core.py +201 -201
  98. janito/tools/adapters/local/search_text/match_lines.py +1 -1
  99. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  100. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  101. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  102. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  103. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  104. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  105. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  106. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  107. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  108. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  109. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  110. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  111. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  112. janito/tools/adapters/local/view_file.py +167 -167
  113. janito/tools/inspect_registry.py +17 -17
  114. janito/tools/tool_base.py +105 -105
  115. janito/tools/tool_events.py +58 -58
  116. janito/tools/tool_run_exception.py +12 -12
  117. janito/tools/tool_use_tracker.py +81 -81
  118. janito/tools/tool_utils.py +45 -45
  119. janito/tools/tools_adapter.py +78 -6
  120. janito/tools/tools_schema.py +104 -104
  121. janito/version.py +4 -4
  122. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/METADATA +388 -251
  123. janito-2.3.0.dist-info/RECORD +181 -0
  124. janito/drivers/google_genai/driver.py +0 -54
  125. janito/drivers/google_genai/schema_generator.py +0 -67
  126. janito-2.2.0.dist-info/RECORD +0 -182
  127. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/WHEEL +0 -0
  128. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/entry_points.txt +0 -0
  129. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/licenses/LICENSE +0 -0
  130. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/top_level.txt +0 -0
@@ -1,163 +1,163 @@
1
- import subprocess
2
- import os
3
- import sys
4
- import tempfile
5
- import threading
6
- from janito.tools.tool_base import ToolBase
7
- from janito.report_events import ReportAction
8
- from janito.tools.adapters.local.adapter import register_local_tool
9
- from janito.i18n import tr
10
-
11
-
12
- @register_local_tool
13
- class PythonFileRunTool(ToolBase):
14
- """
15
- Tool to execute a specified Python script file.
16
-
17
- Parameters:
18
- file_path (str): Path to the Python script file to execute.
19
- timeout (int): Timeout in seconds for the command. Defaults to 60.
20
-
21
- Returns:
22
- str: Output and status message, or file paths/line counts if output is large.
23
- """
24
- provides_execution = True
25
- tool_name = "python_file_run"
26
-
27
- def run(self, file_path: str, timeout: int = 60) -> str:
28
- self.report_action(
29
- tr("🚀 Running: python {file_path}", file_path=file_path),
30
- ReportAction.EXECUTE,
31
- )
32
- self.report_stdout("\n")
33
- try:
34
- with (
35
- tempfile.NamedTemporaryFile(
36
- mode="w+",
37
- prefix="python_file_stdout_",
38
- delete=False,
39
- encoding="utf-8",
40
- ) as stdout_file,
41
- tempfile.NamedTemporaryFile(
42
- mode="w+",
43
- prefix="python_file_stderr_",
44
- delete=False,
45
- encoding="utf-8",
46
- ) as stderr_file,
47
- ):
48
- process = subprocess.Popen(
49
- [sys.executable, file_path],
50
- stdout=subprocess.PIPE,
51
- stderr=subprocess.PIPE,
52
- text=True,
53
- bufsize=1,
54
- universal_newlines=True,
55
- encoding="utf-8",
56
- env={**os.environ, "PYTHONIOENCODING": "utf-8"},
57
- )
58
- stdout_lines, stderr_lines = self._stream_process_output(
59
- process, stdout_file, stderr_file
60
- )
61
- return_code = self._wait_for_process(process, timeout)
62
- if return_code is None:
63
- return tr(
64
- "Code timed out after {timeout} seconds.", timeout=timeout
65
- )
66
- stdout_file.flush()
67
- stderr_file.flush()
68
- self.report_success(
69
- tr("✅ Return code {return_code}", return_code=return_code),
70
- ReportAction.EXECUTE,
71
- )
72
- return self._format_result(
73
- stdout_file.name, stderr_file.name, return_code
74
- )
75
- except Exception as e:
76
- self.report_error(tr("❌ Error: {error}", error=e), ReportAction.EXECUTE)
77
- return tr("Error running file: {error}", error=e)
78
-
79
- def _stream_process_output(self, process, stdout_file, stderr_file):
80
- stdout_lines = 0
81
- stderr_lines = 0
82
-
83
- def stream_output(stream, file_obj, report_func, count_func):
84
- nonlocal stdout_lines, stderr_lines
85
- for line in stream:
86
- file_obj.write(line)
87
- file_obj.flush()
88
- # Always supply a default action for stdout/stderr reporting
89
- from janito.report_events import ReportAction
90
-
91
- report_func(line.rstrip("\r\n"), ReportAction.EXECUTE)
92
- if count_func == "stdout":
93
- stdout_lines += 1
94
- else:
95
- stderr_lines += 1
96
-
97
- stdout_thread = threading.Thread(
98
- target=stream_output,
99
- args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
100
- )
101
- stderr_thread = threading.Thread(
102
- target=stream_output,
103
- args=(process.stderr, stderr_file, self.report_stderr, "stderr"),
104
- )
105
- stdout_thread.start()
106
- stderr_thread.start()
107
- stdout_thread.join()
108
- stderr_thread.join()
109
- return stdout_lines, stderr_lines
110
-
111
- def _wait_for_process(self, process, timeout):
112
- try:
113
- return process.wait(timeout=timeout)
114
- except subprocess.TimeoutExpired:
115
- process.kill()
116
- self.report_error(
117
- tr("❌ Timed out after {timeout} seconds.", timeout=timeout),
118
- ReportAction.EXECUTE,
119
- )
120
- return None
121
-
122
- def _format_result(self, stdout_file_name, stderr_file_name, return_code):
123
- with open(stdout_file_name, "r", encoding="utf-8", errors="replace") as out_f:
124
- stdout_content = out_f.read()
125
- with open(stderr_file_name, "r", encoding="utf-8", errors="replace") as err_f:
126
- stderr_content = err_f.read()
127
- max_lines = 100
128
- stdout_lines = stdout_content.count("\n")
129
- stderr_lines = stderr_content.count("\n")
130
-
131
- def head_tail(text, n=10):
132
- lines = text.splitlines()
133
- if len(lines) <= 2 * n:
134
- return "\n".join(lines)
135
- return "\n".join(
136
- lines[:n]
137
- + ["... ({} lines omitted) ...".format(len(lines) - 2 * n)]
138
- + lines[-n:]
139
- )
140
-
141
- if stdout_lines <= max_lines and stderr_lines <= max_lines:
142
- result = f"Return code: {return_code}\n--- python_file_run: STDOUT ---\n{stdout_content}"
143
- if stderr_content.strip():
144
- result += f"\n--- python_file_run: STDERR ---\n{stderr_content}"
145
- return result
146
- else:
147
- result = f"stdout_file: {stdout_file_name} (lines: {stdout_lines})\n"
148
- if stderr_lines > 0 and stderr_content.strip():
149
- result += f"stderr_file: {stderr_file_name} (lines: {stderr_lines})\n"
150
- result += f"returncode: {return_code}\n"
151
- result += (
152
- "--- python_file_run: STDOUT (head/tail) ---\n"
153
- + head_tail(stdout_content)
154
- + "\n"
155
- )
156
- if stderr_content.strip():
157
- result += (
158
- "--- python_file_run: STDERR (head/tail) ---\n"
159
- + head_tail(stderr_content)
160
- + "\n"
161
- )
162
- result += "Use the view_file tool to inspect the contents of these files when needed."
163
- return result
1
+ import subprocess
2
+ import os
3
+ import sys
4
+ import tempfile
5
+ import threading
6
+ from janito.tools.tool_base import ToolBase
7
+ from janito.report_events import ReportAction
8
+ from janito.tools.adapters.local.adapter import register_local_tool
9
+ from janito.i18n import tr
10
+
11
+
12
+ @register_local_tool
13
+ class PythonFileRunTool(ToolBase):
14
+ """
15
+ Tool to execute a specified Python script file.
16
+
17
+ Parameters:
18
+ file_path (str): Path to the Python script file to execute.
19
+ timeout (int): Timeout in seconds for the command. Defaults to 60.
20
+
21
+ Returns:
22
+ str: Output and status message, or file paths/line counts if output is large.
23
+ """
24
+ provides_execution = True
25
+ tool_name = "python_file_run"
26
+
27
+ def run(self, file_path: str, timeout: int = 60) -> str:
28
+ self.report_action(
29
+ tr("🚀 Running: python {file_path}", file_path=file_path),
30
+ ReportAction.EXECUTE,
31
+ )
32
+ self.report_stdout("\n")
33
+ try:
34
+ with (
35
+ tempfile.NamedTemporaryFile(
36
+ mode="w+",
37
+ prefix="python_file_stdout_",
38
+ delete=False,
39
+ encoding="utf-8",
40
+ ) as stdout_file,
41
+ tempfile.NamedTemporaryFile(
42
+ mode="w+",
43
+ prefix="python_file_stderr_",
44
+ delete=False,
45
+ encoding="utf-8",
46
+ ) as stderr_file,
47
+ ):
48
+ process = subprocess.Popen(
49
+ [sys.executable, file_path],
50
+ stdout=subprocess.PIPE,
51
+ stderr=subprocess.PIPE,
52
+ text=True,
53
+ bufsize=1,
54
+ universal_newlines=True,
55
+ encoding="utf-8",
56
+ env={**os.environ, "PYTHONIOENCODING": "utf-8"},
57
+ )
58
+ stdout_lines, stderr_lines = self._stream_process_output(
59
+ process, stdout_file, stderr_file
60
+ )
61
+ return_code = self._wait_for_process(process, timeout)
62
+ if return_code is None:
63
+ return tr(
64
+ "Code timed out after {timeout} seconds.", timeout=timeout
65
+ )
66
+ stdout_file.flush()
67
+ stderr_file.flush()
68
+ self.report_success(
69
+ tr("✅ Return code {return_code}", return_code=return_code),
70
+ ReportAction.EXECUTE,
71
+ )
72
+ return self._format_result(
73
+ stdout_file.name, stderr_file.name, return_code
74
+ )
75
+ except Exception as e:
76
+ self.report_error(tr("❌ Error: {error}", error=e), ReportAction.EXECUTE)
77
+ return tr("Error running file: {error}", error=e)
78
+
79
+ def _stream_process_output(self, process, stdout_file, stderr_file):
80
+ stdout_lines = 0
81
+ stderr_lines = 0
82
+
83
+ def stream_output(stream, file_obj, report_func, count_func):
84
+ nonlocal stdout_lines, stderr_lines
85
+ for line in stream:
86
+ file_obj.write(line)
87
+ file_obj.flush()
88
+ # Always supply a default action for stdout/stderr reporting
89
+ from janito.report_events import ReportAction
90
+
91
+ report_func(line.rstrip("\r\n"), ReportAction.EXECUTE)
92
+ if count_func == "stdout":
93
+ stdout_lines += 1
94
+ else:
95
+ stderr_lines += 1
96
+
97
+ stdout_thread = threading.Thread(
98
+ target=stream_output,
99
+ args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
100
+ )
101
+ stderr_thread = threading.Thread(
102
+ target=stream_output,
103
+ args=(process.stderr, stderr_file, self.report_stderr, "stderr"),
104
+ )
105
+ stdout_thread.start()
106
+ stderr_thread.start()
107
+ stdout_thread.join()
108
+ stderr_thread.join()
109
+ return stdout_lines, stderr_lines
110
+
111
+ def _wait_for_process(self, process, timeout):
112
+ try:
113
+ return process.wait(timeout=timeout)
114
+ except subprocess.TimeoutExpired:
115
+ process.kill()
116
+ self.report_error(
117
+ tr("❌ Timed out after {timeout} seconds.", timeout=timeout),
118
+ ReportAction.EXECUTE,
119
+ )
120
+ return None
121
+
122
+ def _format_result(self, stdout_file_name, stderr_file_name, return_code):
123
+ with open(stdout_file_name, "r", encoding="utf-8", errors="replace") as out_f:
124
+ stdout_content = out_f.read()
125
+ with open(stderr_file_name, "r", encoding="utf-8", errors="replace") as err_f:
126
+ stderr_content = err_f.read()
127
+ max_lines = 100
128
+ stdout_lines = stdout_content.count("\n")
129
+ stderr_lines = stderr_content.count("\n")
130
+
131
+ def head_tail(text, n=10):
132
+ lines = text.splitlines()
133
+ if len(lines) <= 2 * n:
134
+ return "\n".join(lines)
135
+ return "\n".join(
136
+ lines[:n]
137
+ + ["... ({} lines omitted) ...".format(len(lines) - 2 * n)]
138
+ + lines[-n:]
139
+ )
140
+
141
+ if stdout_lines <= max_lines and stderr_lines <= max_lines:
142
+ result = f"Return code: {return_code}\n--- python_file_run: STDOUT ---\n{stdout_content}"
143
+ if stderr_content.strip():
144
+ result += f"\n--- python_file_run: STDERR ---\n{stderr_content}"
145
+ return result
146
+ else:
147
+ result = f"stdout_file: {stdout_file_name} (lines: {stdout_lines})\n"
148
+ if stderr_lines > 0 and stderr_content.strip():
149
+ result += f"stderr_file: {stderr_file_name} (lines: {stderr_lines})\n"
150
+ result += f"returncode: {return_code}\n"
151
+ result += (
152
+ "--- python_file_run: STDOUT (head/tail) ---\n"
153
+ + head_tail(stdout_content)
154
+ + "\n"
155
+ )
156
+ if stderr_content.strip():
157
+ result += (
158
+ "--- python_file_run: STDERR (head/tail) ---\n"
159
+ + head_tail(stderr_content)
160
+ + "\n"
161
+ )
162
+ result += "Use the view_file tool to inspect the contents of these files when needed."
163
+ return result
@@ -28,36 +28,25 @@ class RemoveDirectoryTool(ToolBase):
28
28
  disp_path = display_path(file_path)
29
29
  self.report_action(
30
30
  tr("🗃️ Remove directory '{disp_path}' ...", disp_path=disp_path),
31
- ReportAction.CREATE,
31
+ ReportAction.DELETE,
32
32
  )
33
- backup_zip = None
33
+
34
34
  try:
35
35
  if recursive:
36
- # Backup before recursive removal
37
- if os.path.exists(file_path) and os.path.isdir(file_path):
38
- backup_zip = file_path.rstrip("/\\") + ".bak.zip"
39
- with zipfile.ZipFile(backup_zip, "w", zipfile.ZIP_DEFLATED) as zipf:
40
- for root, dirs, files in os.walk(file_path):
41
- for file in files:
42
- abs_path = os.path.join(root, file)
43
- rel_path = os.path.relpath(
44
- abs_path, os.path.dirname(file_path)
45
- )
46
- zipf.write(abs_path, rel_path)
36
+
47
37
  shutil.rmtree(file_path)
48
38
  else:
49
39
  os.rmdir(file_path)
50
40
  self.report_success(
51
41
  tr("✅ 1 {dir_word}", dir_word=pluralize("directory", 1)),
52
- ReportAction.CREATE,
42
+ ReportAction.DELETE,
53
43
  )
54
44
  msg = tr("Directory removed: {disp_path}", disp_path=disp_path)
55
- if backup_zip:
56
- msg += tr(" (backup at {backup_zip})", backup_zip=backup_zip)
45
+
57
46
  return msg
58
47
  except Exception as e:
59
48
  self.report_error(
60
49
  tr(" ❌ Error removing directory: {error}", error=e),
61
- ReportAction.REMOVE,
50
+ ReportAction.DELETE,
62
51
  )
63
52
  return tr("Error removing directory: {error}", error=e)
@@ -15,7 +15,7 @@ class RemoveFileTool(ToolBase):
15
15
 
16
16
  Args:
17
17
  file_path (str): Path to the file to remove.
18
- backup (bool, optional): If True, create a backup (.bak) before removing. Recommend using backup=True only in the first call to avoid redundant backups. Defaults to False.
18
+ backup (bool, optional): Deprecated. Backups are no longer created. Flag ignored.
19
19
  Returns:
20
20
  str: Status message indicating the result. Example:
21
21
  - " Successfully removed the file at ..."
@@ -28,7 +28,7 @@ class RemoveFileTool(ToolBase):
28
28
  original_path = file_path
29
29
  path = file_path # Using file_path as is
30
30
  disp_path = display_path(original_path)
31
- backup_path = None
31
+
32
32
  # Report initial info about what is going to be removed
33
33
  self.report_action(
34
34
  tr("🗑️ Remove file '{disp_path}' ...", disp_path=disp_path),
@@ -41,20 +41,14 @@ class RemoveFileTool(ToolBase):
41
41
  self.report_error(tr("❌ Path is not a file."), ReportAction.DELETE)
42
42
  return tr("❌ Path is not a file.")
43
43
  try:
44
- if backup:
45
- backup_path = path + ".bak"
46
- shutil.copy2(path, backup_path)
44
+
47
45
  os.remove(path)
48
46
  self.report_success(tr("✅ File removed"), ReportAction.DELETE)
49
47
  msg = tr(
50
48
  "✅ Successfully removed the file at '{disp_path}'.",
51
49
  disp_path=disp_path,
52
50
  )
53
- if backup_path:
54
- msg += tr(
55
- " (backup at {backup_disp})",
56
- backup_disp=display_path(original_path + ".bak"),
57
- )
51
+
58
52
  return msg
59
53
  except Exception as e:
60
54
  self.report_error(
@@ -21,10 +21,10 @@ class ReplaceTextInFileTool(ToolBase):
21
21
  search_text (str): The exact text to search for (including indentation).
22
22
  replacement_text (str): The text to replace with (including indentation).
23
23
  replace_all (bool): If True, replace all occurrences; otherwise, only the first occurrence.
24
- backup (bool, optional): If True, create a backup (.bak) before replacing. Recommend using backup=True only in the first call to avoid redundant backups. Defaults to False.
24
+ backup (bool, optional): Deprecated. No backups are created anymore and this flag is ignored. Defaults to False.
25
25
  Returns:
26
26
  str: Status message. Example:
27
- - "Text replaced in /path/to/file (backup at /path/to/file.bak)"
27
+ - "Text replaced in /path/to/file"
28
28
  - "No changes made. [Warning: Search text not found in file] Please review the original file."
29
29
  - "Error replacing text: <error message>"
30
30
  """
@@ -63,9 +63,7 @@ class ReplaceTextInFileTool(ToolBase):
63
63
  content, search_text, replacement_text, replace_all, occurrences
64
64
  )
65
65
  file_changed = new_content != content
66
- backup_path = file_path + ".bak"
67
- if backup and file_changed:
68
- self._backup_file(file_path, backup_path)
66
+ backup_path = None
69
67
  validation_result = ""
70
68
  if file_changed:
71
69
  self._write_file_content(file_path, new_content)
@@ -88,7 +86,7 @@ class ReplaceTextInFileTool(ToolBase):
88
86
  replace_all,
89
87
  )
90
88
  return self._format_final_msg(
91
- file_path, warning, backup_path, match_info, details
89
+ file_path, warning, match_info, details
92
90
  ) + (f"\n{validation_result}" if validation_result else "")
93
91
  except Exception as e:
94
92
  self.report_error(tr(" ❌ Error"), ReportAction.REPLACE)
@@ -260,13 +258,12 @@ class ReplaceTextInFileTool(ToolBase):
260
258
  details = ""
261
259
  return match_info, details
262
260
 
263
- def _format_final_msg(self, file_path, warning, backup_path, match_info, details):
261
+ def _format_final_msg(self, file_path, warning, match_info, details):
264
262
  """Format the final status message."""
265
263
  return tr(
266
- "Text replaced in {file_path}{warning} (backup at {backup_path}). {match_info}{details}",
264
+ "Text replaced in {file_path}{warning}. {match_info}{details}",
267
265
  file_path=file_path,
268
266
  warning=warning,
269
- backup_path=backup_path,
270
267
  match_info=match_info,
271
268
  details=details,
272
269
  )