janito 3.8.0__py3-none-any.whl → 3.10.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 (77) hide show
  1. janito/agent_events.py +75 -0
  2. janito/cli/chat_mode/session.py +1 -0
  3. janito/cli/chat_mode/shell/commands/__init__.py +2 -0
  4. janito/cli/chat_mode/shell/commands/interactive.py +33 -0
  5. janito/cli/chat_mode/toolbar.py +16 -1
  6. janito/cli/cli_commands/list_tools.py +1 -1
  7. janito/cli/core/runner.py +33 -0
  8. janito/cli/main_cli.py +9 -0
  9. janito/cli/prompt_core.py +301 -257
  10. janito/cli/rich_terminal_reporter.py +170 -171
  11. janito/cli/single_shot_mode/handler.py +19 -0
  12. janito/llm/agent.py +65 -0
  13. janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/core.py +7 -2
  14. janito/plugins/core/filemanager/tools/validate_file_syntax/txt_validator.py +28 -0
  15. janito/plugins/manager.py +1 -1
  16. janito/{tools/adapters → plugins/tools}/local/__init__.py +7 -0
  17. janito/{tools/adapters → plugins/tools}/local/adapter.py +1 -1
  18. janito/{tools/adapters → plugins/tools}/local/ask_user.py +1 -1
  19. janito/{tools/adapters → plugins/tools}/local/copy_file.py +1 -1
  20. janito/{tools/adapters → plugins/tools}/local/create_directory.py +45 -2
  21. janito/{tools/adapters → plugins/tools}/local/create_file.py +10 -6
  22. janito/{tools/adapters → plugins/tools}/local/delete_text_in_file.py +2 -2
  23. janito/{tools/adapters → plugins/tools}/local/fetch_url.py +3 -3
  24. janito/{tools/adapters → plugins/tools}/local/find_files.py +1 -1
  25. janito/{tools/adapters → plugins/tools}/local/get_file_outline/core.py +2 -2
  26. janito/{tools/adapters → plugins/tools}/local/move_file.py +1 -1
  27. janito/{tools/adapters → plugins/tools}/local/open_html_in_browser.py +1 -1
  28. janito/{tools/adapters → plugins/tools}/local/open_url.py +1 -1
  29. janito/{tools/adapters → plugins/tools}/local/python_code_run.py +1 -1
  30. janito/{tools/adapters → plugins/tools}/local/python_command_run.py +1 -1
  31. janito/{tools/adapters → plugins/tools}/local/python_file_run.py +1 -1
  32. janito/{tools/adapters → plugins/tools}/local/read_chart.py +1 -1
  33. janito/{tools/adapters → plugins/tools}/local/read_files.py +1 -1
  34. janito/{tools/adapters → plugins/tools}/local/remove_directory.py +1 -1
  35. janito/{tools/adapters → plugins/tools}/local/remove_file.py +1 -1
  36. janito/{tools/adapters → plugins/tools}/local/replace_text_in_file.py +2 -2
  37. janito/{tools/adapters → plugins/tools}/local/run_bash_command.py +1 -1
  38. janito/{tools/adapters → plugins/tools}/local/run_powershell_command.py +1 -1
  39. janito/{tools/adapters → plugins/tools}/local/search_text/core.py +2 -2
  40. janito/{tools/adapters → plugins/tools}/local/show_image.py +1 -1
  41. janito/{tools/adapters → plugins/tools}/local/show_image_grid.py +1 -1
  42. janito/plugins/tools/local/validate_file_syntax/__init__.py +1 -0
  43. janito/plugins/tools/local/validate_file_syntax/core.py +119 -0
  44. janito/plugins/tools/local/validate_file_syntax/txt_validator.py +28 -0
  45. janito/{tools/adapters → plugins/tools}/local/view_file.py +1 -1
  46. janito/tests/test_tool_adapter_case_insensitive.py +112 -0
  47. janito/tools/__init__.py +2 -2
  48. janito/tools/inspect_registry.py +1 -1
  49. janito/tools/tool_base.py +8 -1
  50. janito/tools/tools_adapter.py +514 -510
  51. {janito-3.8.0.dist-info → janito-3.10.0.dist-info}/METADATA +84 -84
  52. {janito-3.8.0.dist-info → janito-3.10.0.dist-info}/RECORD +77 -70
  53. /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/__init__.py +0 -0
  54. /janito/{tools/adapters → plugins/tools}/__init__.py +0 -0
  55. /janito/{tools/adapters → plugins/tools}/local/get_file_outline/__init__.py +0 -0
  56. /janito/{tools/adapters → plugins/tools}/local/get_file_outline/java_outline.py +0 -0
  57. /janito/{tools/adapters → plugins/tools}/local/get_file_outline/markdown_outline.py +0 -0
  58. /janito/{tools/adapters → plugins/tools}/local/get_file_outline/python_outline.py +0 -0
  59. /janito/{tools/adapters → plugins/tools}/local/get_file_outline/search_outline.py +0 -0
  60. /janito/{tools/adapters → plugins/tools}/local/search_text/__init__.py +0 -0
  61. /janito/{tools/adapters → plugins/tools}/local/search_text/match_lines.py +0 -0
  62. /janito/{tools/adapters → plugins/tools}/local/search_text/pattern_utils.py +0 -0
  63. /janito/{tools/adapters → plugins/tools}/local/search_text/traverse_directory.py +0 -0
  64. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/css_validator.py +0 -0
  65. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/html_validator.py +0 -0
  66. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/jinja2_validator.py +0 -0
  67. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/js_validator.py +0 -0
  68. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/json_validator.py +0 -0
  69. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/markdown_validator.py +0 -0
  70. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/ps1_validator.py +0 -0
  71. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/python_validator.py +0 -0
  72. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/xml_validator.py +0 -0
  73. /janito/{tools/adapters → plugins/tools}/local/validate_file_syntax/yaml_validator.py +0 -0
  74. {janito-3.8.0.dist-info → janito-3.10.0.dist-info}/WHEEL +0 -0
  75. {janito-3.8.0.dist-info → janito-3.10.0.dist-info}/entry_points.txt +0 -0
  76. {janito-3.8.0.dist-info → janito-3.10.0.dist-info}/licenses/LICENSE +0 -0
  77. {janito-3.8.0.dist-info → janito-3.10.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- from janito.tools.adapters.local.adapter import register_local_tool
1
+ from janito.plugins.tools.local.adapter import register_local_tool
2
2
 
3
3
  from janito.tools.tool_utils import display_path
4
4
  from janito.tools.tool_base import ToolBase, ToolPermissions
@@ -6,6 +6,7 @@ from janito.report_events import ReportAction
6
6
  from janito.i18n import tr
7
7
  import os
8
8
  from janito.tools.path_utils import expand_path
9
+ from pathlib import Path
9
10
 
10
11
 
11
12
  @register_local_tool
@@ -43,6 +44,8 @@ class CreateDirectoryTool(ToolBase):
43
44
  "❌ Path '{disp_path}' exists and is not a directory.",
44
45
  disp_path=disp_path,
45
46
  )
47
+ # Generate content summary
48
+ content_summary = self._get_directory_summary(path)
46
49
  self.report_error(
47
50
  tr(
48
51
  "❗ Directory '{disp_path}' already exists.",
@@ -50,8 +53,9 @@ class CreateDirectoryTool(ToolBase):
50
53
  )
51
54
  )
52
55
  return tr(
53
- "❗ Cannot create directory: '{disp_path}' already exists.",
56
+ "❗ Cannot create directory: '{disp_path}' already exists.\n{summary}",
54
57
  disp_path=disp_path,
58
+ summary=content_summary,
55
59
  )
56
60
  os.makedirs(path, exist_ok=True)
57
61
  self.report_success(tr("✅ Directory created"))
@@ -68,3 +72,42 @@ class CreateDirectoryTool(ToolBase):
68
72
  )
69
73
  )
70
74
  return tr("❌ Cannot create directory: {error}", error=e)
75
+
76
+ def _get_directory_summary(self, path: str) -> str:
77
+ """Generate a summary of directory contents."""
78
+ try:
79
+ path_obj = Path(path)
80
+ if not path_obj.exists() or not path_obj.is_dir():
81
+ return ""
82
+
83
+ items = list(path_obj.iterdir())
84
+ if not items:
85
+ return "Directory is empty."
86
+
87
+ # Count files and directories
88
+ file_count = sum(1 for item in items if item.is_file())
89
+ dir_count = sum(1 for item in items if item.is_dir())
90
+
91
+ summary_parts = []
92
+ if file_count > 0:
93
+ summary_parts.append(f"{file_count} file{'s' if file_count != 1 else ''}")
94
+ if dir_count > 0:
95
+ summary_parts.append(f"{dir_count} subdirector{'y' if dir_count == 1 else 'ies'}")
96
+
97
+ # Show first few items as examples
98
+ examples = []
99
+ for item in sorted(items)[:3]: # Show up to 3 items
100
+ if item.is_dir():
101
+ examples.append(f"📁 {item.name}")
102
+ else:
103
+ examples.append(f"📄 {item.name}")
104
+
105
+ result = f"Contains: {', '.join(summary_parts)}."
106
+ if examples:
107
+ result += f"\nExamples: {', '.join(examples)}"
108
+ if len(items) > 3:
109
+ result += f" (and {len(items) - 3} more)"
110
+
111
+ return result
112
+ except Exception:
113
+ return "Unable to read directory contents."
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from janito.tools.path_utils import expand_path
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
 
5
5
  from janito.tools.tool_utils import display_path
6
6
  from janito.tools.tool_base import ToolBase, ToolPermissions
@@ -8,7 +8,7 @@ from janito.report_events import ReportAction
8
8
  from janito.i18n import tr
9
9
  from janito.tools.loop_protection_decorator import protect_against_loops
10
10
 
11
- from janito.tools.adapters.local.validate_file_syntax.core import validate_file_syntax
11
+ from janito.plugins.tools.local.validate_file_syntax.core import validate_file_syntax
12
12
 
13
13
 
14
14
  @register_local_tool
@@ -30,12 +30,12 @@ class CreateFileTool(ToolBase):
30
30
  - Cross-platform path handling (Windows, macOS, Linux)
31
31
 
32
32
  Args:
33
- path (str): Target file path. Supports relative and absolute paths, with automatic
33
+ path (str, required): Target file path. Supports relative and absolute paths, with automatic
34
34
  expansion of user home directory (~) and environment variables.
35
35
  Examples: "src/main.py", "~/Documents/config.json", "$HOME/.env"
36
- content (str): File content to write. Empty string creates empty file.
36
+ content (str, optional): File content to write. Empty string creates empty file.
37
37
  Supports any text content including Unicode characters, newlines,
38
- and binary-safe text representation.
38
+ and binary-safe text representation. Default: "" (empty file)
39
39
  overwrite (bool, optional): If True, allows overwriting existing files. Default: False.
40
40
  When False, prevents accidental overwrites by checking
41
41
  file existence and showing current content. Always review
@@ -71,6 +71,10 @@ class CreateFileTool(ToolBase):
71
71
  ✅ Created file 2 lines.
72
72
  ✅ Syntax OK
73
73
 
74
+ Creating empty file:
75
+ >>> create_file("empty.txt", "")
76
+ ✅ Created file 0 lines.
77
+
74
78
  Overwrite protection:
75
79
  >>> create_file("existing.txt", "new content")
76
80
  ❗ Cannot create file: file already exists at 'existing.txt'.
@@ -85,7 +89,7 @@ class CreateFileTool(ToolBase):
85
89
  tool_name = "create_file"
86
90
 
87
91
  @protect_against_loops(max_calls=5, time_window=10.0, key_field="path")
88
- def run(self, path: str, content: str, overwrite: bool = False) -> str:
92
+ def run(self, path: str, content: str = "", overwrite: bool = False) -> str:
89
93
  path = expand_path(path)
90
94
  disp_path = display_path(path)
91
95
  if os.path.exists(path) and not overwrite:
@@ -1,9 +1,9 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
5
5
  import shutil
6
- from janito.tools.adapters.local.validate_file_syntax.core import validate_file_syntax
6
+ from janito.plugins.tools.local.validate_file_syntax.core import validate_file_syntax
7
7
 
8
8
 
9
9
  @register_local_tool
@@ -5,7 +5,7 @@ import json
5
5
  from pathlib import Path
6
6
  from bs4 import BeautifulSoup
7
7
  from typing import Dict, Any, Optional
8
- from janito.tools.adapters.local.adapter import register_local_tool
8
+ from janito.plugins.tools.local.adapter import register_local_tool
9
9
  from janito.tools.tool_base import ToolBase, ToolPermissions
10
10
  from janito.report_events import ReportAction
11
11
  from janito.i18n import tr
@@ -33,7 +33,7 @@ class FetchUrlTool(ToolBase):
33
33
 
34
34
  **Error Cache Behavior:**
35
35
  - HTTP 403 errors: Cached for 24 hours (more permanent)
36
- - HTTP 404 errors: Cached for 1 hour (temporary)
36
+ - HTTP 404 errors: Cached for 1 hour (shorter duration)
37
37
  - Other 4xx errors: Cached for 30 minutes
38
38
  - 5xx errors: Not cached (retried on each request)
39
39
 
@@ -151,7 +151,7 @@ class FetchUrlTool(ToolBase):
151
151
  # Cache 403 errors for 24 hours (more permanent)
152
152
  expiration_time = 24 * 3600
153
153
  elif entry["status_code"] == 404:
154
- # Cache 404 errors for 1 hour (more temporary)
154
+ # Cache 404 errors for 1 hour (shorter duration)
155
155
  expiration_time = 3600
156
156
  else:
157
157
  # Cache other 4xx errors for 30 minutes
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import pluralize, display_path
5
5
  from janito.dir_walk_utils import walk_dir_with_gitignore
6
6
  from janito.i18n import tr
@@ -1,4 +1,4 @@
1
- from janito.tools.adapters.local.adapter import register_local_tool
1
+ from janito.plugins.tools.local.adapter import register_local_tool
2
2
  from .python_outline import parse_python_outline
3
3
  from .markdown_outline import parse_markdown_outline
4
4
  from janito.formatting import OutlineFormatter
@@ -10,7 +10,7 @@ from janito.report_events import ReportAction
10
10
  from janito.tools.tool_utils import display_path, pluralize
11
11
  from janito.i18n import tr
12
12
 
13
- from janito.tools.adapters.local.adapter import register_local_tool as register_tool
13
+ from janito.plugins.tools.local.adapter import register_local_tool as register_tool
14
14
  from janito.tools.loop_protection_decorator import protect_against_loops
15
15
 
16
16
 
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from janito.tools.path_utils import expand_path
3
3
  import shutil
4
- from janito.tools.adapters.local.adapter import register_local_tool
4
+ from janito.plugins.tools.local.adapter import register_local_tool
5
5
  from janito.tools.tool_utils import display_path
6
6
  from janito.tools.tool_base import ToolBase, ToolPermissions
7
7
  from janito.report_events import ReportAction
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  import webbrowser
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_base import ToolBase, ToolPermissions
5
5
  from janito.report_events import ReportAction
6
6
  from janito.i18n import tr
@@ -1,5 +1,5 @@
1
1
  import webbrowser
2
- from janito.tools.adapters.local.adapter import register_local_tool
2
+ from janito.plugins.tools.local.adapter import register_local_tool
3
3
  from janito.tools.tool_base import ToolBase, ToolPermissions
4
4
  from janito.report_events import ReportAction
5
5
  from janito.i18n import tr
@@ -5,7 +5,7 @@ import tempfile
5
5
  import threading
6
6
  from janito.tools.tool_base import ToolBase, ToolPermissions
7
7
  from janito.report_events import ReportAction
8
- from janito.tools.adapters.local.adapter import register_local_tool
8
+ from janito.plugins.tools.local.adapter import register_local_tool
9
9
  from janito.i18n import tr
10
10
 
11
11
 
@@ -5,7 +5,7 @@ import tempfile
5
5
  import threading
6
6
  from janito.tools.tool_base import ToolBase, ToolPermissions
7
7
  from janito.report_events import ReportAction
8
- from janito.tools.adapters.local.adapter import register_local_tool
8
+ from janito.plugins.tools.local.adapter import register_local_tool
9
9
  from janito.i18n import tr
10
10
 
11
11
 
@@ -5,7 +5,7 @@ import tempfile
5
5
  import threading
6
6
  from janito.tools.tool_base import ToolBase, ToolPermissions
7
7
  from janito.report_events import ReportAction
8
- from janito.tools.adapters.local.adapter import register_local_tool
8
+ from janito.plugins.tools.local.adapter import register_local_tool
9
9
  from janito.i18n import tr
10
10
 
11
11
 
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import display_path
5
5
  from janito.i18n import tr
6
6
  import json
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import pluralize
5
5
  from janito.i18n import tr
6
6
  from janito.tools.loop_protection_decorator import protect_against_loops
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import pluralize, display_path
5
5
  from janito.i18n import tr
6
6
  import shutil
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from janito.tools.path_utils import expand_path
3
3
  import shutil
4
- from janito.tools.adapters.local.adapter import register_local_tool
4
+ from janito.plugins.tools.local.adapter import register_local_tool
5
5
 
6
6
  from janito.tools.tool_utils import display_path
7
7
  from janito.tools.tool_base import ToolBase, ToolPermissions
@@ -1,10 +1,10 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
5
5
  import shutil
6
6
  import re
7
- from janito.tools.adapters.local.validate_file_syntax.core import validate_file_syntax
7
+ from janito.plugins.tools.local.validate_file_syntax.core import validate_file_syntax
8
8
 
9
9
 
10
10
  @register_local_tool
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
5
5
  import subprocess
6
6
  import tempfile
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
5
5
  import subprocess
6
6
  import os
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import pluralize, display_path
5
5
  from janito.i18n import tr
6
6
  import os
@@ -11,7 +11,7 @@ from .traverse_directory import traverse_directory
11
11
  from janito.tools.loop_protection_decorator import protect_against_loops
12
12
 
13
13
 
14
- from janito.tools.adapters.local.adapter import register_local_tool as register_tool
14
+ from janito.plugins.tools.local.adapter import register_local_tool as register_tool
15
15
 
16
16
 
17
17
  @register_tool
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
5
5
  from janito.tools.loop_protection_decorator import protect_against_loops
6
6
 
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
5
5
  from janito.tools.loop_protection_decorator import protect_against_loops
6
6
  from typing import Sequence
@@ -0,0 +1 @@
1
+ # Validation syntax package
@@ -0,0 +1,119 @@
1
+ import os
2
+ from janito.tools.path_utils import expand_path
3
+ from janito.i18n import tr
4
+ from janito.tools.tool_base import ToolBase, ToolPermissions
5
+ from janito.report_events import ReportAction
6
+ from janito.plugins.tools.local.adapter import register_local_tool
7
+ from janito.tools.tool_utils import display_path
8
+ from janito.plugins.tools.local.adapter import register_local_tool as register_tool
9
+
10
+ from .python_validator import validate_python
11
+ from .json_validator import validate_json
12
+ from .yaml_validator import validate_yaml
13
+ from .ps1_validator import validate_ps1
14
+ from .xml_validator import validate_xml
15
+ from .html_validator import validate_html
16
+ from .markdown_validator import validate_markdown
17
+ from .js_validator import validate_js
18
+ from .css_validator import validate_css
19
+ from .jinja2_validator import validate_jinja2
20
+ from .txt_validator import validate_txt
21
+ from janito.tools.loop_protection_decorator import protect_against_loops
22
+
23
+
24
+ def _get_validator(ext):
25
+ """Return the appropriate validator function for the file extension."""
26
+ mapping = {
27
+ ".py": validate_python,
28
+ ".pyw": validate_python,
29
+ ".json": validate_json,
30
+ ".yml": validate_yaml,
31
+ ".yaml": validate_yaml,
32
+ ".ps1": validate_ps1,
33
+ ".xml": validate_xml,
34
+ ".html": validate_html,
35
+ ".htm": validate_html,
36
+ ".md": validate_markdown,
37
+ ".js": validate_js,
38
+ ".css": validate_css,
39
+ ".j2": validate_jinja2,
40
+ ".jinja2": validate_jinja2,
41
+ ".txt": validate_txt,
42
+ ".text": validate_txt,
43
+ }
44
+ return mapping.get(ext)
45
+
46
+
47
+ def _handle_validation_error(e, report_warning):
48
+ msg = tr("⚠️ Warning: Syntax error: {error}", error=e)
49
+ if report_warning:
50
+ report_warning(msg)
51
+ return msg
52
+
53
+
54
+ def validate_file_syntax(
55
+ path: str, report_info=None, report_warning=None, report_success=None
56
+ ) -> str:
57
+ ext = os.path.splitext(path)[1].lower()
58
+ validator = _get_validator(ext)
59
+ try:
60
+ if validator:
61
+ return validator(path)
62
+ else:
63
+ msg = tr("⚠️ Warning: Unsupported file extension: {ext}", ext=ext)
64
+ if report_warning:
65
+ report_warning(msg)
66
+ return msg
67
+ except Exception as e:
68
+ return _handle_validation_error(e, report_warning)
69
+
70
+
71
+ class ValidateFileSyntaxTool(ToolBase):
72
+ """
73
+ Validate a file for syntax issues.
74
+
75
+ Supported types:
76
+ - Python (.py, .pyw)
77
+ - JSON (.json)
78
+ - YAML (.yml, .yaml)
79
+ - PowerShell (.ps1)
80
+ - XML (.xml)
81
+ - HTML (.html, .htm) [lxml]
82
+ - Markdown (.md)
83
+ - JavaScript (.js)
84
+ - Jinja2 templates (.j2, .jinja2)
85
+ - Text files (.txt, .text) [UTF-8 validation]
86
+
87
+ Args:
88
+ path (str): Path to the file to validate.
89
+ Returns:
90
+ str: Validation status message. Example:
91
+ - "✅ Syntax OK"
92
+ - "⚠️ Warning: Syntax error: <error message>"
93
+ - "⚠️ Warning: UTF-8 decoding error: <error details>"
94
+ - "⚠️ Warning: Unsupported file extension: <ext>"
95
+ """
96
+
97
+ permissions = ToolPermissions(read=True)
98
+ tool_name = "validate_file_syntax"
99
+
100
+ @protect_against_loops(max_calls=5, time_window=10.0, key_field="path")
101
+ def run(self, path: str) -> str:
102
+ path = expand_path(path)
103
+ disp_path = display_path(path)
104
+ self.report_action(
105
+ tr(
106
+ "🔎 Validate syntax for file '{disp_path}' ...",
107
+ disp_path=disp_path,
108
+ ),
109
+ ReportAction.READ,
110
+ )
111
+ result = validate_file_syntax(
112
+ path,
113
+ report_warning=self.report_warning,
114
+ report_success=self.report_success,
115
+ )
116
+ if result.startswith("✅"):
117
+ self.report_success(result, ReportAction.READ)
118
+
119
+ return result
@@ -0,0 +1,28 @@
1
+ """Text file validator for UTF-8 encoding validation."""
2
+
3
+ import codecs
4
+ from pathlib import Path
5
+
6
+
7
+ def validate_txt(path: str) -> str:
8
+ """
9
+ Validate a text file for UTF-8 encoding issues.
10
+
11
+ Args:
12
+ path (str): Path to the text file to validate
13
+
14
+ Returns:
15
+ str: Validation status message
16
+ - "✅ Syntax OK" if file is valid UTF-8
17
+ - "⚠️ Warning: UTF-8 decoding error: <error details>" if invalid
18
+ """
19
+ try:
20
+ # Try to read the file with UTF-8 encoding
21
+ with codecs.open(path, 'r', encoding='utf-8') as f:
22
+ # Read the entire file to trigger any decoding errors
23
+ f.read()
24
+ return "✅ Syntax OK"
25
+ except UnicodeDecodeError as e:
26
+ return f"⚠️ Warning: UTF-8 decoding error: {e}"
27
+ except Exception as e:
28
+ return f"⚠️ Warning: File read error: {e}"
@@ -1,6 +1,6 @@
1
1
  from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
- from janito.tools.adapters.local.adapter import register_local_tool
3
+ from janito.plugins.tools.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import pluralize
5
5
  from janito.i18n import tr
6
6
  from janito.tools.loop_protection_decorator import protect_against_loops
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ """Test script to verify tool adapter converts argument names to lowercase."""
3
+
4
+ import tempfile
5
+ import os
6
+ import subprocess
7
+ import sys
8
+ from pathlib import Path
9
+ import json
10
+
11
+
12
+ def test_tool_adapter_lowercase_conversion():
13
+ """Test that tool adapter converts argument names to lowercase."""
14
+ print("Testing tool adapter lowercase conversion...")
15
+
16
+ # Create a simple test tool that logs its arguments
17
+ test_tool_content = '''
18
+ from janito.plugins.tools.local.adapter import register_local_tool
19
+ from janito.tools.tool_base import ToolBase, ToolPermissions
20
+
21
+ class TestArgsTool(ToolBase):
22
+ tool_name = "test_args_tool"
23
+ description = "Test tool to verify argument case conversion"
24
+ permissions = ToolPermissions(read=True, write=False, execute=False)
25
+
26
+ def execute(self, test_path: str, test_mode: str = "default") -> str:
27
+ """Test tool that returns its arguments."""
28
+ return f"Received: test_path={test_path}, test_mode={test_mode}"
29
+
30
+ register_local_tool(TestArgsTool)
31
+ '''
32
+
33
+ # Create a temporary Python file with the test tool
34
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
35
+ f.write(test_tool_content)
36
+ test_tool_file = f.name
37
+
38
+ try:
39
+ # Test with mixed case arguments
40
+ print("\n1. Testing mixed case argument names...")
41
+
42
+ # Create a simple test script that uses the tool adapter directly
43
+ test_script = f'''
44
+ import sys
45
+ import os
46
+ sys.path.insert(0, os.path.join(os.getcwd(), "janito"))
47
+
48
+ # Import the test tool to register it
49
+ exec(open("{test_tool_file}").read())
50
+
51
+ from janito.plugins.tools.local.adapter import LocalToolsAdapter
52
+ from janito.llm.message_parts import FunctionCallMessagePart
53
+ import json
54
+
55
+ # Create a mock function object with mixed case arguments
56
+ class MockFunction:
57
+ def __init__(self, name, arguments):
58
+ self.name = name
59
+ self.arguments = arguments
60
+
61
+ # Create adapter
62
+ adapter = LocalToolsAdapter()
63
+
64
+ # Test with mixed case arguments
65
+ mixed_case_args = {{"Test_Path": "/tmp/test", "Test_Mode": "verify"}}
66
+ function = MockFunction("test_args_tool", json.dumps(mixed_case_args))
67
+ message_part = FunctionCallMessagePart(tool_call_id="test_123", function=function)
68
+
69
+ # Execute and print result
70
+ result = adapter.execute_function_call_message_part(message_part)
71
+ print(f"Result: {{result}}")
72
+ '''
73
+
74
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
75
+ f.write(test_script)
76
+ test_script_file = f.name
77
+
78
+ try:
79
+ # Run the test script
80
+ result = subprocess.run(
81
+ [sys.executable, test_script_file],
82
+ capture_output=True,
83
+ text=True,
84
+ cwd="/home/janito/janito"
85
+ )
86
+
87
+ print(f"Script output: {result.stdout}")
88
+ print(f"Script stderr: {result.stderr}")
89
+
90
+ # Check if the tool was executed successfully
91
+ if result.returncode == 0 and "Received: test_path=/tmp/test, test_mode=verify" in result.stdout:
92
+ print("✓ Mixed case arguments were successfully converted to lowercase")
93
+ return True
94
+ else:
95
+ print("✗ Tool execution failed or arguments were not converted properly")
96
+ return False
97
+
98
+ finally:
99
+ os.unlink(test_script_file)
100
+
101
+ finally:
102
+ os.unlink(test_tool_file)
103
+
104
+
105
+ if __name__ == "__main__":
106
+ success = test_tool_adapter_lowercase_conversion()
107
+ if success:
108
+ print("\n🎉 Test passed!")
109
+ sys.exit(0)
110
+ else:
111
+ print("\n❌ Test failed!")
112
+ sys.exit(1)
janito/tools/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- from janito.tools.adapters.local import (
1
+ from janito.plugins.tools.local import (
2
2
  local_tools_adapter as _internal_local_tools_adapter,
3
3
  LocalToolsAdapter,
4
4
  )
@@ -11,7 +11,7 @@ def get_local_tools_adapter(workdir=None, allowed_permissions=None):
11
11
  if workdir is not None and not os.path.exists(workdir):
12
12
  os.makedirs(workdir, exist_ok=True)
13
13
  # Permissions are now managed globally; ignore allowed_permissions argument except for backward compatibility
14
- # Reuse the singleton adapter defined in janito.tools.adapters.local to maintain tool registrations
14
+ # Reuse the singleton adapter defined in janito.plugins.tools.local to maintain tool registrations
15
15
  registry = _internal_local_tools_adapter
16
16
  # Change workdir if requested
17
17
  if workdir is not None:
@@ -1,6 +1,6 @@
1
1
  def check_tools_registry():
2
2
  # Import and use the singleton tools adapter instance
3
- from janito.tools.adapters.local import local_tools_adapter
3
+ from janito.plugins.tools.local import local_tools_adapter
4
4
 
5
5
  print("Available tool names:", local_tools_adapter.list_tools())
6
6
  print(