janito 1.14.3__py3-none-any.whl → 2.0.1__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 (283) hide show
  1. janito/__init__.py +6 -1
  2. janito/__main__.py +1 -1
  3. janito/agent/setup_agent.py +139 -0
  4. janito/agent/templates/profiles/{system_prompt_template_base.txt.j2 → system_prompt_template_main.txt.j2} +1 -1
  5. janito/cli/__init__.py +9 -0
  6. janito/cli/chat_mode/bindings.py +37 -0
  7. janito/cli/chat_mode/chat_entry.py +23 -0
  8. janito/cli/chat_mode/prompt_style.py +19 -0
  9. janito/cli/chat_mode/session.py +272 -0
  10. janito/{shell/prompt/completer.py → cli/chat_mode/shell/autocomplete.py} +7 -6
  11. janito/cli/chat_mode/shell/commands/__init__.py +55 -0
  12. janito/cli/chat_mode/shell/commands/base.py +9 -0
  13. janito/cli/chat_mode/shell/commands/clear.py +12 -0
  14. janito/{shell → cli/chat_mode/shell}/commands/conversation_restart.py +34 -30
  15. janito/cli/chat_mode/shell/commands/edit.py +25 -0
  16. janito/cli/chat_mode/shell/commands/help.py +16 -0
  17. janito/cli/chat_mode/shell/commands/history_view.py +93 -0
  18. janito/cli/chat_mode/shell/commands/lang.py +25 -0
  19. janito/cli/chat_mode/shell/commands/last.py +137 -0
  20. janito/cli/chat_mode/shell/commands/livelogs.py +49 -0
  21. janito/cli/chat_mode/shell/commands/multi.py +51 -0
  22. janito/cli/chat_mode/shell/commands/prompt.py +64 -0
  23. janito/cli/chat_mode/shell/commands/role.py +36 -0
  24. janito/cli/chat_mode/shell/commands/session.py +40 -0
  25. janito/{shell → cli/chat_mode/shell}/commands/session_control.py +2 -2
  26. janito/cli/chat_mode/shell/commands/termweb_log.py +92 -0
  27. janito/cli/chat_mode/shell/commands/tools.py +32 -0
  28. janito/{shell → cli/chat_mode/shell}/commands/utility.py +4 -7
  29. janito/{shell → cli/chat_mode/shell}/commands/verbose.py +5 -5
  30. janito/cli/chat_mode/shell/session/__init__.py +1 -0
  31. janito/{shell → cli/chat_mode/shell}/session/manager.py +9 -1
  32. janito/cli/chat_mode/toolbar.py +90 -0
  33. janito/cli/cli_commands/list_models.py +35 -0
  34. janito/cli/cli_commands/list_providers.py +9 -0
  35. janito/cli/cli_commands/list_tools.py +53 -0
  36. janito/cli/cli_commands/model_selection.py +50 -0
  37. janito/cli/cli_commands/model_utils.py +84 -0
  38. janito/cli/cli_commands/set_api_key.py +19 -0
  39. janito/cli/cli_commands/show_config.py +51 -0
  40. janito/cli/cli_commands/show_system_prompt.py +62 -0
  41. janito/cli/config.py +28 -0
  42. janito/cli/console.py +3 -0
  43. janito/cli/core/__init__.py +4 -0
  44. janito/cli/core/event_logger.py +59 -0
  45. janito/cli/core/getters.py +31 -0
  46. janito/cli/core/runner.py +141 -0
  47. janito/cli/core/setters.py +174 -0
  48. janito/cli/core/unsetters.py +54 -0
  49. janito/cli/main.py +8 -196
  50. janito/cli/main_cli.py +312 -0
  51. janito/cli/prompt_core.py +230 -0
  52. janito/cli/prompt_handler.py +6 -0
  53. janito/cli/rich_terminal_reporter.py +101 -0
  54. janito/cli/single_shot_mode/__init__.py +6 -0
  55. janito/cli/single_shot_mode/handler.py +137 -0
  56. janito/cli/termweb_starter.py +73 -24
  57. janito/cli/utils.py +25 -0
  58. janito/cli/verbose_output.py +196 -0
  59. janito/config.py +5 -0
  60. janito/config_manager.py +110 -0
  61. janito/conversation_history.py +30 -0
  62. janito/{agent/tools_utils/dir_walk_utils.py → dir_walk_utils.py} +3 -2
  63. janito/driver_events.py +98 -0
  64. janito/drivers/anthropic/driver.py +113 -0
  65. janito/drivers/azure_openai/driver.py +36 -0
  66. janito/drivers/driver_registry.py +33 -0
  67. janito/drivers/google_genai/driver.py +54 -0
  68. janito/drivers/google_genai/schema_generator.py +67 -0
  69. janito/drivers/mistralai/driver.py +41 -0
  70. janito/drivers/openai/driver.py +334 -0
  71. janito/event_bus/__init__.py +2 -0
  72. janito/event_bus/bus.py +68 -0
  73. janito/event_bus/event.py +15 -0
  74. janito/event_bus/handler.py +31 -0
  75. janito/event_bus/queue_bus.py +57 -0
  76. janito/exceptions.py +23 -0
  77. janito/formatting_token.py +54 -0
  78. janito/i18n/pt.py +1 -0
  79. janito/llm/__init__.py +5 -0
  80. janito/llm/agent.py +443 -0
  81. janito/llm/auth.py +62 -0
  82. janito/llm/driver.py +239 -0
  83. janito/llm/driver_config.py +34 -0
  84. janito/llm/driver_config_builder.py +34 -0
  85. janito/llm/driver_input.py +12 -0
  86. janito/llm/message_parts.py +60 -0
  87. janito/llm/model.py +38 -0
  88. janito/llm/provider.py +187 -0
  89. janito/perf_singleton.py +3 -0
  90. janito/performance_collector.py +167 -0
  91. janito/provider_config.py +98 -0
  92. janito/provider_registry.py +152 -0
  93. janito/providers/__init__.py +7 -0
  94. janito/providers/anthropic/model_info.py +22 -0
  95. janito/providers/anthropic/provider.py +65 -0
  96. janito/providers/azure_openai/model_info.py +15 -0
  97. janito/providers/azure_openai/provider.py +72 -0
  98. janito/providers/deepseek/__init__.py +1 -0
  99. janito/providers/deepseek/model_info.py +16 -0
  100. janito/providers/deepseek/provider.py +91 -0
  101. janito/providers/google/__init__.py +1 -0
  102. janito/providers/google/model_info.py +40 -0
  103. janito/providers/google/provider.py +69 -0
  104. janito/providers/mistralai/model_info.py +37 -0
  105. janito/providers/mistralai/provider.py +69 -0
  106. janito/providers/openai/__init__.py +1 -0
  107. janito/providers/openai/model_info.py +137 -0
  108. janito/providers/openai/provider.py +107 -0
  109. janito/providers/openai/schema_generator.py +63 -0
  110. janito/providers/provider_static_info.py +21 -0
  111. janito/providers/registry.py +26 -0
  112. janito/report_events.py +38 -0
  113. janito/termweb/app.py +1 -1
  114. janito/tools/__init__.py +16 -0
  115. janito/tools/adapters/__init__.py +1 -0
  116. janito/tools/adapters/local/__init__.py +54 -0
  117. janito/tools/adapters/local/adapter.py +92 -0
  118. janito/{agent/tools → tools/adapters/local}/ask_user.py +30 -13
  119. janito/tools/adapters/local/copy_file.py +84 -0
  120. janito/{agent/tools → tools/adapters/local}/create_directory.py +11 -10
  121. janito/tools/adapters/local/create_file.py +82 -0
  122. janito/tools/adapters/local/delete_text_in_file.py +136 -0
  123. janito/{agent/tools → tools/adapters/local}/fetch_url.py +18 -19
  124. janito/tools/adapters/local/find_files.py +140 -0
  125. janito/tools/adapters/local/get_file_outline/core.py +151 -0
  126. janito/{agent/tools → tools/adapters/local}/get_file_outline/python_outline.py +125 -0
  127. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -0
  128. janito/{agent/tools → tools/adapters/local}/get_file_outline/search_outline.py +12 -7
  129. janito/{agent/tools → tools/adapters/local}/move_file.py +13 -9
  130. janito/tools/adapters/local/open_html_in_browser.py +34 -0
  131. janito/{agent/tools → tools/adapters/local}/open_url.py +7 -5
  132. janito/tools/adapters/local/python_code_run.py +165 -0
  133. janito/tools/adapters/local/python_command_run.py +163 -0
  134. janito/tools/adapters/local/python_file_run.py +162 -0
  135. janito/{agent/tools → tools/adapters/local}/remove_directory.py +15 -9
  136. janito/{agent/tools → tools/adapters/local}/remove_file.py +17 -14
  137. janito/{agent/tools → tools/adapters/local}/replace_text_in_file.py +27 -22
  138. janito/tools/adapters/local/run_bash_command.py +176 -0
  139. janito/tools/adapters/local/run_powershell_command.py +219 -0
  140. janito/{agent/tools → tools/adapters/local}/search_text/core.py +32 -12
  141. janito/{agent/tools → tools/adapters/local}/search_text/match_lines.py +13 -4
  142. janito/{agent/tools → tools/adapters/local}/search_text/pattern_utils.py +12 -4
  143. janito/{agent/tools → tools/adapters/local}/search_text/traverse_directory.py +15 -2
  144. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/core.py +12 -11
  145. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/css_validator.py +1 -1
  146. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/html_validator.py +1 -1
  147. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/js_validator.py +1 -1
  148. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/json_validator.py +1 -1
  149. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/markdown_validator.py +1 -1
  150. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/ps1_validator.py +1 -1
  151. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/python_validator.py +1 -1
  152. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/xml_validator.py +1 -1
  153. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/yaml_validator.py +1 -1
  154. janito/{agent/tools/get_lines.py → tools/adapters/local/view_file.py} +45 -27
  155. janito/tools/inspect_registry.py +17 -0
  156. janito/tools/tool_base.py +105 -0
  157. janito/tools/tool_events.py +58 -0
  158. janito/tools/tool_run_exception.py +12 -0
  159. janito/{agent → tools}/tool_use_tracker.py +2 -4
  160. janito/{agent/tools_utils/utils.py → tools/tool_utils.py} +18 -9
  161. janito/tools/tools_adapter.py +207 -0
  162. janito/tools/tools_schema.py +104 -0
  163. janito/utils.py +11 -0
  164. janito/version.py +4 -0
  165. janito-2.0.1.dist-info/METADATA +232 -0
  166. janito-2.0.1.dist-info/RECORD +181 -0
  167. janito/agent/__init__.py +0 -0
  168. janito/agent/api_exceptions.py +0 -4
  169. janito/agent/config.py +0 -147
  170. janito/agent/config_defaults.py +0 -12
  171. janito/agent/config_utils.py +0 -0
  172. janito/agent/content_handler.py +0 -0
  173. janito/agent/conversation.py +0 -238
  174. janito/agent/conversation_api.py +0 -306
  175. janito/agent/conversation_exceptions.py +0 -18
  176. janito/agent/conversation_tool_calls.py +0 -39
  177. janito/agent/conversation_ui.py +0 -17
  178. janito/agent/event.py +0 -24
  179. janito/agent/event_dispatcher.py +0 -24
  180. janito/agent/event_handler_protocol.py +0 -5
  181. janito/agent/event_system.py +0 -15
  182. janito/agent/llm_conversation_history.py +0 -82
  183. janito/agent/message_handler.py +0 -20
  184. janito/agent/message_handler_protocol.py +0 -5
  185. janito/agent/openai_client.py +0 -149
  186. janito/agent/openai_schema_generator.py +0 -187
  187. janito/agent/profile_manager.py +0 -96
  188. janito/agent/queued_message_handler.py +0 -50
  189. janito/agent/rich_live.py +0 -32
  190. janito/agent/rich_message_handler.py +0 -115
  191. janito/agent/runtime_config.py +0 -36
  192. janito/agent/test_handler_protocols.py +0 -47
  193. janito/agent/test_openai_schema_generator.py +0 -93
  194. janito/agent/tests/__init__.py +0 -1
  195. janito/agent/tool_base.py +0 -63
  196. janito/agent/tool_executor.py +0 -122
  197. janito/agent/tool_registry.py +0 -49
  198. janito/agent/tools/__init__.py +0 -47
  199. janito/agent/tools/create_file.py +0 -59
  200. janito/agent/tools/delete_text_in_file.py +0 -97
  201. janito/agent/tools/find_files.py +0 -106
  202. janito/agent/tools/get_file_outline/core.py +0 -81
  203. janito/agent/tools/present_choices.py +0 -64
  204. janito/agent/tools/python_command_runner.py +0 -201
  205. janito/agent/tools/python_file_runner.py +0 -199
  206. janito/agent/tools/python_stdin_runner.py +0 -208
  207. janito/agent/tools/replace_file.py +0 -72
  208. janito/agent/tools/run_bash_command.py +0 -218
  209. janito/agent/tools/run_powershell_command.py +0 -251
  210. janito/agent/tools_utils/__init__.py +0 -1
  211. janito/agent/tools_utils/action_type.py +0 -7
  212. janito/agent/tools_utils/test_gitignore_utils.py +0 -46
  213. janito/cli/_livereload_log_utils.py +0 -13
  214. janito/cli/_print_config.py +0 -96
  215. janito/cli/_termweb_log_utils.py +0 -17
  216. janito/cli/_utils.py +0 -9
  217. janito/cli/arg_parser.py +0 -272
  218. janito/cli/cli_main.py +0 -281
  219. janito/cli/config_commands.py +0 -211
  220. janito/cli/config_runner.py +0 -35
  221. janito/cli/formatting_runner.py +0 -12
  222. janito/cli/livereload_starter.py +0 -60
  223. janito/cli/logging_setup.py +0 -38
  224. janito/cli/one_shot.py +0 -80
  225. janito/livereload/app.py +0 -25
  226. janito/rich_utils.py +0 -59
  227. janito/shell/__init__.py +0 -0
  228. janito/shell/commands/__init__.py +0 -61
  229. janito/shell/commands/config.py +0 -22
  230. janito/shell/commands/edit.py +0 -24
  231. janito/shell/commands/history_view.py +0 -18
  232. janito/shell/commands/lang.py +0 -19
  233. janito/shell/commands/livelogs.py +0 -42
  234. janito/shell/commands/prompt.py +0 -62
  235. janito/shell/commands/termweb_log.py +0 -94
  236. janito/shell/commands/tools.py +0 -26
  237. janito/shell/commands/track.py +0 -36
  238. janito/shell/main.py +0 -326
  239. janito/shell/prompt/load_prompt.py +0 -57
  240. janito/shell/prompt/session_setup.py +0 -57
  241. janito/shell/session/config.py +0 -109
  242. janito/shell/session/history.py +0 -0
  243. janito/shell/ui/interactive.py +0 -226
  244. janito/termweb/static/editor.css +0 -158
  245. janito/termweb/static/editor.css.bak +0 -145
  246. janito/termweb/static/editor.html +0 -46
  247. janito/termweb/static/editor.html.bak +0 -46
  248. janito/termweb/static/editor.js +0 -265
  249. janito/termweb/static/editor.js.bak +0 -259
  250. janito/termweb/static/explorer.html.bak +0 -59
  251. janito/termweb/static/favicon.ico +0 -0
  252. janito/termweb/static/favicon.ico.bak +0 -0
  253. janito/termweb/static/index.html +0 -53
  254. janito/termweb/static/index.html.bak +0 -54
  255. janito/termweb/static/index.html.bak.bak +0 -175
  256. janito/termweb/static/landing.html.bak +0 -36
  257. janito/termweb/static/termicon.svg +0 -1
  258. janito/termweb/static/termweb.css +0 -214
  259. janito/termweb/static/termweb.css.bak +0 -237
  260. janito/termweb/static/termweb.js +0 -162
  261. janito/termweb/static/termweb.js.bak +0 -168
  262. janito/termweb/static/termweb.js.bak.bak +0 -157
  263. janito/termweb/static/termweb_quickopen.js +0 -135
  264. janito/termweb/static/termweb_quickopen.js.bak +0 -125
  265. janito/tests/test_rich_utils.py +0 -44
  266. janito/web/__init__.py +0 -0
  267. janito/web/__main__.py +0 -25
  268. janito/web/app.py +0 -145
  269. janito-1.14.3.dist-info/METADATA +0 -313
  270. janito-1.14.3.dist-info/RECORD +0 -162
  271. janito-1.14.3.dist-info/licenses/LICENSE +0 -21
  272. /janito/{shell → cli/chat_mode/shell}/input_history.py +0 -0
  273. /janito/{shell/commands/session.py → cli/chat_mode/shell/session/history.py} +0 -0
  274. /janito/{agent/tools_utils/formatting.py → formatting.py} +0 -0
  275. /janito/{agent/tools_utils/gitignore_utils.py → gitignore_utils.py} +0 -0
  276. /janito/{agent/platform_discovery.py → platform_discovery.py} +0 -0
  277. /janito/{agent/tools → tools/adapters/local}/get_file_outline/__init__.py +0 -0
  278. /janito/{agent/tools → tools/adapters/local}/get_file_outline/markdown_outline.py +0 -0
  279. /janito/{agent/tools → tools/adapters/local}/search_text/__init__.py +0 -0
  280. /janito/{agent/tools → tools/adapters/local}/validate_file_syntax/__init__.py +0 -0
  281. {janito-1.14.3.dist-info → janito-2.0.1.dist-info}/WHEEL +0 -0
  282. {janito-1.14.3.dist-info → janito-2.0.1.dist-info}/entry_points.txt +0 -0
  283. {janito-1.14.3.dist-info → janito-2.0.1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
- from janito.agent.tool_base import ToolBase
2
- from janito.agent.tools_utils.action_type import ActionType
3
- from janito.agent.tool_registry import register_tool
4
- from janito.agent.tools_utils.utils import pluralize, display_path
1
+ from janito.tools.tool_base import ToolBase
2
+ from janito.report_events import ReportAction
3
+ from janito.tools.adapters.local.adapter import register_local_tool
4
+ from janito.tools.tool_utils import pluralize, display_path
5
5
  from janito.i18n import tr
6
6
  import os
7
7
  from .pattern_utils import prepare_pattern, format_result, summarize_total
@@ -9,7 +9,10 @@ from .match_lines import read_file_lines
9
9
  from .traverse_directory import traverse_directory
10
10
 
11
11
 
12
- @register_tool(name="search_text")
12
+ from janito.tools.adapters.local.adapter import register_local_tool as register_tool
13
+
14
+
15
+ @register_tool
13
16
  class SearchTextTool(ToolBase):
14
17
  """
15
18
  Search for a text pattern (regex or plain string) in all files within one or more directories or file paths and return matching lines or counts. Respects .gitignore.
@@ -17,6 +20,7 @@ class SearchTextTool(ToolBase):
17
20
  paths (str): String of one or more paths (space-separated) to search in. Each path can be a directory or a file.
18
21
  pattern (str): Regex pattern or plain text substring to search for in files. Must not be empty. Tries regex first, falls back to substring if regex is invalid.
19
22
  is_regex (bool): If True, treat pattern as a regular expression. If False, treat as plain text (default).
23
+ case_sensitive (bool): If False, perform a case-insensitive search. Default is True (case sensitive).
20
24
  max_depth (int, optional): Maximum directory depth to search. If 0 (default), search is recursive with no depth limit. If >0, limits recursion to that depth. Setting max_depth=1 disables recursion (only top-level directory). Ignored for file paths.
21
25
  max_results (int, optional): Maximum number of results to return. Defaults to 100. 0 means no limit.
22
26
  count_only (bool): If True, return only the count of matches per file and total, not the matching lines. Default is False.
@@ -26,12 +30,15 @@ class SearchTextTool(ToolBase):
26
30
  If max_results is reached, appends a note to the output.
27
31
  """
28
32
 
33
+ tool_name = "search_text"
34
+
29
35
  def _handle_file(
30
36
  self,
31
37
  search_path,
32
38
  pattern,
33
39
  regex,
34
40
  use_regex,
41
+ case_sensitive,
35
42
  max_results,
36
43
  total_results,
37
44
  count_only,
@@ -42,6 +49,7 @@ class SearchTextTool(ToolBase):
42
49
  pattern,
43
50
  regex,
44
51
  use_regex,
52
+ case_sensitive,
45
53
  True,
46
54
  max_results,
47
55
  total_results,
@@ -54,6 +62,7 @@ class SearchTextTool(ToolBase):
54
62
  pattern,
55
63
  regex,
56
64
  use_regex,
65
+ case_sensitive,
57
66
  False,
58
67
  max_results,
59
68
  total_results,
@@ -71,13 +80,14 @@ class SearchTextTool(ToolBase):
71
80
  pattern,
72
81
  regex,
73
82
  use_regex,
83
+ case_sensitive,
74
84
  max_depth,
75
85
  max_results,
76
86
  total_results,
77
87
  count_only,
78
88
  ):
79
89
  info_str = tr(
80
- "\U0001f50d Search {search_type} '{pattern}' in '{disp_path}'",
90
+ "🔍 Search {search_type} '{pattern}' in '{disp_path}'",
81
91
  search_type=("regex" if use_regex else "text"),
82
92
  pattern=pattern,
83
93
  disp_path=display_path(search_path),
@@ -86,13 +96,14 @@ class SearchTextTool(ToolBase):
86
96
  info_str += tr(" [max_depth={max_depth}]", max_depth=max_depth)
87
97
  if count_only:
88
98
  info_str += " [count]"
89
- self.report_info(ActionType.READ, info_str)
99
+ self.report_action(info_str, ReportAction.READ)
90
100
  if os.path.isfile(search_path):
91
101
  dir_output, dir_limit_reached, per_file_counts = self._handle_file(
92
102
  search_path,
93
103
  pattern,
94
104
  regex,
95
105
  use_regex,
106
+ case_sensitive,
96
107
  max_results,
97
108
  total_results,
98
109
  count_only,
@@ -104,6 +115,7 @@ class SearchTextTool(ToolBase):
104
115
  pattern,
105
116
  regex,
106
117
  use_regex,
118
+ case_sensitive,
107
119
  max_depth,
108
120
  max_results,
109
121
  total_results,
@@ -116,6 +128,7 @@ class SearchTextTool(ToolBase):
116
128
  pattern,
117
129
  regex,
118
130
  use_regex,
131
+ case_sensitive,
119
132
  max_depth,
120
133
  max_results,
121
134
  total_results,
@@ -123,13 +136,18 @@ class SearchTextTool(ToolBase):
123
136
  )
124
137
  count = sum(count for _, count in per_file_counts)
125
138
  file_word = pluralize("match", count)
139
+ num_files = len(per_file_counts)
140
+ file_label = pluralize("file", num_files)
141
+ file_word_max = file_word + (" (max)" if dir_limit_reached else "")
126
142
  self.report_success(
127
143
  tr(
128
- " ✅ {count} {file_word}{max_flag}",
144
+ " ✅ {count} {file_word} from {num_files} {file_label}",
129
145
  count=count,
130
- file_word=file_word,
131
- max_flag=" (max)" if dir_limit_reached else "",
132
- )
146
+ file_word=file_word_max,
147
+ num_files=num_files,
148
+ file_label=file_label,
149
+ ),
150
+ ReportAction.READ,
133
151
  )
134
152
  return info_str, dir_output, dir_limit_reached, per_file_counts
135
153
 
@@ -138,12 +156,13 @@ class SearchTextTool(ToolBase):
138
156
  paths: str,
139
157
  pattern: str,
140
158
  is_regex: bool = False,
159
+ case_sensitive: bool = False,
141
160
  max_depth: int = 0,
142
161
  max_results: int = 100,
143
162
  count_only: bool = False,
144
163
  ) -> str:
145
164
  regex, use_regex, error_msg = prepare_pattern(
146
- pattern, is_regex, self.report_error, self.report_warning
165
+ pattern, is_regex, case_sensitive, self.report_error, self.report_warning
147
166
  )
148
167
  if error_msg:
149
168
  return error_msg
@@ -157,6 +176,7 @@ class SearchTextTool(ToolBase):
157
176
  pattern,
158
177
  regex,
159
178
  use_regex,
179
+ case_sensitive,
160
180
  max_depth,
161
181
  max_results,
162
182
  0,
@@ -1,5 +1,5 @@
1
1
  import re
2
- from janito.agent.tools_utils.gitignore_utils import GitignoreFilter
2
+ from janito.gitignore_utils import GitignoreFilter
3
3
  import os
4
4
 
5
5
 
@@ -20,9 +20,11 @@ def is_binary_file(path, blocksize=1024):
20
20
  return False
21
21
 
22
22
 
23
- def match_line(line, pattern, regex, use_regex):
23
+ def match_line(line, pattern, regex, use_regex, case_sensitive):
24
24
  if use_regex:
25
25
  return regex and regex.search(line)
26
+ if not case_sensitive:
27
+ return pattern in line.lower()
26
28
  return pattern in line
27
29
 
28
30
 
@@ -34,7 +36,14 @@ def should_limit(max_results, total_results, match_count, count_only, dir_output
34
36
 
35
37
 
36
38
  def read_file_lines(
37
- path, pattern, regex, use_regex, count_only, max_results, total_results
39
+ path,
40
+ pattern,
41
+ regex,
42
+ use_regex,
43
+ case_sensitive,
44
+ count_only,
45
+ max_results,
46
+ total_results,
38
47
  ):
39
48
  dir_output = []
40
49
  dir_limit_reached = False
@@ -44,7 +53,7 @@ def read_file_lines(
44
53
  open_kwargs = {"mode": "r", "encoding": "utf-8"}
45
54
  with open(path, **open_kwargs) as f:
46
55
  for lineno, line in enumerate(f, 1):
47
- if match_line(line, pattern, regex, use_regex):
56
+ if match_line(line, pattern, regex, use_regex, case_sensitive):
48
57
  match_count += 1
49
58
  if not count_only:
50
59
  dir_output.append(f"{path}:{lineno}: {line.rstrip()}")
@@ -1,11 +1,14 @@
1
1
  import re
2
2
  from janito.i18n import tr
3
- from janito.agent.tools_utils.utils import pluralize
3
+ from janito.tools.tool_utils import pluralize
4
4
 
5
5
 
6
- def prepare_pattern(pattern, is_regex, report_error, report_warning):
6
+ def prepare_pattern(pattern, is_regex, case_sensitive, report_error, report_warning):
7
7
  if not pattern:
8
- report_error(tr("Error: Empty search pattern provided. Operation aborted."))
8
+ report_error(
9
+ tr("Error: Empty search pattern provided. Operation aborted."),
10
+ ReportAction.SEARCH,
11
+ )
9
12
  return (
10
13
  None,
11
14
  False,
@@ -15,7 +18,10 @@ def prepare_pattern(pattern, is_regex, report_error, report_warning):
15
18
  use_regex = False
16
19
  if is_regex:
17
20
  try:
18
- regex = re.compile(pattern)
21
+ flags = 0
22
+ if not case_sensitive:
23
+ flags |= re.IGNORECASE
24
+ regex = re.compile(pattern, flags=flags)
19
25
  use_regex = True
20
26
  except re.error as e:
21
27
  report_warning(tr("⚠️ Invalid regex pattern."))
@@ -30,6 +36,8 @@ def prepare_pattern(pattern, is_regex, report_error, report_warning):
30
36
  # Do not compile as regex if is_regex is False; treat as plain text
31
37
  regex = None
32
38
  use_regex = False
39
+ if not case_sensitive:
40
+ pattern = pattern.lower()
33
41
  return regex, use_regex, None
34
42
 
35
43
 
@@ -1,5 +1,5 @@
1
1
  import os
2
- from janito.agent.tools_utils.gitignore_utils import GitignoreFilter
2
+ from janito.gitignore_utils import GitignoreFilter
3
3
  from .match_lines import match_line, should_limit, read_file_lines
4
4
 
5
5
 
@@ -24,13 +24,21 @@ def filter_dirs(dirs, root, gitignore_filter):
24
24
 
25
25
 
26
26
  def process_file_count_only(
27
- file_path, per_file_counts, pattern, regex, use_regex, max_results, total_results
27
+ file_path,
28
+ per_file_counts,
29
+ pattern,
30
+ regex,
31
+ use_regex,
32
+ case_sensitive,
33
+ max_results,
34
+ total_results,
28
35
  ):
29
36
  match_count, file_limit_reached, _ = read_file_lines(
30
37
  file_path,
31
38
  pattern,
32
39
  regex,
33
40
  use_regex,
41
+ case_sensitive,
34
42
  True,
35
43
  max_results,
36
44
  total_results + sum(count for _, count in per_file_counts),
@@ -47,6 +55,7 @@ def process_file_collect(
47
55
  pattern,
48
56
  regex,
49
57
  use_regex,
58
+ case_sensitive,
50
59
  max_results,
51
60
  total_results,
52
61
  ):
@@ -55,6 +64,7 @@ def process_file_collect(
55
64
  pattern,
56
65
  regex,
57
66
  use_regex,
67
+ case_sensitive,
58
68
  False,
59
69
  max_results,
60
70
  total_results + len(dir_output),
@@ -79,6 +89,7 @@ def traverse_directory(
79
89
  pattern,
80
90
  regex,
81
91
  use_regex,
92
+ case_sensitive,
82
93
  max_depth,
83
94
  max_results,
84
95
  total_results,
@@ -103,6 +114,7 @@ def traverse_directory(
103
114
  pattern,
104
115
  regex,
105
116
  use_regex,
117
+ case_sensitive,
106
118
  max_results,
107
119
  total_results,
108
120
  )
@@ -117,6 +129,7 @@ def traverse_directory(
117
129
  pattern,
118
130
  regex,
119
131
  use_regex,
132
+ case_sensitive,
120
133
  max_results,
121
134
  total_results,
122
135
  )
@@ -1,9 +1,10 @@
1
1
  import os
2
2
  from janito.i18n import tr
3
- from janito.agent.tool_base import ToolBase
4
- from janito.agent.tools_utils.action_type import ActionType
5
- from janito.agent.tool_registry import register_tool
6
- from janito.agent.tools_utils.utils import display_path
3
+ from janito.tools.tool_base import ToolBase
4
+ from janito.report_events import ReportAction
5
+ from janito.tools.adapters.local.adapter import register_local_tool
6
+ from janito.tools.tool_utils import display_path
7
+ from janito.tools.adapters.local.adapter import register_local_tool as register_tool
7
8
 
8
9
  from .python_validator import validate_python
9
10
  from .json_validator import validate_json
@@ -59,7 +60,6 @@ def validate_file_syntax(
59
60
  return _handle_validation_error(e, report_warning)
60
61
 
61
62
 
62
- @register_tool(name="validate_file_syntax")
63
63
  class ValidateFileSyntaxTool(ToolBase):
64
64
  """
65
65
  Validate a file for syntax issues.
@@ -83,14 +83,16 @@ class ValidateFileSyntaxTool(ToolBase):
83
83
  - "⚠️ Warning: Unsupported file extension: <ext>"
84
84
  """
85
85
 
86
+ tool_name = "validate_file_syntax"
87
+
86
88
  def run(self, file_path: str) -> str:
87
89
  disp_path = display_path(file_path)
88
- self.report_info(
89
- ActionType.READ,
90
+ self.report_action(
90
91
  tr(
91
- "\U0001f50e Validate syntax for file '{disp_path}' ...",
92
+ "🔎 Validate syntax for file '{disp_path}' ...",
92
93
  disp_path=disp_path,
93
94
  ),
95
+ ReportAction.READ,
94
96
  )
95
97
  result = validate_file_syntax(
96
98
  file_path,
@@ -99,7 +101,6 @@ class ValidateFileSyntaxTool(ToolBase):
99
101
  report_success=self.report_success,
100
102
  )
101
103
  if result.startswith("✅"):
102
- self.report_success(result)
103
- elif result.startswith("⚠️"):
104
- self.report_warning(tr("⚠️ ") + result.lstrip("⚠️ "))
104
+ self.report_success(result, ReportAction.READ)
105
+
105
106
  return result
@@ -32,4 +32,4 @@ def validate_css(file_path: str) -> str:
32
32
  "⚠️ Warning: CSS syntax issues found:\n{errors}", errors="\n".join(errors)
33
33
  )
34
34
  return msg
35
- return "✅ Syntax valid"
35
+ return "✅ OK"
@@ -90,4 +90,4 @@ def _build_result_message(warnings, lxml_error):
90
90
  msg += lxml_error
91
91
  if msg:
92
92
  return msg.strip()
93
- return "✅ Syntax valid"
93
+ return "✅ OK"
@@ -24,4 +24,4 @@ def validate_js(file_path: str) -> str:
24
24
  errors="\n".join(errors),
25
25
  )
26
26
  return msg
27
- return "✅ Syntax valid"
27
+ return "✅ OK"
@@ -3,4 +3,4 @@ def validate_json(file_path: str) -> str:
3
3
 
4
4
  with open(file_path, "r", encoding="utf-8") as f:
5
5
  json.load(f)
6
- return "✅ Syntax valid"
6
+ return "✅ OK"
@@ -106,4 +106,4 @@ def _build_markdown_result(errors):
106
106
  errors="\n".join(errors),
107
107
  )
108
108
  return msg
109
- return "✅ Syntax valid"
109
+ return "✅ OK"
@@ -29,4 +29,4 @@ def validate_ps1(file_path: str) -> str:
29
29
  errors="\n".join(errors),
30
30
  )
31
31
  return msg
32
- return "✅ Syntax valid"
32
+ return "✅ OK"
@@ -2,4 +2,4 @@ def validate_python(file_path: str) -> str:
2
2
  import py_compile
3
3
 
4
4
  py_compile.compile(file_path, doraise=True)
5
- return "✅ Syntax valid"
5
+ return "✅ OK"
@@ -8,4 +8,4 @@ def validate_xml(file_path: str) -> str:
8
8
  return tr("⚠️ lxml not installed. Cannot validate XML.")
9
9
  with open(file_path, "rb") as f:
10
10
  etree.parse(f)
11
- return "✅ Syntax valid"
11
+ return "✅ OK"
@@ -3,4 +3,4 @@ def validate_yaml(file_path: str) -> str:
3
3
 
4
4
  with open(file_path, "r", encoding="utf-8") as f:
5
5
  yaml.safe_load(f)
6
- return "✅ Syntax valid"
6
+ return "✅ OK"
@@ -1,12 +1,12 @@
1
- from janito.agent.tool_base import ToolBase
2
- from janito.agent.tools_utils.action_type import ActionType
3
- from janito.agent.tool_registry import register_tool
4
- from janito.agent.tools_utils.utils import pluralize
1
+ from janito.tools.tool_base import ToolBase
2
+ from janito.report_events import ReportAction
3
+ from janito.tools.adapters.local.adapter import register_local_tool
4
+ from janito.tools.tool_utils import pluralize
5
5
  from janito.i18n import tr
6
6
 
7
7
 
8
- @register_tool(name="get_lines")
9
- class GetLinesTool(ToolBase):
8
+ @register_local_tool
9
+ class ViewFileTool(ToolBase):
10
10
  """
11
11
  Read lines from a file. You can specify a line range, or read the entire file by simply omitting the from_line and to_line parameters.
12
12
 
@@ -25,12 +25,20 @@ class GetLinesTool(ToolBase):
25
25
  - "❗ not found"
26
26
  """
27
27
 
28
+ tool_name = "view_file"
29
+
28
30
  def run(self, file_path: str, from_line: int = None, to_line: int = None) -> str:
29
- from janito.agent.tools_utils.utils import display_path
31
+ import os
32
+ from janito.tools.tool_utils import display_path
30
33
 
31
34
  disp_path = display_path(file_path)
32
- self._report_read_info(disp_path, from_line, to_line)
35
+ self.report_action(
36
+ tr("📖 View '{disp_path}'", disp_path=disp_path),
37
+ ReportAction.READ,
38
+ )
33
39
  try:
40
+ if os.path.isdir(file_path):
41
+ return self._list_directory(file_path, disp_path)
34
42
  lines = self._read_file_lines(file_path)
35
43
  selected, selected_len, total_lines = self._select_lines(
36
44
  lines, from_line, to_line
@@ -40,26 +48,36 @@ class GetLinesTool(ToolBase):
40
48
  disp_path, from_line, to_line, selected_len, total_lines
41
49
  )
42
50
  return header + "".join(selected)
51
+ except FileNotFoundError as e:
52
+ self.report_warning(tr("❗ not found"))
53
+ return f"Error reading file: {e}"
43
54
  except Exception as e:
44
- return self._handle_read_error(e)
55
+ self.report_error(tr(" ❌ Error: {error}", error=e))
56
+ return tr("Error reading file: {error}", error=e)
45
57
 
46
- def _report_read_info(self, disp_path, from_line, to_line):
47
- """Report the info message for reading lines."""
48
- if from_line and to_line:
49
- self.report_info(
50
- ActionType.READ,
51
- tr(
52
- "📖 Read file '{disp_path}' {from_line}-{to_line}",
53
- disp_path=disp_path,
54
- from_line=from_line,
55
- to_line=to_line,
56
- ),
57
- )
58
- else:
59
- self.report_info(
60
- ActionType.READ,
61
- tr("📖 Read file '{disp_path}'", disp_path=disp_path),
58
+ def _list_directory(self, file_path, disp_path):
59
+ import os
60
+
61
+ try:
62
+ entries = os.listdir(file_path)
63
+ entries.sort()
64
+ # Suffix subdirectories with '/'
65
+ formatted_entries = []
66
+ for entry in entries:
67
+ full_path = os.path.join(file_path, entry)
68
+ if os.path.isdir(full_path):
69
+ formatted_entries.append(entry + "/")
70
+ else:
71
+ formatted_entries.append(entry)
72
+ header = (
73
+ f"--- view_file: {disp_path} [directory, {len(entries)} entries] ---\n"
62
74
  )
75
+ listing = "\n".join(formatted_entries)
76
+ self.report_success(tr("📁 Directory ({count} items)", count=len(entries)))
77
+ return header + listing + "\n"
78
+ except Exception as e:
79
+ self.report_error(tr(" ❌ Error listing directory: {error}", error=e))
80
+ return tr("Error listing directory: {error}", error=e)
63
81
 
64
82
  def _read_file_lines(self, file_path):
65
83
  """Read all lines from the file."""
@@ -143,7 +161,7 @@ class GetLinesTool(ToolBase):
143
161
  def _handle_read_error(self, e):
144
162
  """Handle file read errors and report appropriately."""
145
163
  if isinstance(e, FileNotFoundError):
146
- self.report_error(tr("❗ not found"))
164
+ self.report_error(tr("❗ not found"), ReportAction.READ)
147
165
  return tr("❗ not found")
148
- self.report_error(tr(" ❌ Error: {error}", error=e))
166
+ self.report_error(tr(" ❌ Error: {error}", error=e), ReportAction.READ)
149
167
  return tr("Error reading file: {error}", error=e)
@@ -0,0 +1,17 @@
1
+ def check_tools_registry():
2
+ # Import and use the singleton tools adapter instance
3
+ from janito.tools.adapters.local import local_tools_adapter
4
+
5
+ print("Available tool names:", local_tools_adapter.list_tools())
6
+ print(
7
+ "Available tool classes:",
8
+ [cls.__name__ for cls in local_tools_adapter.get_tool_classes()],
9
+ )
10
+ print(
11
+ "Available tool instances:",
12
+ [tool.name for tool in local_tools_adapter.get_tools()],
13
+ )
14
+
15
+
16
+ if __name__ == "__main__":
17
+ check_tools_registry()
@@ -0,0 +1,105 @@
1
+ from janito.report_events import ReportEvent, ReportSubtype, ReportAction
2
+ from janito.event_bus.bus import event_bus as default_event_bus
3
+
4
+
5
+ class ToolBase:
6
+ """
7
+ Base class for all tools in the janito project.
8
+ Extend this class to implement specific tool functionality.
9
+ """
10
+ provides_execution = False # Indicates if the tool provides execution capability (default: False)
11
+
12
+ def __init__(self, name=None, event_bus=None):
13
+ self.name = name or self.__class__.__name__
14
+ self._event_bus = event_bus or default_event_bus
15
+
16
+ @property
17
+ def event_bus(self):
18
+ return self._event_bus
19
+
20
+ @event_bus.setter
21
+ def event_bus(self, bus):
22
+ self._event_bus = bus or default_event_bus
23
+
24
+ def report_action(self, message: str, action: ReportAction, context: dict = None):
25
+ """
26
+ Report that a tool action is starting. This should be the first reporting call for every tool action.
27
+ """
28
+ self._event_bus.publish(
29
+ ReportEvent(
30
+ subtype=ReportSubtype.ACTION_INFO,
31
+ message=" " + message,
32
+ action=action,
33
+ tool=self.name,
34
+ context=context,
35
+ )
36
+ )
37
+
38
+ def report_info(self, message: str, context: dict = None):
39
+ self._event_bus.publish(
40
+ ReportEvent(
41
+ subtype=ReportSubtype.ACTION_INFO,
42
+ message=message,
43
+ action=None,
44
+ tool=self.name,
45
+ context=context,
46
+ )
47
+ )
48
+
49
+ def report_error(self, message: str, context: dict = None):
50
+ self._event_bus.publish(
51
+ ReportEvent(
52
+ subtype=ReportSubtype.ERROR,
53
+ message=message,
54
+ action=None,
55
+ tool=self.name,
56
+ context=context,
57
+ )
58
+ )
59
+
60
+ def report_success(self, message: str, context: dict = None):
61
+ self._event_bus.publish(
62
+ ReportEvent(
63
+ subtype=ReportSubtype.SUCCESS,
64
+ message=message,
65
+ action=None,
66
+ tool=self.name,
67
+ context=context,
68
+ )
69
+ )
70
+
71
+ def report_warning(self, message: str, context: dict = None):
72
+ self._event_bus.publish(
73
+ ReportEvent(
74
+ subtype=ReportSubtype.WARNING,
75
+ message=message,
76
+ action=None,
77
+ tool=self.name,
78
+ context=context,
79
+ )
80
+ )
81
+
82
+ def report_stdout(self, message: str, context: dict = None):
83
+ self._event_bus.publish(
84
+ ReportEvent(
85
+ subtype=ReportSubtype.STDOUT,
86
+ message=message,
87
+ action=None,
88
+ tool=self.name,
89
+ context=context,
90
+ )
91
+ )
92
+
93
+ def report_stderr(self, message: str, context: dict = None):
94
+ self._event_bus.publish(
95
+ ReportEvent(
96
+ subtype=ReportSubtype.STDERR,
97
+ message=message,
98
+ action=None,
99
+ tool=self.name,
100
+ context=context,
101
+ )
102
+ )
103
+
104
+ def run(self, *args, **kwargs):
105
+ raise NotImplementedError("Subclasses must implement the run method.")