janito 2.1.1__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 (137) 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 -2
  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 +3 -1
  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 +27 -6
  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 +29 -5
  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 +44 -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/openai/model_info.py +0 -11
  71. janito/providers/openai/provider.py +1 -1
  72. janito/providers/provider_static_info.py +2 -3
  73. janito/providers/registry.py +26 -26
  74. janito/tools/adapters/__init__.py +1 -1
  75. janito/tools/adapters/local/__init__.py +62 -62
  76. janito/tools/adapters/local/adapter.py +33 -11
  77. janito/tools/adapters/local/ask_user.py +102 -102
  78. janito/tools/adapters/local/copy_file.py +84 -84
  79. janito/tools/adapters/local/create_directory.py +69 -69
  80. janito/tools/adapters/local/create_file.py +82 -82
  81. janito/tools/adapters/local/delete_text_in_file.py +4 -7
  82. janito/tools/adapters/local/fetch_url.py +97 -97
  83. janito/tools/adapters/local/find_files.py +138 -140
  84. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  85. janito/tools/adapters/local/get_file_outline/core.py +117 -151
  86. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -0
  87. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  88. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  89. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  90. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  91. janito/tools/adapters/local/move_file.py +3 -13
  92. janito/tools/adapters/local/open_html_in_browser.py +24 -29
  93. janito/tools/adapters/local/open_url.py +3 -2
  94. janito/tools/adapters/local/python_code_run.py +166 -166
  95. janito/tools/adapters/local/python_command_run.py +164 -164
  96. janito/tools/adapters/local/python_file_run.py +163 -163
  97. janito/tools/adapters/local/remove_directory.py +6 -17
  98. janito/tools/adapters/local/remove_file.py +9 -15
  99. janito/tools/adapters/local/replace_text_in_file.py +6 -9
  100. janito/tools/adapters/local/run_bash_command.py +176 -176
  101. janito/tools/adapters/local/run_powershell_command.py +219 -219
  102. janito/tools/adapters/local/search_text/__init__.py +1 -1
  103. janito/tools/adapters/local/search_text/core.py +201 -201
  104. janito/tools/adapters/local/search_text/match_lines.py +1 -1
  105. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  106. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  107. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  108. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  109. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  110. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  111. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  112. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  113. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  114. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  115. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  116. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  117. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  118. janito/tools/adapters/local/view_file.py +167 -167
  119. janito/tools/inspect_registry.py +17 -17
  120. janito/tools/tool_base.py +105 -105
  121. janito/tools/tool_events.py +58 -58
  122. janito/tools/tool_run_exception.py +12 -12
  123. janito/tools/tool_use_tracker.py +81 -81
  124. janito/tools/tool_utils.py +45 -45
  125. janito/tools/tools_adapter.py +78 -6
  126. janito/tools/tools_schema.py +104 -104
  127. janito/version.py +4 -4
  128. {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/METADATA +388 -232
  129. janito-2.3.0.dist-info/RECORD +181 -0
  130. janito-2.3.0.dist-info/licenses/LICENSE +21 -0
  131. janito/cli/chat_mode/shell/commands/last.py +0 -137
  132. janito/drivers/google_genai/driver.py +0 -54
  133. janito/drivers/google_genai/schema_generator.py +0 -67
  134. janito-2.1.1.dist-info/RECORD +0 -181
  135. {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/WHEEL +0 -0
  136. {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/entry_points.txt +0 -0
  137. {janito-2.1.1.dist-info → janito-2.3.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
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
@@ -16,7 +16,7 @@ class MoveFileTool(ToolBase):
16
16
  src_path (str): Source file or directory path.
17
17
  dest_path (str): Destination file or directory path.
18
18
  overwrite (bool, optional): Whether to overwrite if the destination exists. Defaults to False.
19
- backup (bool, optional): If True, create a backup (.bak for files, .bak.zip for directories) of the destination before moving if it exists. Recommend using backup=True only in the first call to avoid redundant backups. Defaults to False.
19
+ backup (bool, optional): Deprecated. No backups are created anymore. This flag is ignored. Defaults to False.
20
20
  Returns:
21
21
  str: Status message indicating the result.
22
22
  """
@@ -60,11 +60,7 @@ class MoveFileTool(ToolBase):
60
60
  shutil.move(src, dest)
61
61
  self.report_success(tr("✅ Move complete."))
62
62
  msg = tr("✅ Move complete.")
63
- if backup_path:
64
- msg += tr(
65
- " (backup at {backup_disp})",
66
- backup_disp=display_path(backup_path),
67
- )
63
+
68
64
  return msg
69
65
  except Exception as e:
70
66
  self.report_error(tr("❌ Error moving: {error}", error=e))
@@ -116,13 +112,7 @@ class MoveFileTool(ToolBase):
116
112
  "❗ Destination '{disp_dest}' already exists and overwrite is False.",
117
113
  disp_dest=disp_dest,
118
114
  )
119
- if backup:
120
- if os.path.isfile(dest):
121
- backup_path = dest + ".bak"
122
- shutil.copy2(dest, backup_path)
123
- elif os.path.isdir(dest):
124
- backup_path = dest.rstrip("/\\") + ".bak.zip"
125
- shutil.make_archive(dest.rstrip("/\\") + ".bak", "zip", dest)
115
+
126
116
  try:
127
117
  if os.path.isfile(dest):
128
118
  os.remove(dest)
@@ -1,43 +1,38 @@
1
- from janito.tools.tool_base import ToolBase
1
+ import os
2
+ import webbrowser
2
3
  from janito.tools.adapters.local.adapter import register_local_tool
4
+ from janito.tools.tool_base import ToolBase
3
5
  from janito.report_events import ReportAction
4
- import webbrowser
5
- import os
6
+ from janito.i18n import tr
6
7
 
7
8
  @register_local_tool
8
9
  class OpenHtmlInBrowserTool(ToolBase):
9
10
  """
10
- Opens an HTML file in the default web browser.
11
+ Open the supplied HTML file in the default web browser.
11
12
 
12
13
  Args:
13
- file_path (str): The path to the HTML file to open.
14
-
14
+ file_path (str): Path to the HTML file to open.
15
15
  Returns:
16
- str: Status message indicating the result. Example:
17
- - "✅ Successfully opened the file in the default browser."
18
- - "âš ī¸ Error: The specified file does not exist."
19
- - "âš ī¸ Error: The specified file is not an HTML file."
16
+ str: Status message indicating the result.
20
17
  """
21
-
22
18
  tool_name = "open_html_in_browser"
23
19
 
24
20
  def run(self, file_path: str) -> str:
25
- from janito.i18n import tr
26
- disp_path = file_path
27
- self.report_action(tr("📖 Opening HTML file: '{disp_path}'", disp_path=disp_path), ReportAction.EXECUTE)
28
-
29
- if not os.path.exists(file_path):
30
- self.report_error(tr("âš ī¸ The specified file does not exist: '{disp_path}'", disp_path=disp_path))
31
- return "âš ī¸ The specified file does not exist."
32
-
33
- if not file_path.lower().endswith('.html'):
34
- self.report_error(tr("âš ī¸ The specified file is not an HTML file: '{disp_path}'", disp_path=disp_path))
35
- return "âš ī¸ The specified file is not an HTML file."
36
-
21
+ if not file_path.strip():
22
+ self.report_warning(tr("â„šī¸ Empty file path provided."))
23
+ return tr("Warning: Empty file path provided. Operation skipped.")
24
+ if not os.path.isfile(file_path):
25
+ self.report_error(tr("❗ File does not exist: {file_path}", file_path=file_path))
26
+ return tr("Warning: File does not exist: {file_path}", file_path=file_path)
27
+ if not file_path.lower().endswith(('.html', '.htm')):
28
+ self.report_warning(tr("âš ī¸ Not an HTML file: {file_path}", file_path=file_path))
29
+ return tr("Warning: Not an HTML file: {file_path}", file_path=file_path)
30
+ url = 'file://' + os.path.abspath(file_path)
31
+ self.report_action(tr("📖 Opening HTML file in browser: {file_path}", file_path=file_path), ReportAction.READ)
37
32
  try:
38
- webbrowser.open(f"file://{os.path.abspath(file_path)}")
39
- self.report_success(tr("✅ Ok"))
40
- return "✅ Ok"
41
- except Exception as e:
42
- self.report_error(tr("âš ī¸ Failed to open the HTML file: {err}", err=str(e)))
43
- return f"âš ī¸ Failed to open the file: {str(e)}"
33
+ webbrowser.open(url)
34
+ except Exception as err:
35
+ self.report_error(tr("❗ Error opening HTML file: {file_path}: {err}", file_path=file_path, err=str(err)))
36
+ return tr("Warning: Error opening HTML file: {file_path}: {err}", file_path=file_path, err=str(err))
37
+ self.report_success(tr("✅ HTML file opened in browser: {file_path}", file_path=file_path))
38
+ return tr("HTML file opened in browser: {file_path}", file_path=file_path)
@@ -8,9 +8,10 @@ from janito.i18n import tr
8
8
  @register_local_tool
9
9
  class OpenUrlTool(ToolBase):
10
10
  """
11
- Open the supplied URL in the default web browser.
11
+ Open the supplied URL or local file in the default web browser.
12
+
12
13
  Args:
13
- url (str): The URL to open.
14
+ url (str): The URL or local file path (as a file:// URL) to open. Supports both web URLs (http, https) and local files (file://).
14
15
  Returns:
15
16
  str: Status message indicating the result.
16
17
  """