janito 2.3.0__py3-none-any.whl → 2.4.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 (150) hide show
  1. janito/__init__.py +6 -6
  2. janito/_version.py +57 -0
  3. janito/agent/setup_agent.py +92 -18
  4. janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
  5. janito/cli/chat_mode/bindings.py +21 -2
  6. janito/cli/chat_mode/chat_entry.py +2 -3
  7. janito/cli/chat_mode/prompt_style.py +5 -0
  8. janito/cli/chat_mode/session.py +80 -94
  9. janito/cli/chat_mode/session_profile_select.py +80 -0
  10. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  11. janito/cli/chat_mode/shell/commands/__init__.py +13 -7
  12. janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
  13. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  14. janito/cli/chat_mode/shell/commands/conversation_restart.py +30 -0
  15. janito/cli/chat_mode/shell/commands/execute.py +42 -0
  16. janito/cli/chat_mode/shell/commands/help.py +6 -3
  17. janito/cli/chat_mode/shell/commands/model.py +28 -0
  18. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  19. janito/cli/chat_mode/shell/commands/read.py +37 -0
  20. janito/cli/chat_mode/shell/commands/tools.py +45 -18
  21. janito/cli/chat_mode/shell/commands/write.py +37 -0
  22. janito/cli/chat_mode/shell/commands.bak.zip +0 -0
  23. janito/cli/chat_mode/shell/input_history.py +62 -62
  24. janito/cli/chat_mode/shell/session.bak.zip +0 -0
  25. janito/cli/chat_mode/toolbar.py +44 -27
  26. janito/cli/cli_commands/list_models.py +35 -35
  27. janito/cli/cli_commands/list_providers.py +9 -9
  28. janito/cli/cli_commands/list_tools.py +86 -53
  29. janito/cli/cli_commands/model_selection.py +50 -50
  30. janito/cli/cli_commands/set_api_key.py +19 -19
  31. janito/cli/cli_commands/show_config.py +51 -51
  32. janito/cli/cli_commands/show_system_prompt.py +105 -62
  33. janito/cli/config.py +5 -6
  34. janito/cli/core/__init__.py +4 -4
  35. janito/cli/core/event_logger.py +59 -59
  36. janito/cli/core/runner.py +25 -18
  37. janito/cli/core/setters.py +10 -1
  38. janito/cli/core/unsetters.py +54 -54
  39. janito/cli/main_cli.py +28 -5
  40. janito/cli/prompt_core.py +18 -2
  41. janito/cli/prompt_setup.py +56 -0
  42. janito/cli/single_shot_mode/__init__.py +6 -6
  43. janito/cli/single_shot_mode/handler.py +14 -73
  44. janito/cli/verbose_output.py +1 -1
  45. janito/config.py +5 -5
  46. janito/config_manager.py +13 -0
  47. janito/drivers/anthropic/driver.py +113 -113
  48. janito/drivers/dashscope.bak.zip +0 -0
  49. janito/drivers/openai/README.md +20 -0
  50. janito/drivers/openai_responses.bak.zip +0 -0
  51. janito/event_bus/event.py +2 -2
  52. janito/formatting_token.py +54 -54
  53. janito/i18n/__init__.py +35 -35
  54. janito/i18n/messages.py +23 -23
  55. janito/i18n/pt.py +46 -47
  56. janito/llm/README.md +23 -0
  57. janito/llm/__init__.py +5 -5
  58. janito/llm/agent.py +507 -443
  59. janito/llm/driver.py +8 -0
  60. janito/llm/driver_config_builder.py +34 -34
  61. janito/llm/driver_input.py +12 -12
  62. janito/llm/message_parts.py +60 -60
  63. janito/llm/model.py +38 -38
  64. janito/llm/provider.py +196 -196
  65. janito/provider_registry.py +8 -6
  66. janito/providers/anthropic/model_info.py +22 -22
  67. janito/providers/anthropic/provider.py +2 -0
  68. janito/providers/azure_openai/provider.py +3 -0
  69. janito/providers/dashscope.bak.zip +0 -0
  70. janito/providers/deepseek/__init__.py +1 -1
  71. janito/providers/deepseek/model_info.py +16 -16
  72. janito/providers/deepseek/provider.py +94 -91
  73. janito/providers/google/provider.py +3 -0
  74. janito/providers/mistralai/provider.py +3 -0
  75. janito/providers/openai/provider.py +4 -0
  76. janito/providers/registry.py +26 -26
  77. janito/shell.bak.zip +0 -0
  78. janito/tools/DOCSTRING_STANDARD.txt +33 -0
  79. janito/tools/README.md +3 -0
  80. janito/tools/__init__.py +20 -6
  81. janito/tools/adapters/__init__.py +1 -1
  82. janito/tools/adapters/local/__init__.py +65 -62
  83. janito/tools/adapters/local/adapter.py +18 -35
  84. janito/tools/adapters/local/ask_user.py +101 -102
  85. janito/tools/adapters/local/copy_file.py +84 -84
  86. janito/tools/adapters/local/create_directory.py +69 -69
  87. janito/tools/adapters/local/create_file.py +82 -82
  88. janito/tools/adapters/local/delete_text_in_file.py +2 -2
  89. janito/tools/adapters/local/fetch_url.py +97 -97
  90. janito/tools/adapters/local/find_files.py +139 -138
  91. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  92. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  93. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  94. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  95. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  96. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  97. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  98. janito/tools/adapters/local/move_file.py +2 -2
  99. janito/tools/adapters/local/open_html_in_browser.py +2 -1
  100. janito/tools/adapters/local/open_url.py +2 -2
  101. janito/tools/adapters/local/python_code_run.py +166 -166
  102. janito/tools/adapters/local/python_command_run.py +164 -164
  103. janito/tools/adapters/local/python_file_run.py +163 -163
  104. janito/tools/adapters/local/remove_directory.py +2 -2
  105. janito/tools/adapters/local/remove_file.py +2 -2
  106. janito/tools/adapters/local/replace_text_in_file.py +2 -2
  107. janito/tools/adapters/local/run_bash_command.py +176 -176
  108. janito/tools/adapters/local/run_powershell_command.py +219 -219
  109. janito/tools/adapters/local/search_text/__init__.py +1 -1
  110. janito/tools/adapters/local/search_text/core.py +201 -201
  111. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  112. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  113. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  114. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  115. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  116. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  117. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  118. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  119. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  120. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  121. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  122. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  123. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  124. janito/tools/adapters/local/view_file.py +168 -167
  125. janito/tools/inspect_registry.py +17 -17
  126. janito/tools/outline_file.bak.zip +0 -0
  127. janito/tools/permissions.py +45 -0
  128. janito/tools/permissions_parse.py +12 -0
  129. janito/tools/tool_base.py +118 -105
  130. janito/tools/tool_events.py +58 -58
  131. janito/tools/tool_run_exception.py +12 -12
  132. janito/tools/tool_use_tracker.py +81 -81
  133. janito/tools/tool_utils.py +43 -45
  134. janito/tools/tools_adapter.py +25 -20
  135. janito/tools/tools_schema.py +104 -104
  136. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/METADATA +425 -388
  137. janito-2.4.0.dist-info/RECORD +195 -0
  138. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
  139. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
  140. janito/cli/chat_mode/shell/commands/edit.py +0 -25
  141. janito/cli/chat_mode/shell/commands/exec.py +0 -27
  142. janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
  143. janito/cli/termweb_starter.py +0 -122
  144. janito/termweb/app.py +0 -95
  145. janito/version.py +0 -4
  146. janito-2.3.0.dist-info/RECORD +0 -181
  147. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/WHEEL +0 -0
  148. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
  149. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
  150. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/top_level.txt +0 -0
@@ -1,156 +1,156 @@
1
- import re
2
- from typing import List
3
-
4
-
5
- def extract_signature_and_decorators(lines, start_idx):
6
- """
7
- Extracts the signature line and leading decorators for a given function/class/method.
8
- Returns (signature:str, decorators:List[str], signature_lineno:int)
9
- """
10
- decorators = []
11
- sig_line = None
12
- sig_lineno = start_idx
13
- for i in range(start_idx - 1, -1, -1):
14
- striped = lines[i].strip()
15
- if striped.startswith("@"):
16
- decorators.insert(0, striped)
17
- sig_lineno = i
18
- elif not striped:
19
- continue
20
- else:
21
- break
22
- # Find the signature line itself
23
- for k in range(start_idx, len(lines)):
24
- striped = lines[k].strip()
25
- if striped.startswith("def ") or striped.startswith("class "):
26
- sig_line = striped
27
- sig_lineno = k
28
- break
29
- return sig_line, decorators, sig_lineno
30
-
31
-
32
- def extract_docstring(lines, start_idx, end_idx):
33
- """Extracts a docstring from lines[start_idx:end_idx] if present."""
34
- for i in range(start_idx, min(end_idx, len(lines))):
35
- line = lines[i].lstrip()
36
- if not line:
37
- continue
38
- if line.startswith('"""') or line.startswith("'''"):
39
- quote = line[:3]
40
- doc = line[3:]
41
- if doc.strip().endswith(quote):
42
- return doc.strip()[:-3].strip()
43
- docstring_lines = [doc]
44
- for j in range(i + 1, min(end_idx, len(lines))):
45
- line = lines[j]
46
- if line.strip().endswith(quote):
47
- docstring_lines.append(line.strip()[:-3])
48
- return "\n".join([d.strip() for d in docstring_lines]).strip()
49
- docstring_lines.append(line)
50
- break
51
- else:
52
- break
53
- return ""
54
-
55
-
56
- def build_outline_entry(obj, lines, outline):
57
- obj_type, name, start, end, parent, indent = obj
58
- # Determine if this is a method
59
- if obj_type == "function" and parent:
60
- outline_type = "method"
61
- elif obj_type == "function":
62
- outline_type = "function"
63
- else:
64
- outline_type = obj_type
65
- docstring = extract_docstring(lines, start, end)
66
- signature, decorators, signature_lineno = extract_signature_and_decorators(
67
- lines, start - 1
68
- )
69
- outline.append(
70
- {
71
- "type": outline_type,
72
- "name": name,
73
- "start": start,
74
- "end": end,
75
- "parent": parent,
76
- "signature": signature,
77
- "decorators": decorators,
78
- "docstring": docstring,
79
- }
80
- )
81
-
82
-
83
- def parse_python_outline_v2(lines: List[str]):
84
- class_pat = re.compile(r"^(\s*)class\s+(\w+)")
85
- func_pat = re.compile(r"^(\s*)def\s+(\w+)")
86
- assign_pat = re.compile(r"^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=.*")
87
- main_pat = re.compile(r"^\s*if\s+__name__\s*==\s*[\'\"]__main__[\'\"]\s*:")
88
- outline = []
89
- stack = []
90
- obj_ranges = []
91
- last_top_obj = None
92
- for idx, line in enumerate(lines):
93
- class_match = class_pat.match(line)
94
- func_match = func_pat.match(line)
95
- assign_match = assign_pat.match(line)
96
- indent = len(line) - len(line.lstrip())
97
- parent = ""
98
- for s in reversed(stack):
99
- if s[0] == "class" and indent > s[2]:
100
- parent = s[1]
101
- break
102
- if class_match:
103
- obj = ("class", class_match.group(2), idx + 1, None, parent, indent)
104
- stack.append(obj)
105
- last_top_obj = obj
106
- elif func_match:
107
- obj = ("function", func_match.group(2), idx + 1, None, parent, indent)
108
- stack.append(obj)
109
- last_top_obj = obj
110
- elif assign_match and indent == 0:
111
- outline.append(
112
- {
113
- "type": "const" if assign_match.group(2).isupper() else "var",
114
- "name": assign_match.group(2),
115
- "start": idx + 1,
116
- "end": idx + 1,
117
- "parent": "",
118
- "signature": line.strip(),
119
- "decorators": [],
120
- "docstring": "",
121
- }
122
- )
123
- if line.strip().startswith("if __name__ == "):
124
- outline.append(
125
- {
126
- "type": "main",
127
- "name": "__main__",
128
- "start": idx + 1,
129
- "end": idx + 1,
130
- "parent": "",
131
- "signature": line.strip(),
132
- "decorators": [],
133
- "docstring": "",
134
- }
135
- )
136
- # Close stack objects if indent falls back
137
- while stack and indent <= stack[-1][5] and idx + 1 > stack[-1][2]:
138
- finished = stack.pop()
139
- outline_entry = finished[:2] + (
140
- finished[2],
141
- idx + 1,
142
- finished[4],
143
- finished[5],
144
- )
145
- build_outline_entry(outline_entry, lines, outline)
146
- # Close any remaining objects
147
- while stack:
148
- finished = stack.pop()
149
- outline_entry = finished[:2] + (
150
- finished[2],
151
- len(lines),
152
- finished[4],
153
- finished[5],
154
- )
155
- build_outline_entry(outline_entry, lines, outline)
156
- return outline
1
+ import re
2
+ from typing import List
3
+
4
+
5
+ def extract_signature_and_decorators(lines, start_idx):
6
+ """
7
+ Extracts the signature line and leading decorators for a given function/class/method.
8
+ Returns (signature:str, decorators:List[str], signature_lineno:int)
9
+ """
10
+ decorators = []
11
+ sig_line = None
12
+ sig_lineno = start_idx
13
+ for i in range(start_idx - 1, -1, -1):
14
+ striped = lines[i].strip()
15
+ if striped.startswith("@"):
16
+ decorators.insert(0, striped)
17
+ sig_lineno = i
18
+ elif not striped:
19
+ continue
20
+ else:
21
+ break
22
+ # Find the signature line itself
23
+ for k in range(start_idx, len(lines)):
24
+ striped = lines[k].strip()
25
+ if striped.startswith("def ") or striped.startswith("class "):
26
+ sig_line = striped
27
+ sig_lineno = k
28
+ break
29
+ return sig_line, decorators, sig_lineno
30
+
31
+
32
+ def extract_docstring(lines, start_idx, end_idx):
33
+ """Extracts a docstring from lines[start_idx:end_idx] if present."""
34
+ for i in range(start_idx, min(end_idx, len(lines))):
35
+ line = lines[i].lstrip()
36
+ if not line:
37
+ continue
38
+ if line.startswith('"""') or line.startswith("'''"):
39
+ quote = line[:3]
40
+ doc = line[3:]
41
+ if doc.strip().endswith(quote):
42
+ return doc.strip()[:-3].strip()
43
+ docstring_lines = [doc]
44
+ for j in range(i + 1, min(end_idx, len(lines))):
45
+ line = lines[j]
46
+ if line.strip().endswith(quote):
47
+ docstring_lines.append(line.strip()[:-3])
48
+ return "\n".join([d.strip() for d in docstring_lines]).strip()
49
+ docstring_lines.append(line)
50
+ break
51
+ else:
52
+ break
53
+ return ""
54
+
55
+
56
+ def build_outline_entry(obj, lines, outline):
57
+ obj_type, name, start, end, parent, indent = obj
58
+ # Determine if this is a method
59
+ if obj_type == "function" and parent:
60
+ outline_type = "method"
61
+ elif obj_type == "function":
62
+ outline_type = "function"
63
+ else:
64
+ outline_type = obj_type
65
+ docstring = extract_docstring(lines, start, end)
66
+ signature, decorators, signature_lineno = extract_signature_and_decorators(
67
+ lines, start - 1
68
+ )
69
+ outline.append(
70
+ {
71
+ "type": outline_type,
72
+ "name": name,
73
+ "start": start,
74
+ "end": end,
75
+ "parent": parent,
76
+ "signature": signature,
77
+ "decorators": decorators,
78
+ "docstring": docstring,
79
+ }
80
+ )
81
+
82
+
83
+ def parse_python_outline_v2(lines: List[str]):
84
+ class_pat = re.compile(r"^(\s*)class\s+(\w+)")
85
+ func_pat = re.compile(r"^(\s*)def\s+(\w+)")
86
+ assign_pat = re.compile(r"^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=.*")
87
+ main_pat = re.compile(r"^\s*if\s+__name__\s*==\s*[\'\"]__main__[\'\"]\s*:")
88
+ outline = []
89
+ stack = []
90
+ obj_ranges = []
91
+ last_top_obj = None
92
+ for idx, line in enumerate(lines):
93
+ class_match = class_pat.match(line)
94
+ func_match = func_pat.match(line)
95
+ assign_match = assign_pat.match(line)
96
+ indent = len(line) - len(line.lstrip())
97
+ parent = ""
98
+ for s in reversed(stack):
99
+ if s[0] == "class" and indent > s[2]:
100
+ parent = s[1]
101
+ break
102
+ if class_match:
103
+ obj = ("class", class_match.group(2), idx + 1, None, parent, indent)
104
+ stack.append(obj)
105
+ last_top_obj = obj
106
+ elif func_match:
107
+ obj = ("function", func_match.group(2), idx + 1, None, parent, indent)
108
+ stack.append(obj)
109
+ last_top_obj = obj
110
+ elif assign_match and indent == 0:
111
+ outline.append(
112
+ {
113
+ "type": "const" if assign_match.group(2).isupper() else "var",
114
+ "name": assign_match.group(2),
115
+ "start": idx + 1,
116
+ "end": idx + 1,
117
+ "parent": "",
118
+ "signature": line.strip(),
119
+ "decorators": [],
120
+ "docstring": "",
121
+ }
122
+ )
123
+ if line.strip().startswith("if __name__ == "):
124
+ outline.append(
125
+ {
126
+ "type": "main",
127
+ "name": "__main__",
128
+ "start": idx + 1,
129
+ "end": idx + 1,
130
+ "parent": "",
131
+ "signature": line.strip(),
132
+ "decorators": [],
133
+ "docstring": "",
134
+ }
135
+ )
136
+ # Close stack objects if indent falls back
137
+ while stack and indent <= stack[-1][5] and idx + 1 > stack[-1][2]:
138
+ finished = stack.pop()
139
+ outline_entry = finished[:2] + (
140
+ finished[2],
141
+ idx + 1,
142
+ finished[4],
143
+ finished[5],
144
+ )
145
+ build_outline_entry(outline_entry, lines, outline)
146
+ # Close any remaining objects
147
+ while stack:
148
+ finished = stack.pop()
149
+ outline_entry = finished[:2] + (
150
+ finished[2],
151
+ len(lines),
152
+ finished[4],
153
+ finished[5],
154
+ )
155
+ build_outline_entry(outline_entry, lines, outline)
156
+ return outline
@@ -1,33 +1,33 @@
1
- from janito.tools.tool_base import ToolBase
2
- from janito.report_events import ReportAction
3
-
4
-
5
- class SearchOutlineTool(ToolBase):
6
- """
7
- Tool for searching outlines in files.
8
-
9
- Args:
10
- file_path (str): Path to the file for which to generate an outline.
11
- Returns:
12
- str: Outline search result or status message.
13
- """
14
-
15
- tool_name = "search_outline"
16
-
17
- def run(self, file_path: str) -> str:
18
- from janito.tools.tool_utils import display_path
19
- from janito.i18n import tr
20
-
21
- self.report_action(
22
- tr(
23
- "🔍 Searching for outline in '{disp_path}'",
24
- disp_path=display_path(file_path),
25
- ),
26
- ReportAction.READ,
27
- )
28
- # ... rest of implementation ...
29
- # Example warnings and successes:
30
- # self.report_warning(tr("No files found with supported extensions."))
31
- # self.report_warning(tr("Error reading {file_path}: {error}", file_path=file_path, error=e))
32
- # self.report_success(tr("✅ {count} {match_word} found", count=len(output), match_word=pluralize('match', len(output))))
33
- pass
1
+ from janito.tools.tool_base import ToolBase, ToolPermissions
2
+ from janito.report_events import ReportAction
3
+
4
+
5
+ class SearchOutlineTool(ToolBase):
6
+ """
7
+ Tool for searching outlines in files.
8
+
9
+ Args:
10
+ file_path (str): Path to the file for which to generate an outline.
11
+ Returns:
12
+ str: Outline search result or status message.
13
+ """
14
+ permissions = ToolPermissions(read=True)
15
+ tool_name = "search_outline"
16
+
17
+ def run(self, file_path: str) -> str:
18
+ from janito.tools.tool_utils import display_path
19
+ from janito.i18n import tr
20
+
21
+ self.report_action(
22
+ tr(
23
+ "🔍 Searching for outline in '{disp_path}'",
24
+ disp_path=display_path(file_path),
25
+ ),
26
+ ReportAction.READ,
27
+ )
28
+ # ... rest of implementation ...
29
+ # Example warnings and successes:
30
+ # self.report_warning(tr("No files found with supported extensions."))
31
+ # self.report_warning(tr("Error reading {file_path}: {error}", file_path=file_path, error=e))
32
+ # self.report_success(tr("✅ {count} {match_word} found", count=len(output), match_word=pluralize('match', len(output))))
33
+ pass
@@ -2,7 +2,7 @@ import os
2
2
  import shutil
3
3
  from janito.tools.adapters.local.adapter import register_local_tool
4
4
  from janito.tools.tool_utils import display_path
5
- from janito.tools.tool_base import ToolBase
5
+ from janito.tools.tool_base import ToolBase, ToolPermissions
6
6
  from janito.report_events import ReportAction
7
7
  from janito.i18n import tr
8
8
 
@@ -20,7 +20,7 @@ class MoveFileTool(ToolBase):
20
20
  Returns:
21
21
  str: Status message indicating the result.
22
22
  """
23
-
23
+ permissions = ToolPermissions(read=True, write=True)
24
24
  tool_name = "move_file"
25
25
 
26
26
  def run(
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import webbrowser
3
3
  from janito.tools.adapters.local.adapter import register_local_tool
4
- from janito.tools.tool_base import ToolBase
4
+ from janito.tools.tool_base import ToolBase, ToolPermissions
5
5
  from janito.report_events import ReportAction
6
6
  from janito.i18n import tr
7
7
 
@@ -15,6 +15,7 @@ class OpenHtmlInBrowserTool(ToolBase):
15
15
  Returns:
16
16
  str: Status message indicating the result.
17
17
  """
18
+ permissions = ToolPermissions(read=True)
18
19
  tool_name = "open_html_in_browser"
19
20
 
20
21
  def run(self, file_path: str) -> str:
@@ -1,6 +1,6 @@
1
1
  import webbrowser
2
2
  from janito.tools.adapters.local.adapter import register_local_tool
3
- from janito.tools.tool_base import ToolBase
3
+ from janito.tools.tool_base import ToolBase, ToolPermissions
4
4
  from janito.report_events import ReportAction
5
5
  from janito.i18n import tr
6
6
 
@@ -15,7 +15,7 @@ class OpenUrlTool(ToolBase):
15
15
  Returns:
16
16
  str: Status message indicating the result.
17
17
  """
18
-
18
+ permissions = ToolPermissions(read=True)
19
19
  tool_name = "open_url"
20
20
 
21
21
  def run(self, url: str) -> str: