janito 3.4.0__py3-none-any.whl → 3.5.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.
- janito/README.md +3 -0
- janito/cli/chat_mode/bindings.py +50 -0
- janito/cli/chat_mode/session.py +12 -1
- janito/cli/chat_mode/shell/commands/multi.py +5 -0
- janito/cli/chat_mode/shell/commands/security/allowed_sites.py +47 -33
- janito/cli/cli_commands/check_tools.py +212 -0
- janito/cli/cli_commands/list_plugins.py +52 -43
- janito/cli/core/getters.py +3 -0
- janito/cli/core/model_guesser.py +40 -24
- janito/cli/main_cli.py +9 -12
- janito/cli/prompt_core.py +47 -9
- janito/cli/rich_terminal_reporter.py +2 -2
- janito/drivers/openai/driver.py +1 -0
- janito/drivers/zai/driver.py +1 -0
- janito/i18n/it.py +46 -46
- janito/llm/agent.py +32 -16
- janito/llm/auth_utils.py +14 -5
- janito/llm/cancellation_manager.py +63 -0
- janito/llm/driver.py +8 -0
- janito/llm/enter_cancellation.py +107 -0
- janito/plugin_system/__init__.py +10 -0
- janito/{plugins → plugin_system}/base.py +5 -2
- janito/plugin_system/core_loader.py +217 -0
- janito/plugin_system/core_loader_fixed.py +225 -0
- janito/plugins/__init__.py +31 -12
- janito/plugins/auto_loader.py +12 -11
- janito/plugins/auto_loader_fixed.py +12 -11
- janito/plugins/builtin.py +15 -1
- janito/plugins/core/__init__.py +7 -0
- janito/plugins/core/codeanalyzer/__init__.py +43 -0
- janito/plugins/core/filemanager/__init__.py +124 -0
- janito/plugins/core/filemanager/tools/create_file.py +87 -0
- janito/plugins/core/filemanager/tools/replace_text_in_file.py +270 -0
- janito/plugins/core/imagedisplay/__init__.py +14 -0
- janito/plugins/core/imagedisplay/plugin.py +51 -0
- janito/plugins/core/imagedisplay/tools/__init__.py +1 -0
- janito/plugins/core/imagedisplay/tools/show_image.py +83 -0
- janito/{tools/adapters/local → plugins/core/imagedisplay/tools}/show_image_grid.py +13 -5
- janito/plugins/core/system/__init__.py +23 -0
- janito/plugins/core_adapter.py +89 -11
- janito/plugins/dev/__init__.py +7 -0
- janito/plugins/dev/pythondev/__init__.py +37 -0
- janito/plugins/dev/visualization/__init__.py +23 -0
- janito/plugins/discovery.py +5 -5
- janito/plugins/discovery_core.py +14 -9
- janito/plugins/example_plugin.py +108 -0
- janito/plugins/manager.py +1 -1
- janito/plugins/tools/__init__.py +10 -0
- janito/{tools/adapters/local → plugins/tools}/ask_user.py +3 -3
- janito/plugins/tools/copy_file.py +87 -0
- janito/plugins/tools/core_tools_plugin.py +87 -0
- janito/plugins/tools/create_directory.py +70 -0
- janito/{tools/adapters/local → plugins/tools}/create_file.py +6 -6
- janito/plugins/tools/decorators.py +19 -0
- janito/plugins/tools/delete_text_in_file.py +134 -0
- janito/{tools/adapters/local → plugins/tools}/fetch_url.py +3 -3
- janito/plugins/tools/find_files.py +143 -0
- janito/plugins/tools/get_file_outline/__init__.py +7 -0
- janito/plugins/tools/get_file_outline/core.py +122 -0
- janito/plugins/tools/get_file_outline/java_outline.py +47 -0
- janito/plugins/tools/get_file_outline/markdown_outline.py +14 -0
- janito/plugins/tools/get_file_outline/python_outline.py +303 -0
- janito/plugins/tools/get_file_outline/search_outline.py +36 -0
- janito/plugins/tools/move_file.py +131 -0
- janito/plugins/tools/open_html_in_browser.py +51 -0
- janito/plugins/tools/open_url.py +37 -0
- janito/plugins/tools/python_code_run.py +172 -0
- janito/plugins/tools/python_command_run.py +171 -0
- janito/plugins/tools/python_file_run.py +172 -0
- janito/plugins/tools/read_chart.py +259 -0
- janito/plugins/tools/read_files.py +58 -0
- janito/plugins/tools/remove_directory.py +55 -0
- janito/plugins/tools/remove_file.py +58 -0
- janito/{tools/adapters/local → plugins/tools}/replace_text_in_file.py +4 -4
- janito/plugins/tools/run_bash_command.py +183 -0
- janito/plugins/tools/run_powershell_command.py +218 -0
- janito/plugins/tools/search_text/__init__.py +7 -0
- janito/plugins/tools/search_text/core.py +205 -0
- janito/plugins/tools/search_text/match_lines.py +67 -0
- janito/plugins/tools/search_text/pattern_utils.py +73 -0
- janito/plugins/tools/search_text/traverse_directory.py +145 -0
- janito/{tools/adapters/local → plugins/tools}/show_image.py +15 -6
- janito/plugins/tools/show_image_grid.py +85 -0
- janito/plugins/tools/validate_file_syntax/__init__.py +7 -0
- janito/plugins/tools/validate_file_syntax/core.py +114 -0
- janito/plugins/tools/validate_file_syntax/css_validator.py +35 -0
- janito/plugins/tools/validate_file_syntax/html_validator.py +100 -0
- janito/plugins/tools/validate_file_syntax/jinja2_validator.py +50 -0
- janito/plugins/tools/validate_file_syntax/js_validator.py +27 -0
- janito/plugins/tools/validate_file_syntax/json_validator.py +6 -0
- janito/plugins/tools/validate_file_syntax/markdown_validator.py +109 -0
- janito/plugins/tools/validate_file_syntax/ps1_validator.py +32 -0
- janito/plugins/tools/validate_file_syntax/python_validator.py +5 -0
- janito/plugins/tools/validate_file_syntax/xml_validator.py +11 -0
- janito/plugins/tools/validate_file_syntax/yaml_validator.py +6 -0
- janito/plugins/tools/view_file.py +172 -0
- janito/plugins/ui/__init__.py +7 -0
- janito/plugins/ui/userinterface/__init__.py +16 -0
- janito/plugins/ui/userinterface/tools/ask_user.py +110 -0
- janito/plugins/web/__init__.py +7 -0
- janito/plugins/web/webtools/__init__.py +33 -0
- janito/plugins/web/webtools/tools/fetch_url.py +458 -0
- janito/providers/__init__.py +1 -0
- janito/providers/together/__init__.py +1 -0
- janito/providers/together/model_info.py +69 -0
- janito/providers/together/provider.py +108 -0
- janito/tools/__init__.py +31 -7
- janito/tools/adapters/__init__.py +6 -1
- janito/tools/adapters/local/__init__.py +7 -70
- janito/tools/cli_initializer.py +88 -0
- janito/tools/initialize.py +70 -0
- janito/tools/loop_protection_decorator.py +114 -117
- janito-3.5.0.dist-info/METADATA +229 -0
- {janito-3.4.0.dist-info → janito-3.5.0.dist-info}/RECORD +158 -86
- janito/plugins/core_loader.py +0 -120
- janito/plugins/core_loader_fixed.py +0 -125
- janito/tools/function_adapter.py +0 -65
- janito-3.4.0.dist-info/METADATA +0 -84
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/__init__.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/core.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/java_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/markdown_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/python_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/search_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/__init__.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/core.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/match_lines.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/pattern_utils.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/traverse_directory.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/copy_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/create_directory.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/delete_text_in_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/find_files.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/move_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/read_files.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/remove_directory.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/remove_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/__init__.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/core.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/css_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/html_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/jinja2_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/js_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/json_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/markdown_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/ps1_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/python_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/xml_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/yaml_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/view_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/system/tools}/run_bash_command.py +0 -0
- /janito/{tools/adapters/local → plugins/core/system/tools}/run_powershell_command.py +0 -0
- /janito/{tools/adapters/local → plugins/dev/pythondev/tools}/python_code_run.py +0 -0
- /janito/{tools/adapters/local → plugins/dev/pythondev/tools}/python_command_run.py +0 -0
- /janito/{tools/adapters/local → plugins/dev/pythondev/tools}/python_file_run.py +0 -0
- /janito/{tools/adapters/local → plugins/dev/visualization/tools}/read_chart.py +0 -0
- /janito/{tools/adapters/local → plugins/web/webtools/tools}/open_html_in_browser.py +0 -0
- /janito/{tools/adapters/local → plugins/web/webtools/tools}/open_url.py +0 -0
- {janito-3.4.0.dist-info → janito-3.5.0.dist-info}/WHEEL +0 -0
- {janito-3.4.0.dist-info → janito-3.5.0.dist-info}/entry_points.txt +0 -0
- {janito-3.4.0.dist-info → janito-3.5.0.dist-info}/licenses/LICENSE +0 -0
- {janito-3.4.0.dist-info → janito-3.5.0.dist-info}/top_level.txt +0 -0
janito/README.md
CHANGED
@@ -106,6 +106,9 @@ 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
|
+
|
109
112
|
### Tool Usage
|
110
113
|
|
111
114
|
Janito includes powerful built-in tools for:
|
janito/cli/chat_mode/bindings.py
CHANGED
@@ -35,4 +35,54 @@ 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
|
+
@bindings.add("escape", eager=True)
|
65
|
+
def _(event):
|
66
|
+
"""Handle ESC key to interrupt current request (like Ctrl+C)."""
|
67
|
+
import threading
|
68
|
+
|
69
|
+
# Use global cancellation manager for robust cancellation
|
70
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
71
|
+
|
72
|
+
cancel_manager = get_cancellation_manager()
|
73
|
+
|
74
|
+
cancelled = cancel_manager.cancel_current_request()
|
75
|
+
if cancelled:
|
76
|
+
# Provide user feedback
|
77
|
+
from rich.console import Console
|
78
|
+
|
79
|
+
console = Console()
|
80
|
+
console.print("[red]Request cancelled by ESC key[/red]")
|
81
|
+
|
82
|
+
# Prevent the ESC key from being processed as input
|
83
|
+
event.app.output.flush()
|
84
|
+
return
|
85
|
+
|
86
|
+
# If no active request to cancel, ESC does nothing
|
87
|
+
|
38
88
|
return bindings
|
janito/cli/chat_mode/session.py
CHANGED
@@ -22,6 +22,7 @@ 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
|
25
26
|
|
26
27
|
import time
|
27
28
|
|
@@ -113,6 +114,10 @@ class ChatSession:
|
|
113
114
|
|
114
115
|
# Check if multi-line mode should be enabled by default
|
115
116
|
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
|
116
121
|
|
117
122
|
def _select_profile_and_role(self, args, role):
|
118
123
|
profile, role_arg, python_profile, market_profile = self._extract_args(args)
|
@@ -283,7 +288,13 @@ class ChatSession:
|
|
283
288
|
)
|
284
289
|
)
|
285
290
|
|
286
|
-
|
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
|
+
|
287
298
|
end_time = time.time()
|
288
299
|
elapsed = end_time - start_time
|
289
300
|
self.msg_count += 1
|
@@ -23,6 +23,11 @@ class MultiShellHandler(ShellCmdHandler):
|
|
23
23
|
submitted["value"] = buffer.text
|
24
24
|
event.app.exit(result=buffer.text)
|
25
25
|
|
26
|
+
# Support single ESC to cancel/interrupt (like Ctrl+C)
|
27
|
+
@bindings.add("escape")
|
28
|
+
def _(event):
|
29
|
+
raise KeyboardInterrupt
|
30
|
+
|
26
31
|
# Support Ctrl+D
|
27
32
|
@bindings.add("c-d")
|
28
33
|
def _(event):
|
@@ -59,39 +59,53 @@ Examples:
|
|
59
59
|
command = args[0].lower()
|
60
60
|
whitelist_manager = get_url_whitelist_manager()
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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)
|
95
72
|
else:
|
96
73
|
print(f"Error: Unknown command '{command}'")
|
97
74
|
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)")
|
@@ -0,0 +1,212 @@
|
|
1
|
+
"""
|
2
|
+
CLI Command: Check all registered tools for signature validation and availability
|
3
|
+
"""
|
4
|
+
|
5
|
+
import inspect
|
6
|
+
import sys
|
7
|
+
from typing import Dict, List, Tuple, Any
|
8
|
+
|
9
|
+
|
10
|
+
def _validate_tool_signature(tool_instance) -> Tuple[bool, List[str]]:
|
11
|
+
"""Validate the signature of a tool's run method."""
|
12
|
+
errors = []
|
13
|
+
|
14
|
+
if not hasattr(tool_instance, "run"):
|
15
|
+
errors.append("Missing 'run' method")
|
16
|
+
return False, errors
|
17
|
+
|
18
|
+
try:
|
19
|
+
sig = inspect.signature(tool_instance.run)
|
20
|
+
except ValueError as e:
|
21
|
+
errors.append(f"Invalid signature: {e}")
|
22
|
+
return False, errors
|
23
|
+
|
24
|
+
# Basic signature validation - just check if it's callable
|
25
|
+
if not callable(getattr(tool_instance, "run")):
|
26
|
+
errors.append("'run' method is not callable")
|
27
|
+
|
28
|
+
return len(errors) == 0, errors
|
29
|
+
|
30
|
+
|
31
|
+
def _check_tool_availability(tool_instance) -> Tuple[bool, List[str]]:
|
32
|
+
"""Check if a tool is available for use."""
|
33
|
+
errors = []
|
34
|
+
|
35
|
+
# Check if tool has required attributes
|
36
|
+
required_attrs = ["tool_name"]
|
37
|
+
for attr in required_attrs:
|
38
|
+
if not hasattr(tool_instance, attr):
|
39
|
+
errors.append(f"Missing required attribute: {attr}")
|
40
|
+
|
41
|
+
# Check description (optional for now)
|
42
|
+
if not hasattr(tool_instance, "description"):
|
43
|
+
pass # Allow missing description
|
44
|
+
|
45
|
+
# Check permissions
|
46
|
+
if not hasattr(tool_instance, "permissions"):
|
47
|
+
# Function-based tools use permissions from function decorators
|
48
|
+
pass # Allow missing permissions for function-based tools
|
49
|
+
else:
|
50
|
+
perms = tool_instance.permissions
|
51
|
+
if (
|
52
|
+
not hasattr(perms, "read")
|
53
|
+
or not hasattr(perms, "write")
|
54
|
+
or not hasattr(perms, "execute")
|
55
|
+
):
|
56
|
+
errors.append("Invalid permissions structure")
|
57
|
+
|
58
|
+
return len(errors) == 0, errors
|
59
|
+
|
60
|
+
|
61
|
+
def _get_tool_status_summary(
|
62
|
+
tools: List[Any], disabled_tools: List[str]
|
63
|
+
) -> Dict[str, Any]:
|
64
|
+
"""Get a comprehensive status summary for all tools."""
|
65
|
+
summary = {
|
66
|
+
"total": len(tools),
|
67
|
+
"available": 0,
|
68
|
+
"disabled": 0,
|
69
|
+
"invalid": 0,
|
70
|
+
"details": [],
|
71
|
+
}
|
72
|
+
|
73
|
+
for tool in tools:
|
74
|
+
tool_name = getattr(tool, "tool_name", str(tool))
|
75
|
+
|
76
|
+
# Check if disabled
|
77
|
+
is_disabled = tool_name in disabled_tools
|
78
|
+
|
79
|
+
# Validate signature and availability
|
80
|
+
sig_valid, sig_errors = _validate_tool_signature(tool)
|
81
|
+
avail_valid, avail_errors = _check_tool_availability(tool)
|
82
|
+
|
83
|
+
status = {
|
84
|
+
"name": tool_name,
|
85
|
+
"disabled": is_disabled,
|
86
|
+
"signature_valid": sig_valid,
|
87
|
+
"available": avail_valid,
|
88
|
+
"signature_errors": sig_errors,
|
89
|
+
"availability_errors": avail_errors,
|
90
|
+
}
|
91
|
+
|
92
|
+
summary["details"].append(status)
|
93
|
+
|
94
|
+
if is_disabled:
|
95
|
+
summary["disabled"] += 1
|
96
|
+
elif not sig_valid or not avail_valid:
|
97
|
+
summary["invalid"] += 1
|
98
|
+
else:
|
99
|
+
summary["available"] += 1
|
100
|
+
|
101
|
+
return summary
|
102
|
+
|
103
|
+
|
104
|
+
def _print_check_results(console, summary: Dict[str, Any], verbose: bool = False):
|
105
|
+
"""Print the tool check results in a formatted way."""
|
106
|
+
from rich.table import Table
|
107
|
+
from rich.panel import Panel
|
108
|
+
from rich.text import Text
|
109
|
+
|
110
|
+
# Overall summary
|
111
|
+
summary_text = Text()
|
112
|
+
summary_text.append(f"Total tools: {summary['total']}", style="cyan")
|
113
|
+
summary_text.append(" | ")
|
114
|
+
summary_text.append(f"Available: {summary['available']}", style="green")
|
115
|
+
summary_text.append(" | ")
|
116
|
+
summary_text.append(f"Disabled: {summary['disabled']}", style="yellow")
|
117
|
+
summary_text.append(" | ")
|
118
|
+
summary_text.append(f"Invalid: {summary['invalid']}", style="red")
|
119
|
+
|
120
|
+
console.print(Panel(summary_text, title="Tool Check Summary", style="bold"))
|
121
|
+
|
122
|
+
# Always show the table for check-tools
|
123
|
+
table = Table(title="Tool Details", show_header=True, header_style="bold")
|
124
|
+
table.add_column("Tool", style="cyan", no_wrap=True)
|
125
|
+
table.add_column("Status", style="green")
|
126
|
+
table.add_column("Issues", style="red")
|
127
|
+
|
128
|
+
for detail in summary["details"]:
|
129
|
+
name = detail["name"]
|
130
|
+
|
131
|
+
if detail["disabled"]:
|
132
|
+
status = "[yellow]Disabled[/yellow]"
|
133
|
+
issues = "-"
|
134
|
+
elif not detail["available"] or not detail["signature_valid"]:
|
135
|
+
status = "[red]Invalid[/red]"
|
136
|
+
all_issues = detail["signature_errors"] + detail["availability_errors"]
|
137
|
+
issues = "\n".join(all_issues)
|
138
|
+
else:
|
139
|
+
status = "[green]Available[/green]"
|
140
|
+
issues = "-"
|
141
|
+
|
142
|
+
table.add_row(name, status, issues)
|
143
|
+
|
144
|
+
console.print(table)
|
145
|
+
|
146
|
+
|
147
|
+
def handle_check_tools(args=None):
|
148
|
+
"""Handle the --check-tools CLI command."""
|
149
|
+
from janito.tools.adapters.local.adapter import LocalToolsAdapter
|
150
|
+
import janito.tools # Ensure all tools are registered
|
151
|
+
|
152
|
+
# Load disabled tools from config
|
153
|
+
from janito.tools.disabled_tools import DisabledToolsState
|
154
|
+
from janito.config import config
|
155
|
+
|
156
|
+
disabled_str = config.get("disabled_tools", "")
|
157
|
+
if disabled_str:
|
158
|
+
DisabledToolsState.set_disabled_tools(disabled_str)
|
159
|
+
disabled_tools = DisabledToolsState.get_disabled_tools()
|
160
|
+
|
161
|
+
# Initialize tools properly using the same approach as list_tools.py
|
162
|
+
from janito.tools.adapters.local.adapter import LocalToolsAdapter
|
163
|
+
from janito.tools.tool_base import ToolPermissions
|
164
|
+
import janito.tools # Ensure all tools are registered
|
165
|
+
|
166
|
+
read = getattr(args, "read", False) if args else False
|
167
|
+
write = getattr(args, "write", False) if args else False
|
168
|
+
execute = getattr(args, "exec", False) if args else False
|
169
|
+
if not (read or write or execute):
|
170
|
+
read = write = execute = True
|
171
|
+
from janito.tools.permissions import set_global_allowed_permissions
|
172
|
+
|
173
|
+
set_global_allowed_permissions(
|
174
|
+
ToolPermissions(read=read, write=write, execute=execute)
|
175
|
+
)
|
176
|
+
|
177
|
+
# Load disabled tools from config
|
178
|
+
from janito.tools.disabled_tools import DisabledToolsState
|
179
|
+
from janito.config import config
|
180
|
+
|
181
|
+
disabled_str = config.get("disabled_tools", "")
|
182
|
+
if disabled_str:
|
183
|
+
DisabledToolsState.set_disabled_tools(disabled_str)
|
184
|
+
disabled_tools = DisabledToolsState.get_disabled_tools()
|
185
|
+
|
186
|
+
# Initialize tools using the same method as list_tools.py
|
187
|
+
from janito.tools.initialize import initialize_tools
|
188
|
+
|
189
|
+
registry = initialize_tools()
|
190
|
+
|
191
|
+
# Get actual tool instances
|
192
|
+
tool_instances = []
|
193
|
+
for name, tool_info in registry._tools.items():
|
194
|
+
if "instance" in tool_info:
|
195
|
+
tool_instances.append(tool_info["instance"])
|
196
|
+
|
197
|
+
if not tool_instances:
|
198
|
+
print("No tools registered.")
|
199
|
+
return
|
200
|
+
|
201
|
+
from rich.console import Console
|
202
|
+
|
203
|
+
console = Console()
|
204
|
+
|
205
|
+
verbose = getattr(args, "verbose", False) if args else False
|
206
|
+
|
207
|
+
summary = _get_tool_status_summary(tool_instances, disabled_tools)
|
208
|
+
_print_check_results(console, summary, verbose=verbose)
|
209
|
+
|
210
|
+
# Exit with error code if there are invalid tools
|
211
|
+
if summary["invalid"] > 0:
|
212
|
+
sys.exit(1)
|
@@ -8,7 +8,11 @@ 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
|
11
|
+
from janito.plugins.auto_loader_fixed import (
|
12
|
+
load_core_plugins,
|
13
|
+
get_loaded_core_plugins,
|
14
|
+
is_core_plugin,
|
15
|
+
)
|
12
16
|
from rich.console import Console
|
13
17
|
from rich.table import Table
|
14
18
|
from rich.panel import Panel
|
@@ -51,7 +55,8 @@ def _list_available_plugins():
|
|
51
55
|
console.print(table)
|
52
56
|
|
53
57
|
# Show core plugins
|
54
|
-
from janito.
|
58
|
+
from janito.plugin_system.core_loader_fixed import get_core_plugins
|
59
|
+
|
55
60
|
core_plugins = get_core_plugins()
|
56
61
|
core_table = Table(title="Core Plugins (Enabled by Default)")
|
57
62
|
core_table.add_column("Plugin Name", style="cyan", no_wrap=True)
|
@@ -62,14 +67,16 @@ def _list_available_plugins():
|
|
62
67
|
|
63
68
|
console.print(core_table)
|
64
69
|
else:
|
65
|
-
console.print(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
console.print(
|
71
|
+
Panel(
|
72
|
+
"No plugins found in search paths\n"
|
73
|
+
f"[dim]Search paths:[/dim]\n"
|
74
|
+
f" • {os.getcwd()}/plugins\n"
|
75
|
+
f" • {os.path.expanduser('~')}/.janito/plugins",
|
76
|
+
title="No Plugins Found",
|
77
|
+
style="yellow",
|
78
|
+
)
|
79
|
+
)
|
73
80
|
|
74
81
|
|
75
82
|
def _print_builtin_plugins(builtin_plugins):
|
@@ -92,7 +99,7 @@ def _print_external_plugins(available, builtin_plugins):
|
|
92
99
|
def _list_plugin_resources():
|
93
100
|
"""List all resources from loaded plugins using rich formatting."""
|
94
101
|
from janito.plugins.auto_loader_fixed import get_plugin_manager
|
95
|
-
|
102
|
+
|
96
103
|
console = Console()
|
97
104
|
manager = get_plugin_manager()
|
98
105
|
all_resources = manager.list_all_resources()
|
@@ -100,11 +107,11 @@ def _list_plugin_resources():
|
|
100
107
|
if all_resources:
|
101
108
|
for plugin_name, resources in all_resources.items():
|
102
109
|
metadata = manager.get_plugin_metadata(plugin_name)
|
103
|
-
version = metadata.version if metadata else
|
104
|
-
|
110
|
+
version = metadata.version if metadata else "unknown"
|
111
|
+
|
105
112
|
# Create panel for each plugin
|
106
113
|
panel_content = []
|
107
|
-
|
114
|
+
|
108
115
|
tools = [r for r in resources if r["type"] == "tool"]
|
109
116
|
commands = [r for r in resources if r["type"] == "command"]
|
110
117
|
configs = [r for r in resources if r["type"] == "config"]
|
@@ -122,19 +129,25 @@ def _list_plugin_resources():
|
|
122
129
|
if configs:
|
123
130
|
panel_content.append("[bold yellow]Configuration:[/bold yellow]")
|
124
131
|
for config in configs:
|
125
|
-
panel_content.append(
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
+
panel_content.append(
|
133
|
+
f" • {config['name']}: {config['description']}"
|
134
|
+
)
|
135
|
+
|
136
|
+
console.print(
|
137
|
+
Panel(
|
138
|
+
"\n".join(panel_content),
|
139
|
+
title=f"{plugin_name} v{version}",
|
140
|
+
style="cyan",
|
141
|
+
)
|
142
|
+
)
|
132
143
|
else:
|
133
|
-
console.print(
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
144
|
+
console.print(
|
145
|
+
Panel(
|
146
|
+
"No plugins are currently loaded.",
|
147
|
+
title="No Plugin Resources",
|
148
|
+
style="yellow",
|
149
|
+
)
|
150
|
+
)
|
138
151
|
|
139
152
|
|
140
153
|
def _print_resources_by_type(resources):
|
@@ -162,7 +175,7 @@ def _print_resources_by_type(resources):
|
|
162
175
|
def _list_loaded_plugins():
|
163
176
|
"""List loaded plugins using rich formatting."""
|
164
177
|
from janito.plugins.auto_loader_fixed import get_plugin_manager
|
165
|
-
|
178
|
+
|
166
179
|
console = Console()
|
167
180
|
manager = get_plugin_manager()
|
168
181
|
loaded = manager.list_plugins()
|
@@ -177,42 +190,38 @@ def _list_loaded_plugins():
|
|
177
190
|
|
178
191
|
core_plugins = []
|
179
192
|
other_plugins = []
|
180
|
-
|
193
|
+
|
181
194
|
for plugin_name in loaded:
|
182
195
|
if is_core_plugin(plugin_name):
|
183
196
|
core_plugins.append(plugin_name)
|
184
197
|
else:
|
185
198
|
other_plugins.append(plugin_name)
|
186
|
-
|
199
|
+
|
187
200
|
# Add core plugins
|
188
201
|
for plugin_name in core_plugins:
|
189
202
|
metadata = manager.get_plugin_metadata(plugin_name)
|
190
203
|
if metadata:
|
191
204
|
table.add_row(
|
192
|
-
metadata.name,
|
193
|
-
metadata.version,
|
194
|
-
metadata.description,
|
195
|
-
"🔵 Core"
|
205
|
+
metadata.name, metadata.version, metadata.description, "🔵 Core"
|
196
206
|
)
|
197
|
-
|
207
|
+
|
198
208
|
# Add other plugins
|
199
209
|
for plugin_name in other_plugins:
|
200
210
|
metadata = manager.get_plugin_metadata(plugin_name)
|
201
211
|
if metadata:
|
202
212
|
table.add_row(
|
203
|
-
metadata.name,
|
204
|
-
metadata.version,
|
205
|
-
metadata.description,
|
206
|
-
"🔶 External"
|
213
|
+
metadata.name, metadata.version, metadata.description, "🔶 External"
|
207
214
|
)
|
208
215
|
|
209
216
|
console.print(table)
|
210
217
|
else:
|
211
|
-
console.print(
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
218
|
+
console.print(
|
219
|
+
Panel(
|
220
|
+
"No plugins are currently loaded.",
|
221
|
+
title="No Plugins Loaded",
|
222
|
+
style="yellow",
|
223
|
+
)
|
224
|
+
)
|
216
225
|
|
217
226
|
|
218
227
|
def _print_plugin_details(manager, plugin_name):
|
janito/cli/core/getters.py
CHANGED
@@ -5,6 +5,7 @@ import sys
|
|
5
5
|
from janito.cli.cli_commands.list_providers import handle_list_providers
|
6
6
|
from janito.cli.cli_commands.list_models import handle_list_models
|
7
7
|
from janito.cli.cli_commands.list_tools import handle_list_tools
|
8
|
+
from janito.cli.cli_commands.check_tools import handle_check_tools
|
8
9
|
from janito.cli.cli_commands.show_config import handle_show_config
|
9
10
|
from janito.cli.cli_commands.list_config import handle_list_config
|
10
11
|
from janito.cli.cli_commands.list_drivers import handle_list_drivers
|
@@ -28,6 +29,7 @@ GETTER_KEYS = [
|
|
28
29
|
"list_plugins",
|
29
30
|
"list_plugins_available",
|
30
31
|
"list_resources",
|
32
|
+
"check_tools",
|
31
33
|
]
|
32
34
|
|
33
35
|
|
@@ -64,6 +66,7 @@ def handle_getter(args, config_mgr=None):
|
|
64
66
|
"list_plugins": partial(handle_list_plugins, args),
|
65
67
|
"list_plugins_available": partial(handle_list_plugins, args),
|
66
68
|
"list_resources": partial(handle_list_plugins, args),
|
69
|
+
"check_tools": partial(handle_check_tools, args),
|
67
70
|
}
|
68
71
|
for arg in GETTER_KEYS:
|
69
72
|
if getattr(args, arg, False) and arg in GETTER_DISPATCH:
|
janito/cli/core/model_guesser.py
CHANGED
@@ -21,34 +21,50 @@ 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."""
|
24
29
|
for provider_name in LLMProviderRegistry.list_providers():
|
25
30
|
provider_class = LLMProviderRegistry.get(provider_name)
|
26
31
|
if not provider_class:
|
27
32
|
continue
|
28
33
|
|
29
|
-
|
30
|
-
|
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
|
34
|
+
if _check_provider_models(provider_name, provider_class, model_name):
|
35
|
+
return provider_name
|
53
36
|
|
54
37
|
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
|