janito 3.6.1__py3-none-any.whl → 3.8.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 (172) hide show
  1. janito/README.md +4 -7
  2. janito/cli/chat_mode/bindings.py +0 -50
  3. janito/cli/chat_mode/session.py +1 -12
  4. janito/cli/chat_mode/shell/commands/multi.py +0 -5
  5. janito/cli/chat_mode/shell/commands/security/allowed_sites.py +33 -47
  6. janito/cli/cli_commands/list_plugins.py +43 -52
  7. janito/cli/cli_commands/list_tools.py +1 -6
  8. janito/cli/core/getters.py +0 -3
  9. janito/cli/core/model_guesser.py +24 -40
  10. janito/cli/main_cli.py +13 -10
  11. janito/cli/prompt_core.py +9 -47
  12. janito/cli/rich_terminal_reporter.py +4 -4
  13. janito/docs/GETTING_STARTED.md +9 -8
  14. janito/drivers/openai/driver.py +0 -1
  15. janito/drivers/zai/driver.py +0 -1
  16. janito/i18n/it.py +46 -46
  17. janito/llm/agent.py +16 -32
  18. janito/llm/auth_utils.py +5 -14
  19. janito/llm/driver.py +0 -8
  20. janito/plugins/__init__.py +12 -31
  21. janito/plugins/auto_loader.py +11 -12
  22. janito/plugins/auto_loader_fixed.py +11 -12
  23. janito/{plugin_system → plugins}/base.py +2 -5
  24. janito/plugins/builtin.py +1 -15
  25. janito/plugins/core_adapter.py +11 -89
  26. janito/plugins/core_loader.py +120 -0
  27. janito/plugins/core_loader_fixed.py +125 -0
  28. janito/plugins/discovery.py +5 -5
  29. janito/plugins/discovery_core.py +9 -14
  30. janito/plugins/manager.py +1 -1
  31. janito/providers/__init__.py +0 -1
  32. janito/providers/alibaba/model_info.py +10 -0
  33. janito/providers/alibaba/provider.py +1 -3
  34. janito/providers/moonshot/model_info.py +7 -7
  35. janito/providers/moonshot/provider.py +1 -1
  36. janito/tools/__init__.py +7 -41
  37. janito/tools/adapters/__init__.py +1 -6
  38. janito/tools/adapters/local/__init__.py +70 -7
  39. janito/{plugins/tools/core → tools/adapters/local}/ask_user.py +3 -3
  40. janito/tools/adapters/local/copy_file.py +87 -0
  41. janito/tools/adapters/local/create_file.py +138 -0
  42. janito/{plugins/tools/core → tools/adapters/local}/fetch_url.py +23 -20
  43. janito/tools/adapters/local/move_file.py +131 -0
  44. janito/{plugins/tools/core → tools/adapters/local}/python_code_run.py +7 -23
  45. janito/{plugins/tools/core → tools/adapters/local}/python_command_run.py +5 -21
  46. janito/{plugins/tools/core → tools/adapters/local}/python_file_run.py +5 -21
  47. janito/tools/adapters/local/remove_file.py +58 -0
  48. janito/{plugins/tools/core → tools/adapters/local}/replace_text_in_file.py +4 -4
  49. janito/{plugins/tools/core → tools/adapters/local}/run_bash_command.py +3 -3
  50. janito/{plugins/tools/core → tools/adapters/local}/run_powershell_command.py +3 -3
  51. janito/{plugins/tools/core → tools/adapters/local}/show_image.py +6 -15
  52. janito/{plugins/core/imagedisplay/tools → tools/adapters/local}/show_image_grid.py +5 -13
  53. janito/tools/adapters/local/view_file.py +172 -0
  54. janito/tools/function_adapter.py +65 -0
  55. janito/tools/loop_protection_decorator.py +117 -114
  56. janito-3.8.0.dist-info/METADATA +84 -0
  57. janito-3.8.0.dist-info/RECORD +264 -0
  58. janito/cli/cli_commands/check_tools.py +0 -212
  59. janito/data/blocked.txt +0 -96
  60. janito/llm/cancellation_manager.py +0 -63
  61. janito/llm/enter_cancellation.py +0 -107
  62. janito/plugin_system/__init__.py +0 -10
  63. janito/plugin_system/core_loader.py +0 -217
  64. janito/plugin_system/core_loader_fixed.py +0 -225
  65. janito/plugins/core/__init__.py +0 -7
  66. janito/plugins/core/codeanalyzer/__init__.py +0 -43
  67. janito/plugins/core/filemanager/__init__.py +0 -124
  68. janito/plugins/core/filemanager/tools/copy_file.py +0 -87
  69. janito/plugins/core/filemanager/tools/create_file.py +0 -87
  70. janito/plugins/core/filemanager/tools/move_file.py +0 -131
  71. janito/plugins/core/filemanager/tools/remove_file.py +0 -58
  72. janito/plugins/core/filemanager/tools/replace_text_in_file.py +0 -270
  73. janito/plugins/core/filemanager/tools/view_file.py +0 -172
  74. janito/plugins/core/imagedisplay/__init__.py +0 -14
  75. janito/plugins/core/imagedisplay/plugin.py +0 -51
  76. janito/plugins/core/imagedisplay/tools/__init__.py +0 -1
  77. janito/plugins/core/imagedisplay/tools/show_image.py +0 -83
  78. janito/plugins/core/system/__init__.py +0 -23
  79. janito/plugins/core/system/tools/run_bash_command.py +0 -204
  80. janito/plugins/core/system/tools/run_powershell_command.py +0 -234
  81. janito/plugins/dev/__init__.py +0 -7
  82. janito/plugins/dev/pythondev/__init__.py +0 -37
  83. janito/plugins/dev/visualization/__init__.py +0 -23
  84. janito/plugins/example_plugin.py +0 -108
  85. janito/plugins/tools/__init__.py +0 -39
  86. janito/plugins/tools/core/__init__.py +0 -65
  87. janito/plugins/tools/core/copy_file.py +0 -87
  88. janito/plugins/tools/core/create_directory.py +0 -70
  89. janito/plugins/tools/core/create_file.py +0 -138
  90. janito/plugins/tools/core/decorators.py +0 -19
  91. janito/plugins/tools/core/delete_text_in_file.py +0 -134
  92. janito/plugins/tools/core/find_files.py +0 -143
  93. janito/plugins/tools/core/get_file_outline/__init__.py +0 -7
  94. janito/plugins/tools/core/get_file_outline/core.py +0 -122
  95. janito/plugins/tools/core/get_file_outline/java_outline.py +0 -47
  96. janito/plugins/tools/core/get_file_outline/markdown_outline.py +0 -14
  97. janito/plugins/tools/core/get_file_outline/python_outline.py +0 -303
  98. janito/plugins/tools/core/get_file_outline/search_outline.py +0 -36
  99. janito/plugins/tools/core/move_file.py +0 -131
  100. janito/plugins/tools/core/open_html_in_browser.py +0 -51
  101. janito/plugins/tools/core/open_url.py +0 -37
  102. janito/plugins/tools/core/read_chart.py +0 -259
  103. janito/plugins/tools/core/read_files.py +0 -58
  104. janito/plugins/tools/core/remove_directory.py +0 -55
  105. janito/plugins/tools/core/remove_file.py +0 -58
  106. janito/plugins/tools/core/search_text/__init__.py +0 -7
  107. janito/plugins/tools/core/search_text/core.py +0 -205
  108. janito/plugins/tools/core/search_text/match_lines.py +0 -67
  109. janito/plugins/tools/core/search_text/pattern_utils.py +0 -73
  110. janito/plugins/tools/core/search_text/traverse_directory.py +0 -145
  111. janito/plugins/tools/core/show_image_grid.py +0 -85
  112. janito/plugins/tools/core/validate_file_syntax/__init__.py +0 -7
  113. janito/plugins/tools/core/validate_file_syntax/core.py +0 -114
  114. janito/plugins/tools/core/validate_file_syntax/css_validator.py +0 -35
  115. janito/plugins/tools/core/validate_file_syntax/html_validator.py +0 -100
  116. janito/plugins/tools/core/validate_file_syntax/jinja2_validator.py +0 -50
  117. janito/plugins/tools/core/validate_file_syntax/js_validator.py +0 -27
  118. janito/plugins/tools/core/validate_file_syntax/json_validator.py +0 -6
  119. janito/plugins/tools/core/validate_file_syntax/markdown_validator.py +0 -109
  120. janito/plugins/tools/core/validate_file_syntax/ps1_validator.py +0 -32
  121. janito/plugins/tools/core/validate_file_syntax/python_validator.py +0 -5
  122. janito/plugins/tools/core/validate_file_syntax/xml_validator.py +0 -11
  123. janito/plugins/tools/core/validate_file_syntax/yaml_validator.py +0 -6
  124. janito/plugins/tools/core/view_file.py +0 -172
  125. janito/plugins/ui/__init__.py +0 -7
  126. janito/plugins/ui/userinterface/__init__.py +0 -16
  127. janito/plugins/ui/userinterface/tools/ask_user.py +0 -110
  128. janito/plugins/web/__init__.py +0 -7
  129. janito/plugins/web/webtools/__init__.py +0 -23
  130. janito/providers/together/__init__.py +0 -1
  131. janito/providers/together/model_info.py +0 -69
  132. janito/providers/together/provider.py +0 -108
  133. janito/tools/blocked_sites.py +0 -74
  134. janito/tools/cli_initializer.py +0 -88
  135. janito/tools/initialize.py +0 -70
  136. janito-3.6.1.dist-info/METADATA +0 -228
  137. janito-3.6.1.dist-info/RECORD +0 -339
  138. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/create_directory.py +0 -0
  139. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/delete_text_in_file.py +0 -0
  140. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/find_files.py +0 -0
  141. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/__init__.py +0 -0
  142. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/core.py +0 -0
  143. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/java_outline.py +0 -0
  144. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/markdown_outline.py +0 -0
  145. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/python_outline.py +0 -0
  146. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/search_outline.py +0 -0
  147. /janito/{plugins/web/webtools/tools → tools/adapters/local}/open_html_in_browser.py +0 -0
  148. /janito/{plugins/web/webtools/tools → tools/adapters/local}/open_url.py +0 -0
  149. /janito/{plugins/dev/visualization/tools → tools/adapters/local}/read_chart.py +0 -0
  150. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/read_files.py +0 -0
  151. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/remove_directory.py +0 -0
  152. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/__init__.py +0 -0
  153. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/core.py +0 -0
  154. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/match_lines.py +0 -0
  155. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/pattern_utils.py +0 -0
  156. /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/traverse_directory.py +0 -0
  157. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/__init__.py +0 -0
  158. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/core.py +0 -0
  159. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/css_validator.py +0 -0
  160. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/html_validator.py +0 -0
  161. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/jinja2_validator.py +0 -0
  162. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/js_validator.py +0 -0
  163. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/json_validator.py +0 -0
  164. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/markdown_validator.py +0 -0
  165. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/ps1_validator.py +0 -0
  166. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/python_validator.py +0 -0
  167. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/xml_validator.py +0 -0
  168. /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/yaml_validator.py +0 -0
  169. {janito-3.6.1.dist-info → janito-3.8.0.dist-info}/WHEEL +0 -0
  170. {janito-3.6.1.dist-info → janito-3.8.0.dist-info}/entry_points.txt +0 -0
  171. {janito-3.6.1.dist-info → janito-3.8.0.dist-info}/licenses/LICENSE +0 -0
  172. {janito-3.6.1.dist-info → janito-3.8.0.dist-info}/top_level.txt +0 -0
@@ -1,107 +0,0 @@
1
- """
2
- Enter key cancellation for LLM requests.
3
- Allows pressing Enter to cancel ongoing requests.
4
- """
5
-
6
- import threading
7
- import sys
8
- import time
9
- from typing import Optional
10
-
11
-
12
- class EnterCancellation:
13
- """Handles Enter key cancellation of LLM requests."""
14
-
15
- def __init__(self):
16
- self._cancel_event: Optional[threading.Event] = None
17
- self._listener_thread: Optional[threading.Thread] = None
18
- self._listening = False
19
-
20
- def start_monitoring(self, cancel_event: threading.Event):
21
- """Start monitoring for Enter key to cancel the request."""
22
- if self._listening:
23
- return
24
-
25
- self._cancel_event = cancel_event
26
- self._listening = True
27
-
28
- self._listener_thread = threading.Thread(
29
- target=self._monitor_enter_key, daemon=True
30
- )
31
- self._listener_thread.start()
32
-
33
- def stop_monitoring(self):
34
- """Stop monitoring for keyboard input."""
35
- self._listening = False
36
- if self._listener_thread and self._listener_thread.is_alive():
37
- self._listener_thread.join(timeout=0.1)
38
-
39
- def _monitor_enter_key(self):
40
- """Monitor for Enter key press."""
41
- try:
42
- self._handle_key_monitoring()
43
- except Exception:
44
- # Silently handle any errors
45
- pass
46
-
47
- def _handle_key_monitoring(self):
48
- """Handle the actual key monitoring logic."""
49
- import sys
50
- import select
51
-
52
- try:
53
- import msvcrt # Windows-specific keyboard input
54
-
55
- self._monitor_windows_keys()
56
- except ImportError:
57
- self._monitor_unix_keys()
58
-
59
- def _monitor_windows_keys(self):
60
- """Monitor keys on Windows systems."""
61
- import msvcrt
62
-
63
- while (
64
- self._listening and self._cancel_event and not self._cancel_event.is_set()
65
- ):
66
- try:
67
- if msvcrt.kbhit():
68
- char = msvcrt.getch()
69
- if char in [b"\r", b"\n"]:
70
- if self._cancel_event:
71
- self._cancel_event.set()
72
- break
73
- else:
74
- time.sleep(0.05)
75
- except (IOError, OSError):
76
- break
77
-
78
- def _monitor_unix_keys(self):
79
- """Monitor keys on Unix-like systems."""
80
- import sys
81
- import select
82
-
83
- while (
84
- self._listening and self._cancel_event and not self._cancel_event.is_set()
85
- ):
86
- try:
87
- if sys.stdin in select.select([sys.stdin], [], [], 0.05)[0]:
88
- char = sys.stdin.read(1)
89
- if char in ["\r", "\n"]:
90
- if self._cancel_event:
91
- self._cancel_event.set()
92
- break
93
- time.sleep(0.05)
94
- except:
95
- time.sleep(0.05)
96
-
97
-
98
- # Global instance
99
- _global_enter_cancellation = None
100
-
101
-
102
- def get_enter_cancellation() -> EnterCancellation:
103
- """Get the global Enter cancellation instance."""
104
- global _global_enter_cancellation
105
- if _global_enter_cancellation is None:
106
- _global_enter_cancellation = EnterCancellation()
107
- return _global_enter_cancellation
@@ -1,10 +0,0 @@
1
- """
2
- Plugin System Core Package
3
-
4
- This package provides the foundational plugin system architecture.
5
- It should not depend on any specific plugin implementations.
6
- """
7
-
8
- from .base import Plugin, PluginMetadata, PluginResource
9
-
10
- __all__ = ["Plugin", "PluginMetadata", "PluginResource"]
@@ -1,217 +0,0 @@
1
- """
2
- Fixed core plugin loader.
3
-
4
- This module provides a working implementation to load core plugins
5
- by directly using the Plugin base class properly.
6
- """
7
-
8
- import importlib
9
- import importlib.util
10
- import sys
11
- from pathlib import Path
12
- from typing import Optional, List, Type
13
-
14
- from janito.plugin_system.base import Plugin, PluginMetadata
15
- from janito.tools.tool_base import ToolBase, ToolPermissions
16
-
17
-
18
- class CorePlugin(Plugin):
19
- """Working core plugin implementation."""
20
-
21
- def __init__(self, name: str, description: str, tools: list):
22
- self._plugin_name = name
23
- self._description = description
24
- self._tools = tools
25
- self._tool_classes = []
26
- super().__init__() # Call super after setting attributes
27
-
28
- def get_metadata(self) -> PluginMetadata:
29
- return PluginMetadata(
30
- name=self._plugin_name,
31
- version="1.0.0",
32
- description=self._description,
33
- author="Janito",
34
- license="MIT",
35
- )
36
-
37
- def get_tools(self) -> List[Type[ToolBase]]:
38
- return self._tool_classes
39
-
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
- def initialize(self):
115
- """Initialize by creating tool classes."""
116
- self._tool_classes = []
117
- for tool_func in self._tools:
118
- if callable(tool_func):
119
- tool_class = self._create_tool_class(tool_func)
120
- self._tool_classes.append(tool_class)
121
-
122
-
123
- def load_core_plugin(plugin_name: str) -> Optional[Plugin]:
124
- """
125
- Load a core plugin by name.
126
-
127
- Args:
128
- plugin_name: Name of the plugin (e.g., 'core.filemanager')
129
-
130
- Returns:
131
- Plugin instance if loaded successfully
132
- """
133
- try:
134
- # Parse plugin name
135
- if "." not in plugin_name:
136
- return None
137
-
138
- parts = plugin_name.split(".")
139
- if len(parts) != 2:
140
- return None
141
-
142
- package_name, submodule_name = parts
143
-
144
- # Handle imagedisplay specially
145
- if plugin_name == "core.imagedisplay":
146
- # Import the actual plugin class
147
- try:
148
- # Use dynamic import to avoid circular dependency
149
- plugin_module = importlib.import_module(
150
- "janito.plugins.core.imagedisplay.plugin"
151
- )
152
- return plugin_module.ImageDisplayPlugin()
153
- except ImportError as e:
154
- print(f"Failed to load imagedisplay: {e}")
155
- return None
156
-
157
- # Build path to plugin
158
- plugin_path = (
159
- Path("janito/plugins") / package_name / submodule_name / "__init__.py"
160
- )
161
- if not plugin_path.exists():
162
- return None
163
-
164
- # Load the module
165
- spec = importlib.util.spec_from_file_location(plugin_name, plugin_path)
166
- if spec is None or spec.loader is None:
167
- return None
168
-
169
- module = importlib.util.module_from_spec(spec)
170
- spec.loader.exec_module(module)
171
-
172
- # Get plugin info
173
- name = getattr(module, "__plugin_name__", plugin_name)
174
- description = getattr(
175
- module, "__plugin_description__", f"Core plugin: {plugin_name}"
176
- )
177
- tools = getattr(module, "__plugin_tools__", [])
178
-
179
- if not tools:
180
- return None
181
-
182
- # Filter out None values and ensure all tools have tool_name
183
- valid_tools = []
184
- for tool in tools:
185
- if tool is not None:
186
- if not hasattr(tool, "tool_name"):
187
- tool.tool_name = tool.__name__
188
- valid_tools.append(tool)
189
-
190
- if not valid_tools:
191
- return None
192
-
193
- # Create plugin
194
- plugin = CorePlugin(name, description, valid_tools)
195
- plugin.initialize()
196
- return plugin
197
-
198
- except Exception as e:
199
- print(f"Error loading core plugin {plugin_name}: {e}")
200
- return None
201
-
202
-
203
- def get_core_plugins() -> list:
204
- """Get list of all available core plugins."""
205
- core_plugins = [
206
- "core.filemanager",
207
- "core.codeanalyzer",
208
- "core.system",
209
- "core.imagedisplay",
210
- "dev.pythondev",
211
- "dev.visualization",
212
- "ui.userinterface",
213
- "web.webtools",
214
- ]
215
-
216
- # All core plugins are always available
217
- return core_plugins
@@ -1,225 +0,0 @@
1
- """
2
- Fixed core plugin loader.
3
-
4
- This module provides a working implementation to load core plugins
5
- by directly using the Plugin base class properly.
6
- """
7
-
8
- import importlib.util
9
- import sys
10
- from pathlib import Path
11
- from typing import Optional, List, Type
12
-
13
- from janito.plugin_system.base import Plugin, PluginMetadata
14
- from janito.tools.tool_base import ToolBase, ToolPermissions
15
-
16
-
17
- class CorePlugin(Plugin):
18
- """Working core plugin implementation."""
19
-
20
- def __init__(self, name: str, description: str, tools: list):
21
- self._plugin_name = name
22
- self._description = description
23
- self._tools = tools
24
- self._tool_classes = []
25
- super().__init__() # Call super after setting attributes
26
-
27
- def get_metadata(self) -> PluginMetadata:
28
- return PluginMetadata(
29
- name=self._plugin_name,
30
- version="1.0.0",
31
- description=self._description,
32
- author="Janito",
33
- license="MIT",
34
- )
35
-
36
- def get_tools(self) -> List[Type[ToolBase]]:
37
- return self._tool_classes
38
-
39
- def _create_tool_class(self, func):
40
- """Create a ToolBase class from a function."""
41
- resolved_tool_name = getattr(func, "tool_name", func.__name__)
42
-
43
- # Create a proper tool class with explicit parameters and documentation
44
- import inspect
45
- from typing import get_type_hints
46
-
47
- func_sig = inspect.signature(func)
48
- type_hints = get_type_hints(func)
49
-
50
- # Build parameter definitions for the run method
51
- param_defs = []
52
- param_docs = []
53
- for name, param in func_sig.parameters.items():
54
- type_hint = type_hints.get(name, str)
55
- if param.default == inspect.Parameter.empty:
56
- param_defs.append(f"{name}: {type_hint.__name__}")
57
- else:
58
- param_defs.append(f"{name}: {type_hint.__name__} = {repr(param.default)}")
59
-
60
- # Add parameter documentation
61
- param_docs.append(f" {name}: {type_hint.__name__} - Parameter {name}")
62
-
63
- # Get function docstring or create one
64
- func_doc = func.__doc__ or f"Execute {resolved_tool_name} tool"
65
-
66
- # Create the tool class with proper signature and documentation
67
- exec_globals = {
68
- 'ToolBase': ToolBase,
69
- 'ToolPermissions': ToolPermissions,
70
- 'func': func,
71
- 'inspect': inspect,
72
- 'str': str,
73
- 'List': list,
74
- 'Dict': dict,
75
- 'Optional': type(None),
76
- }
77
-
78
- param_docs_str = '\n'.join(param_docs)
79
-
80
- class_def = f'''
81
- class DynamicTool(ToolBase):
82
- """
83
- {func_doc}
84
-
85
- Parameters:
86
- {param_docs_str}
87
-
88
- Returns:
89
- str: Execution result
90
- """
91
- tool_name = "{resolved_tool_name}"
92
- permissions = ToolPermissions(read=True, write=True, execute=True)
93
-
94
- def __init__(self):
95
- super().__init__()
96
-
97
- def run(self, {', '.join(param_defs)}) -> str:
98
- kwargs = locals()
99
- sig = inspect.signature(func)
100
-
101
- # Filter kwargs to only include parameters the function accepts
102
- filtered_kwargs = {{}}
103
- for name, param in sig.parameters.items():
104
- if name in kwargs and kwargs[name] is not None:
105
- filtered_kwargs[name] = kwargs[name]
106
-
107
- result = func(**filtered_kwargs)
108
- return str(result) if result is not None else ""
109
- '''
110
-
111
- exec(class_def, exec_globals)
112
- return exec_globals['DynamicTool']
113
-
114
- return DynamicTool
115
-
116
- def initialize(self):
117
- """Initialize by creating tool classes."""
118
- self._tool_classes = []
119
- for tool_func in self._tools:
120
- if callable(tool_func):
121
- tool_class = self._create_tool_class(tool_func)
122
- self._tool_classes.append(tool_class)
123
-
124
-
125
- def load_core_plugin(plugin_name: str) -> Optional[Plugin]:
126
- """
127
- Load a core plugin by name.
128
-
129
- Args:
130
- plugin_name: Name of the plugin (e.g., 'core.filemanager')
131
-
132
- Returns:
133
- Plugin instance if loaded successfully
134
- """
135
- try:
136
- # Parse plugin name
137
- if "." not in plugin_name:
138
- return None
139
-
140
- parts = plugin_name.split(".")
141
- if len(parts) != 2:
142
- return None
143
-
144
- package_name, submodule_name = parts
145
-
146
- # Handle imagedisplay specially
147
- if plugin_name == "core.imagedisplay":
148
- # Import the actual plugin class
149
- try:
150
- from janito.plugins.core.imagedisplay.plugin import ImageDisplayPlugin
151
-
152
- return ImageDisplayPlugin()
153
- except ImportError as e:
154
- print(f"Failed to load imagedisplay: {e}")
155
- return None
156
-
157
- # Build path to plugin
158
- plugin_path = (
159
- Path("janito/plugins") / package_name / submodule_name / "__init__.py"
160
- )
161
- if not plugin_path.exists():
162
- return None
163
-
164
- # Load the module
165
- spec = importlib.util.spec_from_file_location(plugin_name, plugin_path)
166
- if spec is None or spec.loader is None:
167
- return None
168
-
169
- module = importlib.util.module_from_spec(spec)
170
-
171
- # Add module to sys.modules to prevent circular imports
172
- sys.modules[plugin_name] = module
173
-
174
- try:
175
- # Read and execute the module content
176
- with open(plugin_path, "r", encoding="utf-8") as f:
177
- code = f.read()
178
-
179
- # Execute in module's namespace
180
- exec(code, module.__dict__)
181
-
182
- # Get plugin info
183
- name = module.__dict__.get("__plugin_name__", plugin_name)
184
- description = module.__dict__.get(
185
- "__plugin_description__", f"Core plugin: {plugin_name}"
186
- )
187
- tools = module.__dict__.get("__plugin_tools__", [])
188
-
189
- if not tools:
190
- return None
191
-
192
- # Ensure all tools have tool_name attribute
193
- for tool in tools:
194
- if tool is not None and not hasattr(tool, "tool_name"):
195
- tool.tool_name = tool.__name__
196
-
197
- # Create plugin
198
- plugin = CorePlugin(name, description, tools)
199
- plugin.initialize()
200
- return plugin
201
- finally:
202
- # Clean up sys.modules
203
- if plugin_name in sys.modules:
204
- del sys.modules[plugin_name]
205
-
206
- except Exception as e:
207
- print(f"Error loading core plugin {plugin_name}: {e}")
208
- return None
209
-
210
-
211
- def get_core_plugins() -> list:
212
- """Get list of all available core plugins."""
213
- core_plugins = [
214
- "core.filemanager",
215
- "core.codeanalyzer",
216
- "core.system",
217
- "core.imagedisplay",
218
- "dev.pythondev",
219
- "dev.visualization",
220
- "ui.userinterface",
221
- "web.webtools",
222
- ]
223
-
224
- # All core plugins are always available
225
- return core_plugins
@@ -1,7 +0,0 @@
1
- """
2
- Core Plugin Package
3
-
4
- Contains essential system and file management plugins.
5
- """
6
-
7
- __all__ = ["filemanager", "codeanalyzer", "system"]
@@ -1,43 +0,0 @@
1
- """
2
- Code Analyzer Plugin
3
-
4
- Tools for understanding and searching code structure.
5
- """
6
-
7
- from typing import List, Optional
8
-
9
-
10
- def get_file_outline(path: str) -> str:
11
- """Get file structure (classes, functions, etc.)"""
12
- return f"get_file_outline(path='{path}')"
13
-
14
-
15
- get_file_outline.tool_name = "get_file_outline"
16
-
17
-
18
- def search_outline(path: str) -> str:
19
- """Search within file outlines"""
20
- return f"search_outline(path='{path}')"
21
-
22
-
23
- search_outline.tool_name = "search_outline"
24
-
25
-
26
- def search_text(
27
- paths: str,
28
- query: str,
29
- use_regex: bool = False,
30
- case_sensitive: bool = True,
31
- max_depth: Optional[int] = None,
32
- ) -> str:
33
- """Full-text search across files with regex support"""
34
- return f"search_text(paths='{paths}', query='{query}', regex={use_regex})"
35
-
36
-
37
- search_text.tool_name = "search_text"
38
-
39
-
40
- # Plugin metadata
41
- __plugin_name__ = "core.codeanalyzer"
42
- __plugin_description__ = "Code analysis and structure understanding"
43
- __plugin_tools__ = [get_file_outline, search_outline, search_text]