janito 2.5.1__py3-none-any.whl → 2.6.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 (61) hide show
  1. janito/agent/setup_agent.py +231 -223
  2. janito/agent/templates/profiles/system_prompt_template_software_developer.txt.j2 +39 -0
  3. janito/cli/chat_mode/bindings.py +1 -26
  4. janito/cli/chat_mode/session.py +282 -294
  5. janito/cli/chat_mode/session_profile_select.py +125 -55
  6. janito/cli/chat_mode/shell/commands/tools.py +51 -48
  7. janito/cli/chat_mode/toolbar.py +42 -68
  8. janito/cli/cli_commands/list_tools.py +41 -56
  9. janito/cli/cli_commands/show_system_prompt.py +70 -49
  10. janito/cli/core/runner.py +6 -1
  11. janito/cli/core/setters.py +43 -34
  12. janito/cli/main_cli.py +25 -1
  13. janito/cli/prompt_core.py +76 -69
  14. janito/cli/rich_terminal_reporter.py +22 -1
  15. janito/cli/single_shot_mode/handler.py +95 -94
  16. janito/drivers/driver_registry.py +27 -29
  17. janito/drivers/openai/driver.py +436 -494
  18. janito/llm/agent.py +54 -68
  19. janito/provider_registry.py +178 -178
  20. janito/providers/anthropic/model_info.py +41 -22
  21. janito/providers/anthropic/provider.py +80 -67
  22. janito/providers/provider_static_info.py +18 -17
  23. janito/tools/adapters/local/__init__.py +66 -65
  24. janito/tools/adapters/local/adapter.py +79 -18
  25. janito/tools/adapters/local/create_directory.py +9 -9
  26. janito/tools/adapters/local/create_file.py +12 -12
  27. janito/tools/adapters/local/delete_text_in_file.py +16 -16
  28. janito/tools/adapters/local/find_files.py +2 -2
  29. janito/tools/adapters/local/get_file_outline/core.py +5 -5
  30. janito/tools/adapters/local/get_file_outline/search_outline.py +4 -4
  31. janito/tools/adapters/local/open_html_in_browser.py +15 -15
  32. janito/tools/adapters/local/python_file_run.py +4 -4
  33. janito/tools/adapters/local/read_files.py +40 -0
  34. janito/tools/adapters/local/remove_directory.py +5 -5
  35. janito/tools/adapters/local/remove_file.py +4 -4
  36. janito/tools/adapters/local/replace_text_in_file.py +21 -21
  37. janito/tools/adapters/local/run_bash_command.py +1 -1
  38. janito/tools/adapters/local/search_text/pattern_utils.py +2 -2
  39. janito/tools/adapters/local/search_text/traverse_directory.py +10 -10
  40. janito/tools/adapters/local/validate_file_syntax/core.py +7 -7
  41. janito/tools/adapters/local/validate_file_syntax/css_validator.py +2 -2
  42. janito/tools/adapters/local/validate_file_syntax/html_validator.py +7 -7
  43. janito/tools/adapters/local/validate_file_syntax/js_validator.py +2 -2
  44. janito/tools/adapters/local/validate_file_syntax/json_validator.py +2 -2
  45. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +2 -2
  46. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +2 -2
  47. janito/tools/adapters/local/validate_file_syntax/python_validator.py +2 -2
  48. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +2 -2
  49. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +2 -2
  50. janito/tools/adapters/local/view_file.py +12 -12
  51. janito/tools/path_security.py +204 -0
  52. janito/tools/tool_use_tracker.py +12 -12
  53. janito/tools/tools_adapter.py +66 -34
  54. {janito-2.5.1.dist-info → janito-2.6.0.dist-info}/METADATA +412 -412
  55. {janito-2.5.1.dist-info → janito-2.6.0.dist-info}/RECORD +59 -58
  56. janito/drivers/anthropic/driver.py +0 -113
  57. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +0 -156
  58. {janito-2.5.1.dist-info → janito-2.6.0.dist-info}/WHEEL +0 -0
  59. {janito-2.5.1.dist-info → janito-2.6.0.dist-info}/entry_points.txt +0 -0
  60. {janito-2.5.1.dist-info → janito-2.6.0.dist-info}/licenses/LICENSE +0 -0
  61. {janito-2.5.1.dist-info → janito-2.6.0.dist-info}/top_level.txt +0 -0
@@ -1,67 +1,80 @@
1
- from janito.llm.provider import LLMProvider
2
- from janito.llm.model import LLMModelInfo
3
- from janito.llm.auth import LLMAuthManager
4
- from janito.llm.driver_config import LLMDriverConfig
5
- from janito.tools import get_local_tools_adapter
6
- from janito.providers.registry import LLMProviderRegistry
7
-
8
- from .model_info import MODEL_SPECS
9
-
10
- from janito.drivers.anthropic.driver import AnthropicModelDriver
11
-
12
- available = AnthropicModelDriver.available
13
- unavailable_reason = AnthropicModelDriver.unavailable_reason
14
- maintainer = "Needs maintainer"
15
-
16
-
17
- class AnthropicProvider(LLMProvider):
18
- name = "anthropic"
19
- maintainer = "Needs maintainer"
20
- MODEL_SPECS = MODEL_SPECS
21
- DEFAULT_MODEL = "claude-3-opus-20240229"
22
-
23
- def __init__(
24
- self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
25
- ):
26
- # Ensure we always have a tools adapter, even if the driver itself is unavailable.
27
- self._tools_adapter = get_local_tools_adapter()
28
- if not self.available:
29
- self._driver = None
30
- return
31
- self.auth_manager = auth_manager or LLMAuthManager()
32
- self._api_key = self.auth_manager.get_credentials(type(self).name)
33
- self._tools_adapter = get_local_tools_adapter()
34
- self._info = config or LLMDriverConfig(model=None)
35
- if not self._info.model:
36
- self._info.model = self.DEFAULT_MODEL
37
- if not self._info.api_key:
38
- self._info.api_key = self._api_key
39
- self.fill_missing_device_info(self._info)
40
- self._driver = AnthropicModelDriver(tools_adapter=self._tools_adapter)
41
-
42
- @property
43
- def driver(self):
44
- if not self.available:
45
- raise ImportError(
46
- f"AnthropicProvider unavailable: {self.unavailable_reason}"
47
- )
48
- return self._driver
49
-
50
- @property
51
- def available(self):
52
- return available
53
-
54
- @property
55
- def unavailable_reason(self):
56
- return unavailable_reason
57
-
58
- def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
59
- from janito.llm.agent import LLMAgent
60
- from janito.drivers.anthropic.driver import AnthropicModelDriver
61
-
62
- # Always create a new driver with the passed-in tools_adapter
63
- driver = AnthropicModelDriver(tools_adapter=tools_adapter)
64
- return LLMAgent(self, tools_adapter, agent_name=agent_name, **kwargs)
65
-
66
-
67
- LLMProviderRegistry.register(AnthropicProvider.name, AnthropicProvider)
1
+ from janito.llm.provider import LLMProvider
2
+ from janito.llm.model import LLMModelInfo
3
+ from janito.llm.auth import LLMAuthManager
4
+ from janito.llm.driver_config import LLMDriverConfig
5
+ from janito.tools import get_local_tools_adapter
6
+ from janito.providers.registry import LLMProviderRegistry
7
+
8
+ from .model_info import MODEL_SPECS
9
+
10
+ from janito.llm.provider import LLMProvider
11
+ from janito.llm.model import LLMModelInfo
12
+ from janito.llm.auth import LLMAuthManager
13
+ from janito.llm.driver_config import LLMDriverConfig
14
+ from janito.tools import get_local_tools_adapter
15
+ from janito.providers.registry import LLMProviderRegistry
16
+ from .model_info import MODEL_SPECS
17
+ from janito.drivers.openai.driver import OpenAIModelDriver
18
+
19
+ class AnthropicProvider(LLMProvider):
20
+ name = "anthropic"
21
+ maintainer = "Needs maintainer"
22
+ MODEL_SPECS = MODEL_SPECS
23
+ DEFAULT_MODEL = "claude-3-7-sonnet-20250219"
24
+
25
+ def __init__(
26
+ self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
27
+ ):
28
+ self._tools_adapter = get_local_tools_adapter()
29
+ self.auth_manager = auth_manager or LLMAuthManager()
30
+ self._api_key = self.auth_manager.get_credentials(type(self).name)
31
+ self._tools_adapter = get_local_tools_adapter()
32
+ self._driver_config = config or LLMDriverConfig(model=None)
33
+ if not getattr(self._driver_config, 'model', None):
34
+ self._driver_config.model = self.DEFAULT_MODEL
35
+ if not self._driver_config.api_key:
36
+ self._driver_config.api_key = self._api_key
37
+ # Set the Anthropic OpenAI-compatible API endpoint
38
+ self._driver_config.base_url = "https://api.anthropic.com/v1/"
39
+ self.fill_missing_device_info(self._driver_config)
40
+ self._driver = None # to be provided by factory/agent
41
+
42
+ @property
43
+ def driver(self) -> OpenAIModelDriver:
44
+ if not self.available:
45
+ raise ImportError(f"AnthropicProvider unavailable: {self.unavailable_reason}")
46
+ return self._driver
47
+
48
+ @property
49
+ def available(self):
50
+ return OpenAIModelDriver.available
51
+
52
+ @property
53
+ def unavailable_reason(self):
54
+ return OpenAIModelDriver.unavailable_reason
55
+
56
+ def create_driver(self):
57
+ """
58
+ Creates and returns a new OpenAIModelDriver instance configured for Anthropic API.
59
+ """
60
+ driver = OpenAIModelDriver(
61
+ tools_adapter=self._tools_adapter, provider_name=self.name
62
+ )
63
+ driver.config = self._driver_config
64
+ return driver
65
+
66
+ @property
67
+ def model_name(self):
68
+ return self._driver_config.model
69
+
70
+ @property
71
+ def driver_config(self):
72
+ """Public, read-only access to the provider's LLMDriverConfig object."""
73
+ return self._driver_config
74
+
75
+ def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
76
+ self._tools_adapter.event_bus = event_bus
77
+ return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
78
+
79
+
80
+ LLMProviderRegistry.register(AnthropicProvider.name, AnthropicProvider)
@@ -1,17 +1,18 @@
1
- # Provider static metadata registry for listing purposes (name, maintainer, and future fields)
2
- STATIC_PROVIDER_METADATA = {
3
- "openai": {
4
- },
5
- "google": {
6
- "maintainer": "João Pinto <lamego.pinto@gmail.com>",
7
- },
8
- "azure_openai": {
9
- "maintainer": "João Pinto <lamego.pinto@gmail.com>",
10
- },
11
- "anthropic": {
12
- "maintainer": "Needs maintainer",
13
- },
14
- "deepseek": {
15
- "maintainer": "João Pinto <lamego.pinto@gmail.com>",
16
- },
17
- }
1
+ # Provider static metadata registry for listing purposes (name, maintainer, and future fields)
2
+ STATIC_PROVIDER_METADATA = {
3
+ "openai": {
4
+ },
5
+ "google": {
6
+ "maintainer": "João Pinto <lamego.pinto@gmail.com>",
7
+ },
8
+ "azure_openai": {
9
+ "maintainer": "João Pinto <lamego.pinto@gmail.com>",
10
+ },
11
+ "anthropic": {
12
+ "maintainer": "Alberto Minetti <alberto.minetti@gmail.com>",
13
+ },
14
+
15
+ "deepseek": {
16
+ "maintainer": "João Pinto <lamego.pinto@gmail.com>",
17
+ },
18
+ }
@@ -1,65 +1,66 @@
1
- from .adapter import LocalToolsAdapter
2
-
3
- from .ask_user import AskUserTool
4
- from .copy_file import CopyFileTool
5
- from .create_directory import CreateDirectoryTool
6
- from .create_file import CreateFileTool
7
- from .fetch_url import FetchUrlTool
8
- from .find_files import FindFilesTool
9
- from .view_file import ViewFileTool
10
- from .move_file import MoveFileTool
11
- from .open_url import OpenUrlTool
12
- from .open_html_in_browser import OpenHtmlInBrowserTool
13
- from .python_code_run import PythonCodeRunTool
14
- from .python_command_run import PythonCommandRunTool
15
- from .python_file_run import PythonFileRunTool
16
- from .remove_directory import RemoveDirectoryTool
17
- from .remove_file import RemoveFileTool
18
- from .replace_text_in_file import ReplaceTextInFileTool
19
- from .run_bash_command import RunBashCommandTool
20
- from .run_powershell_command import RunPowershellCommandTool
21
- from .get_file_outline.core import GetFileOutlineTool
22
- from .get_file_outline.search_outline import SearchOutlineTool
23
- from .search_text.core import SearchTextTool
24
- from .validate_file_syntax.core import ValidateFileSyntaxTool
25
-
26
- # Singleton tools adapter with all standard tools registered
27
- from janito.tools.tool_base import ToolPermissions
28
- import os
29
- local_tools_adapter = LocalToolsAdapter(workdir=os.getcwd())
30
-
31
- from janito.tools.permissions import get_global_allowed_permissions
32
-
33
- def get_local_tools_adapter(workdir=None):
34
- import os
35
- return LocalToolsAdapter(workdir=workdir or os.getcwd())
36
-
37
- # Register tools
38
- for tool_class in [
39
- AskUserTool,
40
- CopyFileTool,
41
- CreateDirectoryTool,
42
- CreateFileTool,
43
- FetchUrlTool,
44
- FindFilesTool,
45
- ViewFileTool,
46
- MoveFileTool,
47
- OpenUrlTool,
48
- OpenHtmlInBrowserTool,
49
- PythonCodeRunTool,
50
- PythonCommandRunTool,
51
- PythonFileRunTool,
52
- RemoveDirectoryTool,
53
- RemoveFileTool,
54
- ReplaceTextInFileTool,
55
- RunBashCommandTool,
56
- RunPowershellCommandTool,
57
- GetFileOutlineTool,
58
- SearchOutlineTool,
59
- SearchTextTool,
60
- ValidateFileSyntaxTool,
61
- ]:
62
- local_tools_adapter.register_tool(tool_class)
63
-
64
- # DEBUG: Print registered tools at startup
65
-
1
+ from .adapter import LocalToolsAdapter
2
+
3
+ from .ask_user import AskUserTool
4
+ from .copy_file import CopyFileTool
5
+ from .create_directory import CreateDirectoryTool
6
+ from .create_file import CreateFileTool
7
+ from .fetch_url import FetchUrlTool
8
+ from .find_files import FindFilesTool
9
+ from .view_file import ViewFileTool
10
+ from .read_files import ReadFilesTool
11
+ from .move_file import MoveFileTool
12
+ from .open_url import OpenUrlTool
13
+ from .open_html_in_browser import OpenHtmlInBrowserTool
14
+ from .python_code_run import PythonCodeRunTool
15
+ from .python_command_run import PythonCommandRunTool
16
+ from .python_file_run import PythonFileRunTool
17
+ from .remove_directory import RemoveDirectoryTool
18
+ from .remove_file import RemoveFileTool
19
+ from .replace_text_in_file import ReplaceTextInFileTool
20
+ from .run_bash_command import RunBashCommandTool
21
+ from .run_powershell_command import RunPowershellCommandTool
22
+ from .get_file_outline.core import GetFileOutlineTool
23
+ from .get_file_outline.search_outline import SearchOutlineTool
24
+ from .search_text.core import SearchTextTool
25
+ from .validate_file_syntax.core import ValidateFileSyntaxTool
26
+
27
+ from janito.tools.tool_base import ToolPermissions
28
+ import os
29
+ from janito.tools.permissions import get_global_allowed_permissions
30
+
31
+ # Singleton tools adapter with all standard tools registered
32
+ local_tools_adapter = LocalToolsAdapter(workdir=os.getcwd())
33
+
34
+ def get_local_tools_adapter(workdir=None):
35
+ return LocalToolsAdapter(workdir=workdir or os.getcwd())
36
+
37
+ # Register tools
38
+ for tool_class in [
39
+ AskUserTool,
40
+ CopyFileTool,
41
+ CreateDirectoryTool,
42
+ CreateFileTool,
43
+ FetchUrlTool,
44
+ FindFilesTool,
45
+ ViewFileTool,
46
+ ReadFilesTool,
47
+ MoveFileTool,
48
+ OpenUrlTool,
49
+ OpenHtmlInBrowserTool,
50
+ PythonCodeRunTool,
51
+ PythonCommandRunTool,
52
+ PythonFileRunTool,
53
+ RemoveDirectoryTool,
54
+ RemoveFileTool,
55
+ ReplaceTextInFileTool,
56
+ RunBashCommandTool,
57
+ RunPowershellCommandTool,
58
+ GetFileOutlineTool,
59
+ SearchOutlineTool,
60
+ SearchTextTool,
61
+ ValidateFileSyntaxTool,
62
+ ]:
63
+ local_tools_adapter.register_tool(tool_class)
64
+
65
+ # DEBUG: Print registered tools at startup
66
+
@@ -18,16 +18,51 @@ class LocalToolsAdapter(ToolsAdapter):
18
18
  """
19
19
 
20
20
  def __init__(self, tools=None, event_bus=None, workdir=None):
21
+ """Create a new LocalToolsAdapter.
22
+
23
+ Parameters
24
+ ----------
25
+ tools : list, optional
26
+ An optional iterable with tool *classes* (not instances) that should
27
+ be registered immediately.
28
+ event_bus : janito.event_bus.bus.EventBus, optional
29
+ The event bus to which tool-related events will be published. When
30
+ *None* (default) the **global** :pydata:`janito.event_bus.bus.event_bus`
31
+ singleton is used so that CLI components such as the
32
+ :class:`janito.cli.rich_terminal_reporter.RichTerminalReporter` will
33
+ receive security violation or execution events automatically.
34
+ workdir : str | pathlib.Path, optional
35
+ Base directory that path-security checks will allow. Defaults to
36
+ the current working directory at the time of instantiation.
37
+ """
38
+ # Fall back to the global event bus so that ReportEvents emitted from
39
+ # the tools adapter (for example path-security violations) are visible
40
+ # to UI components even if the caller did not supply a custom bus.
41
+ if event_bus is None:
42
+ from janito.event_bus.bus import event_bus as global_event_bus
43
+ event_bus = global_event_bus
44
+
21
45
  super().__init__(tools=tools, event_bus=event_bus)
46
+
47
+ # Internal registry structure: { tool_name: {"class": cls, "instance": obj, "function": obj.run} }
22
48
  self._tools: Dict[str, Dict[str, Any]] = {}
23
- self.workdir = workdir
24
- if self.workdir:
25
- import os
26
- os.chdir(self.workdir)
49
+
50
+ import os
51
+ self.workdir = workdir or os.getcwd()
52
+ # Ensure *some* workdir is set – fallback to CWD.
53
+ if not self.workdir:
54
+ self.workdir = os.getcwd()
55
+ # Normalise by changing the actual process working directory for
56
+ # consistency with many file-system tools.
57
+ os.chdir(self.workdir)
58
+
27
59
  if tools:
28
60
  for tool in tools:
29
61
  self.register_tool(tool)
30
62
 
63
+ # ---------------------------------------------------------------------
64
+ # Registration helpers
65
+ # ---------------------------------------------------------------------
31
66
  def register_tool(self, tool_class: Type):
32
67
  instance = tool_class()
33
68
  if not hasattr(instance, "run") or not callable(instance.run):
@@ -54,28 +89,43 @@ class LocalToolsAdapter(ToolsAdapter):
54
89
  def disable_tool(self, name: str):
55
90
  self.unregister_tool(name)
56
91
 
92
+ # ------------------------------------------------------------------
93
+ # Lookup helpers used by ToolsAdapterBase
94
+ # ------------------------------------------------------------------
57
95
  def get_tool(self, name: str):
58
96
  return self._tools[name]["instance"] if name in self._tools else None
59
97
 
60
98
  def list_tools(self):
61
- return [name for name, entry in self._tools.items() if self.is_tool_allowed(entry["instance"])]
99
+ return [
100
+ name
101
+ for name, entry in self._tools.items()
102
+ if self.is_tool_allowed(entry["instance"])
103
+ ]
62
104
 
63
105
  def get_tool_classes(self):
64
- return [entry["class"] for entry in self._tools.values() if self.is_tool_allowed(entry["instance"])]
106
+ return [
107
+ entry["class"]
108
+ for entry in self._tools.values()
109
+ if self.is_tool_allowed(entry["instance"])
110
+ ]
65
111
 
66
112
  def get_tools(self):
67
- return [entry["instance"] for entry in self._tools.values() if self.is_tool_allowed(entry["instance"])]
68
-
69
-
113
+ return [
114
+ entry["instance"]
115
+ for entry in self._tools.values()
116
+ if self.is_tool_allowed(entry["instance"])
117
+ ]
118
+
119
+ # ------------------------------------------------------------------
120
+ # Convenience methods
121
+ # ------------------------------------------------------------------
70
122
  def add_tool(self, tool):
71
- # Register by instance (useful for hand-built objects)
123
+ """Register an *instance* (instead of a class) as a tool."""
72
124
  if not hasattr(tool, "run") or not callable(tool.run):
73
125
  raise TypeError(f"Tool '{tool}' must implement a callable 'run' method.")
74
126
  tool_name = getattr(tool, "tool_name", None)
75
127
  if not tool_name or not isinstance(tool_name, str):
76
- raise ValueError(
77
- f"Tool '{tool}' must provide a 'tool_name' (str) attribute."
78
- )
128
+ raise ValueError(f"Tool '{tool}' must provide a 'tool_name' (str) attribute.")
79
129
  if tool_name in self._tools:
80
130
  raise ValueError(f"Tool '{tool_name}' is already registered.")
81
131
  self._tools[tool_name] = {
@@ -85,17 +135,28 @@ class LocalToolsAdapter(ToolsAdapter):
85
135
  }
86
136
 
87
137
 
88
- # Optional: a local-tool decorator
89
-
138
+ # -------------------------------------------------------------------------
139
+ # Decorator helper for quick registration of local tools
140
+ # -------------------------------------------------------------------------
90
141
 
91
142
  def register_local_tool(tool=None):
143
+ """Class decorator that registers the tool on the *singleton* adapter.
144
+
145
+ Example
146
+ -------
147
+ >>> @register_local_tool
148
+ ... class MyTool(BaseTool):
149
+ ... ...
150
+ """
151
+
92
152
  def decorator(cls):
93
- from janito.tools.tool_base import ToolPermissions
94
- from janito.tools.permissions import get_global_allowed_permissions
153
+ # Register the tool on a *fresh* adapter instance to avoid circular
154
+ # import issues during package initialisation. This keeps behaviour
155
+ # identical to the original implementation while still allowing
156
+ # immediate use via the singleton in janito.tools.adapters.local.
95
157
  LocalToolsAdapter().register_tool(cls)
96
158
  return cls
97
159
 
98
160
  if tool is None:
99
161
  return decorator
100
162
  return decorator(tool)
101
-
@@ -10,9 +10,9 @@ import os
10
10
  @register_local_tool
11
11
  class CreateDirectoryTool(ToolBase):
12
12
  """
13
- Create a new directory at the specified file_path.
13
+ Create a new directory at the specified path.
14
14
  Args:
15
- file_path (str): Path for the new directory.
15
+ path (str): Path for the new directory.
16
16
  Returns:
17
17
  str: Status message indicating the result. Example:
18
18
  - "5c5 Successfully created the directory at ..."
@@ -21,17 +21,17 @@ class CreateDirectoryTool(ToolBase):
21
21
  permissions = ToolPermissions(write=True)
22
22
  tool_name = "create_directory"
23
23
 
24
- def run(self, file_path: str) -> str:
25
- # file_path = expand_path(file_path)
26
- # Using file_path as is
27
- disp_path = display_path(file_path)
24
+ def run(self, path: str) -> str:
25
+ # path = expand_path(path)
26
+ # Using path as is
27
+ disp_path = display_path(path)
28
28
  self.report_action(
29
29
  tr("📁 Create directory '{disp_path}' ...", disp_path=disp_path),
30
30
  ReportAction.CREATE,
31
31
  )
32
32
  try:
33
- if os.path.exists(file_path):
34
- if not os.path.isdir(file_path):
33
+ if os.path.exists(path):
34
+ if not os.path.isdir(path):
35
35
  self.report_error(
36
36
  tr(
37
37
  "❌ Path '{disp_path}' exists and is not a directory.",
@@ -52,7 +52,7 @@ class CreateDirectoryTool(ToolBase):
52
52
  "❗ Cannot create directory: '{disp_path}' already exists.",
53
53
  disp_path=disp_path,
54
54
  )
55
- os.makedirs(file_path, exist_ok=True)
55
+ os.makedirs(path, exist_ok=True)
56
56
  self.report_success(tr("✅ Directory created"))
57
57
  return tr(
58
58
  "✅ Successfully created the directory at '{disp_path}'.",
@@ -16,7 +16,7 @@ class CreateFileTool(ToolBase):
16
16
  Create a new file with the given content.
17
17
 
18
18
  Args:
19
- file_path (str): Path to the file to create.
19
+ path (str): Path to the file to create.
20
20
  content (str): Content to write to the file.
21
21
  overwrite (bool, optional): Overwrite existing file if True. Default: False. Recommended only after reading the file to be overwritten.
22
22
  Returns:
@@ -28,13 +28,13 @@ class CreateFileTool(ToolBase):
28
28
  permissions = ToolPermissions(write=True)
29
29
  tool_name = "create_file"
30
30
 
31
- def run(self, file_path: str, content: str, overwrite: bool = False) -> str:
32
- expanded_file_path = file_path # Using file_path as is
33
- disp_path = display_path(expanded_file_path)
34
- file_path = expanded_file_path
35
- if os.path.exists(file_path) and not overwrite:
31
+ def run(self, path: str, content: str, overwrite: bool = False) -> str:
32
+ expanded_path = path # Using path as is
33
+ disp_path = display_path(expanded_path)
34
+ path = expanded_path
35
+ if os.path.exists(path) and not overwrite:
36
36
  try:
37
- with open(file_path, "r", encoding="utf-8", errors="replace") as f:
37
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
38
38
  existing_content = f.read()
39
39
  except Exception as e:
40
40
  existing_content = f"[Error reading file: {e}]"
@@ -44,14 +44,14 @@ class CreateFileTool(ToolBase):
44
44
  existing_content=existing_content,
45
45
  )
46
46
  # Determine if we are overwriting an existing file
47
- is_overwrite = os.path.exists(file_path) and overwrite
47
+ is_overwrite = os.path.exists(path) and overwrite
48
48
  if is_overwrite:
49
49
  # Overwrite branch: log only overwrite warning (no create message)
50
50
  self.report_action(
51
- tr("⚠️ Overwriting file '{disp_path}'", disp_path=disp_path),
51
+ tr("⚠️ Overwriting file '{disp_path}'", disp_path=disp_path),
52
52
  ReportAction.CREATE,
53
53
  )
54
- dir_name = os.path.dirname(file_path)
54
+ dir_name = os.path.dirname(path)
55
55
  if dir_name:
56
56
  os.makedirs(dir_name, exist_ok=True)
57
57
  if not is_overwrite:
@@ -60,14 +60,14 @@ class CreateFileTool(ToolBase):
60
60
  tr("📝 Create file '{disp_path}' ...", disp_path=disp_path),
61
61
  ReportAction.CREATE,
62
62
  )
63
- with open(file_path, "w", encoding="utf-8", errors="replace") as f:
63
+ with open(path, "w", encoding="utf-8", errors="replace") as f:
64
64
  f.write(content)
65
65
  new_lines = content.count("\n") + 1 if content else 0
66
66
  self.report_success(
67
67
  tr("✅ {new_lines} lines", new_lines=new_lines), ReportAction.CREATE
68
68
  )
69
69
  # Perform syntax validation and append result
70
- validation_result = validate_file_syntax(file_path)
70
+ validation_result = validate_file_syntax(path)
71
71
  if is_overwrite:
72
72
  # Overwrite branch: return minimal overwrite info to user
73
73
  return (
@@ -12,7 +12,7 @@ class DeleteTextInFileTool(ToolBase):
12
12
  Delete all occurrences of text between start_marker and end_marker (inclusive) in a file, using exact string markers.
13
13
 
14
14
  Args:
15
- file_path (str): Path to the file to modify.
15
+ path (str): Path to the file to modify.
16
16
  start_marker (str): The starting delimiter string.
17
17
  end_marker (str): The ending delimiter string.
18
18
 
@@ -24,14 +24,14 @@ class DeleteTextInFileTool(ToolBase):
24
24
 
25
25
  def run(
26
26
  self,
27
- file_path: str,
27
+ path: str,
28
28
  start_marker: str,
29
29
  end_marker: str,
30
30
  backup: bool = False,
31
31
  ) -> str:
32
32
  from janito.tools.tool_utils import display_path
33
33
 
34
- disp_path = display_path(file_path)
34
+ disp_path = display_path(path)
35
35
  info_msg = tr(
36
36
  "📝 Delete text in {disp_path} between markers: '{start_marker}' ... '{end_marker}'",
37
37
  disp_path=disp_path,
@@ -40,7 +40,7 @@ class DeleteTextInFileTool(ToolBase):
40
40
  )
41
41
  self.report_action(info_msg, ReportAction.CREATE)
42
42
  try:
43
- content = self._read_file_content(file_path)
43
+ content = self._read_file_content(path)
44
44
  occurrences, match_lines = self._find_marker_blocks(
45
45
  content, start_marker, end_marker
46
46
  )
@@ -49,27 +49,27 @@ class DeleteTextInFileTool(ToolBase):
49
49
  tr(" ℹ️ No blocks found between markers."), ReportAction.CREATE
50
50
  )
51
51
  return tr(
52
- "No blocks found between markers in {file_path}.",
53
- file_path=file_path,
52
+ "No blocks found between markers in {path}.",
53
+ path=path,
54
54
  )
55
55
 
56
56
  new_content, deleted_blocks = self._delete_blocks(
57
57
  content, start_marker, end_marker
58
58
  )
59
- self._write_file_content(file_path, new_content)
60
- validation_result = validate_file_syntax(file_path)
59
+ self._write_file_content(path, new_content)
60
+ validation_result = validate_file_syntax(path)
61
61
  self._report_success(match_lines)
62
62
  return tr(
63
- "Deleted {count} block(s) between markers in {file_path}. ",
63
+ "Deleted {count} block(s) between markers in {path}. ",
64
64
  count=deleted_blocks,
65
- file_path=file_path
65
+ path=path
66
66
  ) + (f"\n{validation_result}" if validation_result else "")
67
67
  except Exception as e:
68
68
  self.report_error(tr(" ❌ Error: {error}", error=e), ReportAction.REPLACE)
69
69
  return tr("Error deleting text: {error}", error=e)
70
70
 
71
- def _read_file_content(self, file_path):
72
- with open(file_path, "r", encoding="utf-8", errors="replace") as f:
71
+ def _read_file_content(self, path):
72
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
73
73
  return f.read()
74
74
 
75
75
  def _find_marker_blocks(self, content, start_marker, end_marker):
@@ -110,11 +110,11 @@ class DeleteTextInFileTool(ToolBase):
110
110
  count += 1
111
111
  return new_content, count
112
112
 
113
- def _backup_file(self, file_path, backup_path):
114
- shutil.copy2(file_path, backup_path)
113
+ def _backup_file(self, path, backup_path):
114
+ shutil.copy2(path, backup_path)
115
115
 
116
- def _write_file_content(self, file_path, content):
117
- with open(file_path, "w", encoding="utf-8", errors="replace") as f:
116
+ def _write_file_content(self, path, content):
117
+ with open(path, "w", encoding="utf-8", errors="replace") as f:
118
118
  f.write(content)
119
119
 
120
120
  def _report_success(self, match_lines):