janito 3.2.0__py3-none-any.whl → 3.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 (166) hide show
  1. janito/README.md +0 -3
  2. janito/cli/chat_mode/bindings.py +0 -26
  3. janito/cli/chat_mode/session.py +1 -12
  4. janito/cli/chat_mode/shell/commands/security/allowed_sites.py +33 -47
  5. janito/cli/cli_commands/list_plugins.py +8 -13
  6. janito/cli/core/model_guesser.py +24 -40
  7. janito/cli/prompt_core.py +9 -20
  8. janito/i18n/it.py +46 -46
  9. janito/llm/agent.py +16 -32
  10. janito/llm/driver.py +0 -8
  11. janito/{plugin_system → plugin_system_backup_20250825_070018}/core_loader.py +3 -76
  12. janito/{plugin_system → plugin_system_backup_20250825_070018}/core_loader_fixed.py +3 -79
  13. janito/plugins/__init__.py +21 -29
  14. janito/plugins/__main__.py +85 -0
  15. janito/plugins/base.py +57 -0
  16. janito/plugins/builtin.py +1 -1
  17. janito/plugins/core/filemanager/tools/copy_file.py +25 -1
  18. janito/plugins/core/filemanager/tools/create_directory.py +28 -1
  19. janito/plugins/core/filemanager/tools/create_file.py +27 -3
  20. janito/plugins/core/filemanager/tools/delete_text_in_file.py +1 -0
  21. janito/plugins/core/imagedisplay/plugin.py +1 -1
  22. janito/plugins/core_loader.py +144 -0
  23. janito/plugins/discovery.py +3 -3
  24. janito/plugins/example_plugin.py +1 -1
  25. janito/plugins/manager.py +1 -1
  26. janito/plugins_backup_20250825_070018/__init__.py +36 -0
  27. janito/{plugins → plugins_backup_20250825_070018}/auto_loader.py +11 -12
  28. janito/plugins_backup_20250825_070018/builtin.py +102 -0
  29. janito/plugins_backup_20250825_070018/config.py +84 -0
  30. janito/plugins_backup_20250825_070018/core/__init__.py +7 -0
  31. janito/plugins_backup_20250825_070018/core/codeanalyzer/__init__.py +43 -0
  32. janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/__init__.py +1 -0
  33. janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/core.py +122 -0
  34. janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/__init__.py +1 -0
  35. janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/core.py +205 -0
  36. janito/plugins_backup_20250825_070018/core/filemanager/__init__.py +124 -0
  37. janito/plugins_backup_20250825_070018/core/filemanager/tools/copy_file.py +87 -0
  38. janito/plugins_backup_20250825_070018/core/filemanager/tools/create_directory.py +70 -0
  39. janito/plugins_backup_20250825_070018/core/filemanager/tools/create_file.py +87 -0
  40. janito/plugins_backup_20250825_070018/core/filemanager/tools/delete_text_in_file.py +135 -0
  41. janito/plugins_backup_20250825_070018/core/filemanager/tools/find_files.py +143 -0
  42. janito/plugins_backup_20250825_070018/core/filemanager/tools/move_file.py +131 -0
  43. janito/plugins_backup_20250825_070018/core/filemanager/tools/read_files.py +58 -0
  44. janito/plugins_backup_20250825_070018/core/filemanager/tools/remove_directory.py +55 -0
  45. janito/plugins_backup_20250825_070018/core/filemanager/tools/remove_file.py +58 -0
  46. janito/plugins_backup_20250825_070018/core/filemanager/tools/replace_text_in_file.py +270 -0
  47. janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/__init__.py +1 -0
  48. janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/core.py +114 -0
  49. janito/plugins_backup_20250825_070018/core/filemanager/tools/view_file.py +172 -0
  50. janito/plugins_backup_20250825_070018/core/imagedisplay/__init__.py +14 -0
  51. janito/plugins_backup_20250825_070018/core/imagedisplay/plugin.py +51 -0
  52. janito/plugins_backup_20250825_070018/core/imagedisplay/tools/__init__.py +1 -0
  53. janito/plugins_backup_20250825_070018/core/imagedisplay/tools/show_image.py +83 -0
  54. janito/plugins_backup_20250825_070018/core/imagedisplay/tools/show_image_grid.py +84 -0
  55. janito/plugins_backup_20250825_070018/core/system/__init__.py +23 -0
  56. janito/plugins_backup_20250825_070018/core/system/tools/run_bash_command.py +183 -0
  57. janito/plugins_backup_20250825_070018/core/system/tools/run_powershell_command.py +218 -0
  58. janito/plugins_backup_20250825_070018/core_adapter.py +55 -0
  59. janito/plugins_backup_20250825_070018/dev/__init__.py +7 -0
  60. janito/plugins_backup_20250825_070018/dev/pythondev/__init__.py +37 -0
  61. janito/plugins_backup_20250825_070018/dev/pythondev/tools/python_code_run.py +172 -0
  62. janito/plugins_backup_20250825_070018/dev/pythondev/tools/python_command_run.py +171 -0
  63. janito/plugins_backup_20250825_070018/dev/pythondev/tools/python_file_run.py +172 -0
  64. janito/plugins_backup_20250825_070018/dev/visualization/__init__.py +23 -0
  65. janito/plugins_backup_20250825_070018/dev/visualization/tools/read_chart.py +259 -0
  66. janito/plugins_backup_20250825_070018/discovery.py +289 -0
  67. janito/{plugins → plugins_backup_20250825_070018}/discovery_core.py +9 -14
  68. janito/plugins_backup_20250825_070018/example_plugin.py +108 -0
  69. janito/plugins_backup_20250825_070018/manager.py +243 -0
  70. janito/{plugins → plugins_backup_20250825_070018}/tools/core_tools_plugin.py +10 -9
  71. janito/{plugins → plugins_backup_20250825_070018}/tools/create_file.py +2 -2
  72. janito/{plugins → plugins_backup_20250825_070018}/tools/delete_text_in_file.py +1 -0
  73. janito/plugins_backup_20250825_070018/tools/get_file_outline/java_outline.py +47 -0
  74. janito/plugins_backup_20250825_070018/tools/get_file_outline/markdown_outline.py +14 -0
  75. janito/plugins_backup_20250825_070018/tools/get_file_outline/python_outline.py +303 -0
  76. janito/plugins_backup_20250825_070018/tools/get_file_outline/search_outline.py +36 -0
  77. janito/plugins_backup_20250825_070018/tools/search_text/match_lines.py +67 -0
  78. janito/plugins_backup_20250825_070018/tools/search_text/pattern_utils.py +73 -0
  79. janito/plugins_backup_20250825_070018/tools/search_text/traverse_directory.py +145 -0
  80. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/css_validator.py +35 -0
  81. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/html_validator.py +100 -0
  82. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/jinja2_validator.py +50 -0
  83. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/js_validator.py +27 -0
  84. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/json_validator.py +6 -0
  85. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/markdown_validator.py +109 -0
  86. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/ps1_validator.py +32 -0
  87. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/python_validator.py +5 -0
  88. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/xml_validator.py +11 -0
  89. janito/plugins_backup_20250825_070018/tools/validate_file_syntax/yaml_validator.py +6 -0
  90. janito/plugins_backup_20250825_070018/ui/__init__.py +7 -0
  91. janito/plugins_backup_20250825_070018/ui/userinterface/__init__.py +16 -0
  92. janito/plugins_backup_20250825_070018/ui/userinterface/tools/ask_user.py +110 -0
  93. janito/plugins_backup_20250825_070018/web/__init__.py +7 -0
  94. janito/plugins_backup_20250825_070018/web/webtools/__init__.py +33 -0
  95. janito/plugins_backup_20250825_070018/web/webtools/tools/fetch_url.py +458 -0
  96. janito/plugins_backup_20250825_070018/web/webtools/tools/open_html_in_browser.py +51 -0
  97. janito/plugins_backup_20250825_070018/web/webtools/tools/open_url.py +37 -0
  98. janito/providers/__init__.py +0 -1
  99. janito/tools/base.py +31 -1
  100. janito/tools/cli_initializer.py +1 -1
  101. janito/tools/function_adapter.py +176 -0
  102. janito/tools/initialize.py +1 -1
  103. janito/tools/loop_protection_decorator.py +117 -114
  104. janito/tools/tool_base.py +142 -114
  105. janito/tools/tools_schema.py +12 -6
  106. {janito-3.2.0.dist-info → janito-3.3.0.dist-info}/METADATA +1 -1
  107. {janito-3.2.0.dist-info → janito-3.3.0.dist-info}/RECORD +160 -95
  108. janito/llm/cancellation_manager.py +0 -63
  109. janito/llm/enter_cancellation.py +0 -107
  110. janito/plugins/core_adapter.py +0 -131
  111. janito/providers/together/__init__.py +0 -1
  112. janito/providers/together/model_info.py +0 -69
  113. janito/providers/together/provider.py +0 -108
  114. /janito/{plugin_system → plugin_system_backup_20250825_070018}/__init__.py +0 -0
  115. /janito/{plugin_system → plugin_system_backup_20250825_070018}/base.py +0 -0
  116. /janito/{plugins → plugins_backup_20250825_070018}/auto_loader_fixed.py +0 -0
  117. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/get_file_outline/java_outline.py +0 -0
  118. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/get_file_outline/markdown_outline.py +0 -0
  119. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/get_file_outline/python_outline.py +0 -0
  120. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/get_file_outline/search_outline.py +0 -0
  121. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/search_text/match_lines.py +0 -0
  122. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/search_text/pattern_utils.py +0 -0
  123. /janito/{plugins → plugins_backup_20250825_070018/core/codeanalyzer}/tools/search_text/traverse_directory.py +0 -0
  124. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/css_validator.py +0 -0
  125. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/html_validator.py +0 -0
  126. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/jinja2_validator.py +0 -0
  127. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/js_validator.py +0 -0
  128. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/json_validator.py +0 -0
  129. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/markdown_validator.py +0 -0
  130. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/ps1_validator.py +0 -0
  131. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/python_validator.py +0 -0
  132. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/xml_validator.py +0 -0
  133. /janito/{plugins → plugins_backup_20250825_070018/core/filemanager}/tools/validate_file_syntax/yaml_validator.py +0 -0
  134. /janito/{plugins → plugins_backup_20250825_070018}/tools/__init__.py +0 -0
  135. /janito/{plugins → plugins_backup_20250825_070018}/tools/ask_user.py +0 -0
  136. /janito/{plugins → plugins_backup_20250825_070018}/tools/copy_file.py +0 -0
  137. /janito/{plugins → plugins_backup_20250825_070018}/tools/create_directory.py +0 -0
  138. /janito/{plugins → plugins_backup_20250825_070018}/tools/decorators.py +0 -0
  139. /janito/{plugins → plugins_backup_20250825_070018}/tools/fetch_url.py +0 -0
  140. /janito/{plugins → plugins_backup_20250825_070018}/tools/find_files.py +0 -0
  141. /janito/{plugins → plugins_backup_20250825_070018}/tools/get_file_outline/__init__.py +0 -0
  142. /janito/{plugins → plugins_backup_20250825_070018}/tools/get_file_outline/core.py +0 -0
  143. /janito/{plugins → plugins_backup_20250825_070018}/tools/move_file.py +0 -0
  144. /janito/{plugins → plugins_backup_20250825_070018}/tools/open_html_in_browser.py +0 -0
  145. /janito/{plugins → plugins_backup_20250825_070018}/tools/open_url.py +0 -0
  146. /janito/{plugins → plugins_backup_20250825_070018}/tools/python_code_run.py +0 -0
  147. /janito/{plugins → plugins_backup_20250825_070018}/tools/python_command_run.py +0 -0
  148. /janito/{plugins → plugins_backup_20250825_070018}/tools/python_file_run.py +0 -0
  149. /janito/{plugins → plugins_backup_20250825_070018}/tools/read_chart.py +0 -0
  150. /janito/{plugins → plugins_backup_20250825_070018}/tools/read_files.py +0 -0
  151. /janito/{plugins → plugins_backup_20250825_070018}/tools/remove_directory.py +0 -0
  152. /janito/{plugins → plugins_backup_20250825_070018}/tools/remove_file.py +0 -0
  153. /janito/{plugins → plugins_backup_20250825_070018}/tools/replace_text_in_file.py +0 -0
  154. /janito/{plugins → plugins_backup_20250825_070018}/tools/run_bash_command.py +0 -0
  155. /janito/{plugins → plugins_backup_20250825_070018}/tools/run_powershell_command.py +0 -0
  156. /janito/{plugins → plugins_backup_20250825_070018}/tools/search_text/__init__.py +0 -0
  157. /janito/{plugins → plugins_backup_20250825_070018}/tools/search_text/core.py +0 -0
  158. /janito/{plugins → plugins_backup_20250825_070018}/tools/show_image.py +0 -0
  159. /janito/{plugins → plugins_backup_20250825_070018}/tools/show_image_grid.py +0 -0
  160. /janito/{plugins → plugins_backup_20250825_070018}/tools/validate_file_syntax/__init__.py +0 -0
  161. /janito/{plugins → plugins_backup_20250825_070018}/tools/validate_file_syntax/core.py +0 -0
  162. /janito/{plugins → plugins_backup_20250825_070018}/tools/view_file.py +0 -0
  163. {janito-3.2.0.dist-info → janito-3.3.0.dist-info}/WHEEL +0 -0
  164. {janito-3.2.0.dist-info → janito-3.3.0.dist-info}/entry_points.txt +0 -0
  165. {janito-3.2.0.dist-info → janito-3.3.0.dist-info}/licenses/LICENSE +0 -0
  166. {janito-3.2.0.dist-info → janito-3.3.0.dist-info}/top_level.txt +0 -0
janito/README.md CHANGED
@@ -106,9 +106,6 @@ janito --set model=kimi-k1-8k
106
106
 
107
107
  ## Advanced Features
108
108
 
109
- ### 🚀 New in v3.1.0: Enter Key Cancellation
110
- **Chat Mode Enhancement**: Press **Enter** at any time to instantly cancel long-running requests in interactive chat mode. No more waiting for stuck requests!
111
-
112
109
  ### Tool Usage
113
110
 
114
111
  Janito includes powerful built-in tools for:
@@ -35,30 +35,4 @@ class KeyBindingsFactory:
35
35
  buf.text = "Do It"
36
36
  buf.validate_and_handle()
37
37
 
38
- @bindings.add("c-c")
39
- def _(event):
40
- """Handle Ctrl+C to interrupt current request or exit chat."""
41
- # Use global cancellation manager for robust cancellation
42
- from janito.llm.cancellation_manager import get_cancellation_manager
43
-
44
- cancel_manager = get_cancellation_manager()
45
-
46
- cancelled = cancel_manager.cancel_current_request()
47
- if cancelled:
48
- # Provide user feedback
49
- from rich.console import Console
50
-
51
- console = Console()
52
- console.print("[red]Request cancelled by Ctrl+C[/red]")
53
-
54
- # Prevent the Ctrl+C from being processed as input
55
- event.app.output.flush()
56
- return
57
- else:
58
- # No active request to cancel, exit the chat
59
- from rich.console import Console
60
- console = Console()
61
- console.print("[yellow]Goodbye![/yellow]")
62
- event.app.exit()
63
-
64
38
  return bindings
@@ -22,7 +22,6 @@ import time
22
22
 
23
23
  # Shared prompt/agent factory
24
24
  from janito.cli.prompt_setup import setup_agent_and_prompt_handler
25
- from janito.llm.cancellation_manager import get_cancellation_manager
26
25
 
27
26
  import time
28
27
 
@@ -114,10 +113,6 @@ class ChatSession:
114
113
 
115
114
  # Check if multi-line mode should be enabled by default
116
115
  self.multi_line_mode = getattr(args, "multi", False) if args else False
117
-
118
- # Default to single-line mode (Enter submits) unless explicitly enabled
119
- if not self.multi_line_mode:
120
- self.multi_line_mode = False
121
116
 
122
117
  def _select_profile_and_role(self, args, role):
123
118
  profile, role_arg, python_profile, market_profile = self._extract_args(args)
@@ -288,13 +283,7 @@ class ChatSession:
288
283
  )
289
284
  )
290
285
 
291
- try:
292
- self._prompt_handler.run_prompt(cmd_input)
293
- finally:
294
- # Ensure cancellation manager is cleared
295
- cancel_manager = get_cancellation_manager()
296
- cancel_manager.clear_current_request()
297
-
286
+ self._prompt_handler.run_prompt(cmd_input)
298
287
  end_time = time.time()
299
288
  elapsed = end_time - start_time
300
289
  self.msg_count += 1
@@ -59,53 +59,39 @@ Examples:
59
59
  command = args[0].lower()
60
60
  whitelist_manager = get_url_whitelist_manager()
61
61
 
62
- handlers = {
63
- "list": self._handle_list,
64
- "add": self._handle_add,
65
- "remove": self._handle_remove,
66
- "clear": self._handle_clear,
67
- }
68
-
69
- handler = handlers.get(command)
70
- if handler:
71
- handler(args, whitelist_manager)
62
+ if command == "list":
63
+ sites = whitelist_manager.get_allowed_sites()
64
+ if sites:
65
+ print("Allowed sites:")
66
+ for site in sites:
67
+ print(f" • {site}")
68
+ else:
69
+ print("No sites are whitelisted (all sites are allowed)")
70
+
71
+ elif command == "add":
72
+ if len(args) < 2:
73
+ print("Error: Please specify a site to add")
74
+ return
75
+ site = args[1]
76
+ if whitelist_manager.add_allowed_site(site):
77
+ print(f"✅ Added '{site}' to allowed sites")
78
+ else:
79
+ print(f"ℹ️ '{site}' is already in allowed sites")
80
+
81
+ elif command == "remove":
82
+ if len(args) < 2:
83
+ print("Error: Please specify a site to remove")
84
+ return
85
+ site = args[1]
86
+ if whitelist_manager.remove_allowed_site(site):
87
+ print(f"✅ Removed '{site}' from allowed sites")
88
+ else:
89
+ print(f"ℹ️ '{site}' was not in allowed sites")
90
+
91
+ elif command == "clear":
92
+ whitelist_manager.clear_whitelist()
93
+ print("✅ Cleared all allowed sites (all sites are now allowed)")
94
+
72
95
  else:
73
96
  print(f"Error: Unknown command '{command}'")
74
97
  print(self.get_usage())
75
-
76
- def _handle_list(self, args, whitelist_manager):
77
- """Handle list command."""
78
- sites = whitelist_manager.get_allowed_sites()
79
- if sites:
80
- print("Allowed sites:")
81
- for site in sites:
82
- print(f" • {site}")
83
- else:
84
- print("No sites are whitelisted (all sites are allowed)")
85
-
86
- def _handle_add(self, args, whitelist_manager):
87
- """Handle add command."""
88
- if len(args) < 2:
89
- print("Error: Please specify a site to add")
90
- return
91
- site = args[1]
92
- if whitelist_manager.add_allowed_site(site):
93
- print(f"✅ Added '{site}' to allowed sites")
94
- else:
95
- print(f"ℹ️ '{site}' is already in allowed sites")
96
-
97
- def _handle_remove(self, args, whitelist_manager):
98
- """Handle remove command."""
99
- if len(args) < 2:
100
- print("Error: Please specify a site to remove")
101
- return
102
- site = args[1]
103
- if whitelist_manager.remove_allowed_site(site):
104
- print(f"✅ Removed '{site}' from allowed sites")
105
- else:
106
- print(f"ℹ️ '{site}' was not in allowed sites")
107
-
108
- def _handle_clear(self, args, whitelist_manager):
109
- """Handle clear command."""
110
- whitelist_manager.clear_whitelist()
111
- print("✅ Cleared all allowed sites (all sites are now allowed)")
@@ -8,11 +8,8 @@ from janito.plugins.discovery import list_available_plugins
8
8
  import os
9
9
  from janito.plugins.manager import PluginManager
10
10
  from janito.plugins.builtin import BuiltinPluginRegistry
11
- from janito.plugins.auto_loader_fixed import (
12
- load_core_plugins,
13
- get_loaded_core_plugins,
14
- is_core_plugin,
15
- )
11
+ from janito.plugins.manager import PluginManager
12
+ from janito.plugins.core_loader import get_core_plugins
16
13
  from rich.console import Console
17
14
  from rich.table import Table
18
15
  from rich.panel import Panel
@@ -55,7 +52,7 @@ def _list_available_plugins():
55
52
  console.print(table)
56
53
 
57
54
  # Show core plugins
58
- from janito.plugin_system.core_loader_fixed import get_core_plugins
55
+ from janito.plugins.core_loader import get_core_plugins
59
56
 
60
57
  core_plugins = get_core_plugins()
61
58
  core_table = Table(title="Core Plugins (Enabled by Default)")
@@ -98,10 +95,8 @@ def _print_external_plugins(available, builtin_plugins):
98
95
 
99
96
  def _list_plugin_resources():
100
97
  """List all resources from loaded plugins using rich formatting."""
101
- from janito.plugins.auto_loader_fixed import get_plugin_manager
102
-
103
98
  console = Console()
104
- manager = get_plugin_manager()
99
+ manager = PluginManager()
105
100
  all_resources = manager.list_all_resources()
106
101
 
107
102
  if all_resources:
@@ -174,10 +169,8 @@ def _print_resources_by_type(resources):
174
169
 
175
170
  def _list_loaded_plugins():
176
171
  """List loaded plugins using rich formatting."""
177
- from janito.plugins.auto_loader_fixed import get_plugin_manager
178
-
179
172
  console = Console()
180
- manager = get_plugin_manager()
173
+ manager = PluginManager()
181
174
  loaded = manager.list_plugins()
182
175
 
183
176
  if loaded:
@@ -192,7 +185,9 @@ def _list_loaded_plugins():
192
185
  other_plugins = []
193
186
 
194
187
  for plugin_name in loaded:
195
- if is_core_plugin(plugin_name):
188
+ from janito.plugins.core_loader import get_core_plugins
189
+ core_plugin_list = get_core_plugins()
190
+ if plugin_name in core_plugin_list:
196
191
  core_plugins.append(plugin_name)
197
192
  else:
198
193
  other_plugins.append(plugin_name)
@@ -21,50 +21,34 @@ def guess_provider_from_model(model_name: str) -> str:
21
21
  model_name = model_name.lower()
22
22
 
23
23
  # Check each provider's models
24
- return _find_provider_for_model(model_name)
25
-
26
-
27
- def _find_provider_for_model(model_name: str) -> str:
28
- """Find provider for given model name."""
29
24
  for provider_name in LLMProviderRegistry.list_providers():
30
25
  provider_class = LLMProviderRegistry.get(provider_name)
31
26
  if not provider_class:
32
27
  continue
33
28
 
34
- if _check_provider_models(provider_name, provider_class, model_name):
35
- return provider_name
29
+ # Get model specs for this provider
30
+ try:
31
+ if hasattr(provider_class, "MODEL_SPECS"):
32
+ model_specs = provider_class.MODEL_SPECS
33
+ for spec_model_name in model_specs.keys():
34
+ if spec_model_name.lower() == model_name:
35
+ return provider_name
36
+
37
+ # Handle special cases like moonshot
38
+ if provider_name == "moonshot":
39
+ try:
40
+ from janito.providers.moonshot.model_info import (
41
+ MOONSHOT_MODEL_SPECS,
42
+ )
43
+
44
+ for spec_model_name in MOONSHOT_MODEL_SPECS.keys():
45
+ if spec_model_name.lower() == model_name:
46
+ return "moonshot"
47
+ except ImportError:
48
+ pass
49
+
50
+ except Exception:
51
+ # Skip providers that have issues accessing model specs
52
+ continue
36
53
 
37
54
  return None
38
-
39
-
40
- def _check_provider_models(provider_name: str, provider_class, model_name: str) -> bool:
41
- """Check if provider has matching model."""
42
- try:
43
- if hasattr(provider_class, "MODEL_SPECS"):
44
- model_specs = provider_class.MODEL_SPECS
45
- for spec_model_name in model_specs.keys():
46
- if spec_model_name.lower() == model_name:
47
- return True
48
-
49
- # Handle special cases like moonshot
50
- if provider_name == "moonshot":
51
- return _check_moonshot_models(model_name)
52
-
53
- except Exception:
54
- # Skip providers that have issues accessing model specs
55
- pass
56
-
57
- return False
58
-
59
-
60
- def _check_moonshot_models(model_name: str) -> bool:
61
- """Check moonshot models specifically."""
62
- try:
63
- from janito.providers.moonshot.model_info import MOONSHOT_MODEL_SPECS
64
-
65
- for spec_model_name in MOONSHOT_MODEL_SPECS.keys():
66
- if spec_model_name.lower() == model_name:
67
- return True
68
- except ImportError:
69
- pass
70
- return False
janito/cli/prompt_core.py CHANGED
@@ -207,26 +207,15 @@ class PromptHandler:
207
207
  """
208
208
  try:
209
209
  self._print_verbose_debug("Calling agent.chat()...")
210
-
211
- # Use global cancellation manager
212
- from janito.llm.cancellation_manager import get_cancellation_manager
213
-
214
- cancel_manager = get_cancellation_manager()
215
- driver_cancel_event = cancel_manager.start_new_request()
216
-
217
- try:
218
- final_event = self.agent.chat(prompt=user_prompt)
219
- if hasattr(self.agent, "set_latest_event"):
220
- self.agent.set_latest_event(final_event)
221
- self.agent.last_event = final_event
222
- self._print_verbose_debug(f"agent.chat() returned: {final_event}")
223
- self._print_verbose_final_event(final_event)
224
- if on_event and final_event is not None:
225
- on_event(final_event)
226
- global_event_bus.publish(final_event)
227
- finally:
228
- cancel_manager.clear_current_request()
229
-
210
+ final_event = self.agent.chat(prompt=user_prompt)
211
+ if hasattr(self.agent, "set_latest_event"):
212
+ self.agent.set_latest_event(final_event)
213
+ self.agent.last_event = final_event
214
+ self._print_verbose_debug(f"agent.chat() returned: {final_event}")
215
+ self._print_verbose_final_event(final_event)
216
+ if on_event and final_event is not None:
217
+ on_event(final_event)
218
+ global_event_bus.publish(final_event)
230
219
  except KeyboardInterrupt:
231
220
  # Capture user interrupt / cancellation
232
221
  self.console.print("[red]Interrupted by the user.[/red]")
janito/i18n/it.py CHANGED
@@ -1,46 +1,46 @@
1
- # pragma: allowlist secret
2
- translations = {
3
- "36107ed78ab25f6fb12ad8ce13018cd1ce6735d1": "Avvio del server web...",
4
- "70a0d194687568a47aa617fd85036ace1e69a982": "Vuoi davvero uscire? (s/n): ",
5
- "5c9ebcbbd7632ecb328bd52958b17158afaa32c6": "F12 = Azione Rapida (segue l'azione raccomandata)",
6
- "fe21121e2934234b68d19b2757532117d440c1e3": "Chiave API non trovata. Si prega di configurare 'api_key' nel file di configurazione.",
7
- "c9e3759b1756eba35b381ce2b72cd659e132b01f": "Ciao, {name}!",
8
- "ca1fee2f55baabdc2e4b0e9529c89ee024e62079": "Nessun prompt fornito nei messaggi",
9
- "f7449d23d0c500ae2a0b31e04f92b47a4d8ae845": "max_tokens deve essere un intero, ricevuto: {resolved_max_tokens!r}",
10
- "70a9ed8edb6da12e208431a31aa16ba54419b26f": "Risposta non valida/malformed da OpenAI (tentativo {attempt}/{max_retries}). Riprovo tra {wait_time} secondi...",
11
- "a873085e3b06184fb5d27e842f97b06b6190976d": "Numero massimo di tentativi per risposta non valida raggiunto. Generazione errore.",
12
- "66a34568bbe846bb1bde3619eb4d6dfa10211104": "L'API non supporta l'uso degli strumenti.",
13
- "09b81476b75586da4116b83f8be70d77b174cec3": "Limit di richieste API OpenAI (429) (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
14
- "5717a35dd2a1533fb7e15edc8c9329cb69f3410b": "Errore server API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
15
- "02e760ba15ed863176c1290ac8a9b923963103cd": "Errore client API OpenAI {status_code}: {e}. Nessun nuovo tentativo.",
16
- "2e52b0bbc8f16226b70e3e20f95c9245d2bcdb47": "Errore API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
17
- "012cc970e039fdd79c452fc676202c814ffc76ae": "Numero massimo di tentativi per errore API OpenAI raggiunto. Generazione errore.",
18
- "d0438e45667d31e0022b2497b5901cd4300f084b": "QueuedMessageHandler.handle_message si aspetta un dizionario con 'type' e 'message', ricevuto {msg_type}: {msg!r}",
19
- "9d3460187ffa19c7c8a4020157072b1087e1bd2f": "[QueuedMessageHandler] {msg_type}: {msg}",
20
- "3813833343430e8afa8fce33385c5e39fb24dd60": "[QueuedMessageHandler] {msg_type}: {message}",
21
- "0be9a22226e16a40797010d23a0f581542dca40e": "[ToolExecutor] {tool_name} chiamato con argomenti: {args}",
22
- "42c68edcb25442f518b1af77c6a2ddc07461aae0": "[ToolExecutor] Motivo chiamata: {tool_call_reason}",
23
- "002ff598115d84595ffeee6219cb5c03d3a1d4a6": "Domanda",
24
- "35747d13dcd91e8e8790c7f767d5ed764f541b9e": "procedi",
25
- "33dde3a1afbc418768a69fa53168d9b0638fe1aa": "avanti",
26
- "eee0bbba4ff92adbeb038a77df0466d660f15716": "continua",
27
- "edee9402d198b04ac77dcf5dc9cc3dac44573782": "prossimo",
28
- "8fdb7e2fa84f4faf0d9b92f466df424ec47a165b": "ok",
29
- "5f8f924671cda79b5205a6bf1b776f347c4a7a07": "Opzioni di configurazione disponibili:\n",
30
- "cef780a309cd234750764d42697882c24168ddab": "{key:15} {desc} (predefinito: {default})",
31
- "68c2cc7f0ceaa3e499ecb4db331feb4debbbcc23": "Modello",
32
- "c3f104d1365744b538bfde9f4adb6a6df4b80355": "Funzione",
33
- "99a0efc6cfd85d8ff2732a6718140f822cb90472": "Stile",
34
- "f1702b4686278becffc88baabe6f4b7a8355532c": "Messaggi",
35
- "c38c6c1f3a2743f8626703abb302e403d20ff81c": "Token",
36
- "a817d7eb8e0f1dab755ab5203a082e5c3c094fce": "Prompt",
37
- "2ff255684a2277f806fcebf3fe338ed27857f350": "Completamento",
38
- "b25928c69902557b0ef0a628490a3a1768d7b82f": "Totale",
39
- "76e63d65c883ed50df40ac3aeef0c2d6a1c4ad60": "Azione Rapida",
40
- "5397e0583f14f6c88de06b1ef28f460a1fb5b0ae": "Sì",
41
- "816c52fd2bdd94a63cd0944823a6c0aa9384c103": "No",
42
- "c47ae15370cfe1ed2781eedc1dc2547d12d9e972": "Aiuto",
43
- "cc3dbd47e1cf9003a55d3366b3adbcd72275e525": "Nuovo Task",
44
- "efa5a8b84e1afe65c81ecfce28c398c48f19ddc2": "Benvenuto su Janito{version_str}! Modalità chat attiva. Digita /exit per uscire.",
45
- "b314d6e1460f86e0f21abc5aceb7935a2a0667e8": "Benvenuto su Janito{version_str} in modalità [white on magenta]VANILLA[/white on magenta]! Strumenti, prompt di sistema e temperatura sono disattivati, a meno che non siano sovrascritti.",
46
- }
1
+ # pragma: allowlist secret
2
+ translations = {
3
+ "36107ed78ab25f6fb12ad8ce13018cd1ce6735d1": "Avvio del server web...",
4
+ "70a0d194687568a47aa617fd85036ace1e69a982": "Vuoi davvero uscire? (s/n): ",
5
+ "5c9ebcbbd7632ecb328bd52958b17158afaa32c6": "F12 = Azione Rapida (segue l'azione raccomandata)",
6
+ "fe21121e2934234b68d19b2757532117d440c1e3": "Chiave API non trovata. Si prega di configurare 'api_key' nel file di configurazione.",
7
+ "c9e3759b1756eba35b381ce2b72cd659e132b01f": "Ciao, {name}!",
8
+ "ca1fee2f55baabdc2e4b0e9529c89ee024e62079": "Nessun prompt fornito nei messaggi",
9
+ "f7449d23d0c500ae2a0b31e04f92b47a4d8ae845": "max_tokens deve essere un intero, ricevuto: {resolved_max_tokens!r}",
10
+ "70a9ed8edb6da12e208431a31aa16ba54419b26f": "Risposta non valida/malformed da OpenAI (tentativo {attempt}/{max_retries}). Riprovo tra {wait_time} secondi...",
11
+ "a873085e3b06184fb5d27e842f97b06b6190976d": "Numero massimo di tentativi per risposta non valida raggiunto. Generazione errore.",
12
+ "66a34568bbe846bb1bde3619eb4d6dfa10211104": "L'API non supporta l'uso degli strumenti.",
13
+ "09b81476b75586da4116b83f8be70d77b174cec3": "Limite di richieste API OpenAI (429) (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
14
+ "5717a35dd2a1533fb7e15edc8c9329cb69f3410b": "Errore server API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
15
+ "02e760ba15ed863176c1290ac8a9b923963103cd": "Errore client API OpenAI {status_code}: {e}. Nessun nuovo tentativo.",
16
+ "2e52b0bbc8f16226b70e3e20f95c9245d2bcdb47": "Errore API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
17
+ "012cc970e039fdd79c452fc676202c814ffc76ae": "Numero massimo di tentativi per errore API OpenAI raggiunto. Generazione errore.",
18
+ "d0438e45667d31e0022b2497b5901cd4300f084b": "QueuedMessageHandler.handle_message si aspetta un dizionario con 'type' e 'message', ricevuto {msg_type}: {msg!r}",
19
+ "9d3460187ffa19c7c8a4020157072b1087e1bd2f": "[QueuedMessageHandler] {msg_type}: {msg}",
20
+ "3813833343430e8afa8fce33385c5e39fb24dd60": "[QueuedMessageHandler] {msg_type}: {message}",
21
+ "0be9a22226e16a40797010d23a0f581542dca40e": "[ToolExecutor] {tool_name} chiamato con argomenti: {args}",
22
+ "42c68edcb25442f518b1af77c6a2ddc07461aae0": "[ToolExecutor] Motivo chiamata: {tool_call_reason}",
23
+ "002ff598115d84595ffeee6219cb5c03d3a1d4a6": "Domanda",
24
+ "35747d13dcd91e8e8790c7f767d5ed764f541b9e": "procedi",
25
+ "33dde3a1afbc418768a69fa53168d9b0638fe1aa": "avanti",
26
+ "eee0bbba4ff92adbeb038a77df0466d660f15716": "continua",
27
+ "edee9402d198b04ac77dcf5dc9cc3dac44573782": "prossimo",
28
+ "8fdb7e2fa84f4faf0d9b92f466df424ec47a165b": "ok",
29
+ "5f8f924671cda79b5205a6bf1b776f347c4a7a07": "Opzioni di configurazione disponibili:\n",
30
+ "cef780a309cd234750764d42697882c24168ddab": "{key:15} {desc} (predefinito: {default})",
31
+ "68c2cc7f0ceaa3e499ecb4db331feb4debbbcc23": "Modello",
32
+ "c3f104d1365744b538bfde9f4adb6a6df4b80355": "Funzione",
33
+ "99a0efc6cfd85d8ff2732a6718140f822cb90472": "Stile",
34
+ "f1702b4686278becffc88baabe6f4b7a8355532c": "Messaggi",
35
+ "c38c6c1f3a2743f8626703abb302e403d20ff81c": "Token",
36
+ "a817d7eb8e0f1dab755ab5203a082e5c3c094fce": "Prompt",
37
+ "2ff255684a2277f806fcebf3fe338ed27857f350": "Completamento",
38
+ "b25928c69902557b0ef0a628490a3a1768d7b82f": "Totale",
39
+ "76e63d65c883ed50df40ac3aeef0c2d6a1c4ad60": "Azione Rapida",
40
+ "5397e0583f14f6c88de06b1ef28f460a1fb5b0ae": "Sì",
41
+ "816c52fd2bdd94a63cd0944823a6c0aa9384c103": "No",
42
+ "c47ae15370cfe1ed2781eedc1dc2547d12d9e972": "Aiuto",
43
+ "cc3dbd47e1cf9003a55d3366b3adbcd72275e525": "Nuovo Task",
44
+ "efa5a8b84e1afe65c81ecfce28c398c48f19ddc2": "Benvenuto su Janito{version_str}! Modalità chat attiva. Digita /exit per uscire.",
45
+ "b314d6e1460f86e0f21abc5aceb7935a2a0667e8": "Benvenuto su Janito{version_str} in modalità [white on magenta]VANILLA[/white on magenta]! Strumenti, prompt di sistema e temperatura sono disattivati, a meno che non siano sovrascritti.",
46
+ }
janito/llm/agent.py CHANGED
@@ -318,39 +318,23 @@ class LLMAgent:
318
318
  loop_count = 1
319
319
  import threading
320
320
 
321
- # Use global cancellation manager
322
- from janito.llm.cancellation_manager import get_cancellation_manager
323
-
324
- cancel_manager = get_cancellation_manager()
325
- driver_cancel_event = cancel_manager.start_new_request()
326
-
327
- # Store cancellation event on agent for external access
328
- self.cancel_event = driver_cancel_event
329
-
330
- try:
331
- while True:
332
- self._print_verbose_chat_loop(loop_count)
333
- driver_input = self._prepare_driver_input(
334
- config, cancel_event=driver_cancel_event
321
+ cancel_event = threading.Event()
322
+ while True:
323
+ self._print_verbose_chat_loop(loop_count)
324
+ driver_input = self._prepare_driver_input(config, cancel_event=cancel_event)
325
+ self.input_queue.put(driver_input)
326
+ try:
327
+ result, added_tool_results = self._process_next_response()
328
+ except KeyboardInterrupt:
329
+ cancel_event.set()
330
+ raise
331
+ if getattr(self, "verbose_agent", False):
332
+ print(
333
+ f"[agent] [DEBUG] Returned from _process_next_response: result={result}, added_tool_results={added_tool_results}"
335
334
  )
336
- self.input_queue.put(driver_input)
337
- try:
338
- result, added_tool_results = self._process_next_response()
339
- except KeyboardInterrupt:
340
- cancel_manager.cancel_current_request()
341
- raise
342
- if getattr(self, "verbose_agent", False):
343
- print(
344
- f"[agent] [DEBUG] Returned from _process_next_response: result={result}, added_tool_results={added_tool_results}"
345
- )
346
- if self._should_exit_chat_loop(result, added_tool_results):
347
- return result
348
- loop_count += 1
349
- finally:
350
- cancel_manager.clear_current_request()
351
- # Clean up cancellation event
352
- if hasattr(self, "cancel_event"):
353
- delattr(self, "cancel_event")
335
+ if self._should_exit_chat_loop(result, added_tool_results):
336
+ return result
337
+ loop_count += 1
354
338
 
355
339
  def _clear_driver_queues(self):
356
340
  if hasattr(self, "driver") and self.driver:
janito/llm/driver.py CHANGED
@@ -252,11 +252,3 @@ class LLMDriver(ABC):
252
252
  def _get_message_from_result(self, result):
253
253
  """Extract the message object from the provider result. Subclasses must implement this."""
254
254
  raise NotImplementedError("Subclasses must implement _get_message_from_result.")
255
-
256
- def cancel_current_request(self):
257
- """Cancel the current request being processed."""
258
- # Use global cancellation manager to cancel the current request
259
- from janito.llm.cancellation_manager import get_cancellation_manager
260
-
261
- cancel_manager = get_cancellation_manager()
262
- cancel_manager.cancel_current_request()
@@ -12,7 +12,8 @@ from pathlib import Path
12
12
  from typing import Optional, List, Type
13
13
 
14
14
  from janito.plugin_system.base import Plugin, PluginMetadata
15
- from janito.tools.tool_base import ToolBase, ToolPermissions
15
+ from janito.tools.function_adapter import create_function_tool
16
+ from janito.tools.tool_base import ToolBase
16
17
 
17
18
 
18
19
  class CorePlugin(Plugin):
@@ -37,86 +38,12 @@ class CorePlugin(Plugin):
37
38
  def get_tools(self) -> List[Type[ToolBase]]:
38
39
  return self._tool_classes
39
40
 
40
- def _create_tool_class(self, func):
41
- """Create a ToolBase class from a function."""
42
- resolved_tool_name = getattr(func, "tool_name", func.__name__)
43
-
44
- # Create a proper tool class with explicit parameters and documentation
45
- import inspect
46
- from typing import get_type_hints
47
-
48
- func_sig = inspect.signature(func)
49
- type_hints = get_type_hints(func)
50
-
51
- # Build parameter definitions for the run method
52
- param_defs = []
53
- param_docs = []
54
- for name, param in func_sig.parameters.items():
55
- type_hint = type_hints.get(name, str)
56
- if param.default == inspect.Parameter.empty:
57
- param_defs.append(f"{name}: {type_hint.__name__}")
58
- else:
59
- param_defs.append(f"{name}: {type_hint.__name__} = {repr(param.default)}")
60
-
61
- # Add parameter documentation
62
- param_docs.append(f" {name}: {type_hint.__name__} - Parameter {name}")
63
-
64
- # Get function docstring or create one
65
- func_doc = func.__doc__ or f"Execute {resolved_tool_name} tool"
66
-
67
- # Create the tool class with proper signature and documentation
68
- exec_globals = {
69
- 'ToolBase': ToolBase,
70
- 'ToolPermissions': ToolPermissions,
71
- 'func': func,
72
- 'inspect': inspect,
73
- 'str': str,
74
- }
75
-
76
- param_docs_str = '\n'.join(param_docs)
77
-
78
- class_def = f'''
79
- class DynamicTool(ToolBase):
80
- """
81
- {func_doc}
82
-
83
- Parameters:
84
- {param_docs_str}
85
-
86
- Returns:
87
- str: Execution result
88
- """
89
- tool_name = "{resolved_tool_name}"
90
- permissions = ToolPermissions(read=True, write=True, execute=True)
91
-
92
- def __init__(self):
93
- super().__init__()
94
-
95
- def run(self, {', '.join(param_defs)}) -> str:
96
- kwargs = locals()
97
- sig = inspect.signature(func)
98
-
99
- # Filter kwargs to only include parameters the function accepts
100
- filtered_kwargs = {{}}
101
- for name, param in sig.parameters.items():
102
- if name in kwargs and kwargs[name] is not None:
103
- filtered_kwargs[name] = kwargs[name]
104
-
105
- result = func(**filtered_kwargs)
106
- return str(result) if result is not None else ""
107
- '''
108
-
109
- exec(class_def, exec_globals)
110
- return exec_globals['DynamicTool']
111
-
112
- return DynamicTool
113
-
114
41
  def initialize(self):
115
42
  """Initialize by creating tool classes."""
116
43
  self._tool_classes = []
117
44
  for tool_func in self._tools:
118
45
  if callable(tool_func):
119
- tool_class = self._create_tool_class(tool_func)
46
+ tool_class = create_function_tool(tool_func)
120
47
  self._tool_classes.append(tool_class)
121
48
 
122
49