janito 2.27.1__py3-none-any.whl → 2.29.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 +9 -9
- janito/agent/setup_agent.py +29 -16
- janito/cli/chat_mode/script_runner.py +1 -1
- janito/cli/chat_mode/session.py +160 -56
- janito/cli/chat_mode/session_profile_select.py +8 -2
- janito/cli/chat_mode/shell/commands/execute.py +4 -2
- janito/cli/chat_mode/shell/commands/help.py +2 -0
- janito/cli/chat_mode/shell/commands/privileges.py +6 -2
- janito/cli/chat_mode/shell/commands/provider.py +7 -4
- janito/cli/chat_mode/shell/commands/read.py +4 -2
- janito/cli/chat_mode/shell/commands/security/__init__.py +1 -1
- janito/cli/chat_mode/shell/commands/security/allowed_sites.py +16 -13
- janito/cli/chat_mode/shell/commands/security_command.py +14 -10
- janito/cli/chat_mode/shell/commands/tools.py +4 -2
- janito/cli/chat_mode/shell/commands/unrestricted.py +17 -12
- janito/cli/chat_mode/shell/commands/write.py +4 -2
- janito/cli/chat_mode/toolbar.py +4 -4
- janito/cli/cli_commands/enable_disable_plugin.py +48 -25
- janito/cli/cli_commands/list_models.py +2 -2
- janito/cli/cli_commands/list_plugins.py +18 -18
- janito/cli/cli_commands/list_profiles.py +6 -6
- janito/cli/cli_commands/list_providers.py +1 -1
- janito/cli/cli_commands/model_utils.py +45 -20
- janito/cli/cli_commands/ping_providers.py +10 -10
- janito/cli/cli_commands/set_api_key.py +5 -3
- janito/cli/cli_commands/show_config.py +13 -7
- janito/cli/cli_commands/show_system_prompt.py +13 -6
- janito/cli/core/getters.py +1 -0
- janito/cli/core/model_guesser.py +18 -15
- janito/cli/core/runner.py +15 -7
- janito/cli/core/setters.py +9 -6
- janito/cli/main_cli.py +15 -12
- janito/cli/prompt_setup.py +4 -4
- janito/cli/rich_terminal_reporter.py +2 -1
- janito/config_manager.py +2 -0
- janito/docs/GETTING_STARTED.md +9 -9
- janito/drivers/cerebras/__init__.py +1 -1
- janito/exceptions.py +6 -4
- janito/plugins/__init__.py +2 -2
- janito/plugins/base.py +48 -40
- janito/plugins/builtin.py +13 -9
- janito/plugins/config.py +16 -19
- janito/plugins/discovery.py +73 -66
- janito/plugins/manager.py +62 -60
- janito/provider_registry.py +10 -10
- janito/providers/__init__.py +1 -1
- janito/providers/alibaba/model_info.py +3 -5
- janito/providers/alibaba/provider.py +3 -1
- janito/providers/cerebras/__init__.py +1 -1
- janito/providers/cerebras/model_info.py +12 -27
- janito/providers/cerebras/provider.py +11 -9
- janito/providers/mistral/__init__.py +1 -1
- janito/providers/mistral/model_info.py +1 -1
- janito/providers/mistral/provider.py +1 -1
- janito/providers/moonshot/__init__.py +1 -0
- janito/providers/{moonshotai → moonshot}/model_info.py +3 -3
- janito/providers/{moonshotai → moonshot}/provider.py +8 -8
- janito/providers/openai/provider.py +3 -1
- janito/report_events.py +0 -1
- janito/tools/adapters/local/create_file.py +1 -1
- janito/tools/adapters/local/fetch_url.py +45 -29
- janito/tools/adapters/local/python_command_run.py +2 -1
- janito/tools/adapters/local/python_file_run.py +1 -0
- janito/tools/adapters/local/run_powershell_command.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/jinja2_validator.py +14 -11
- janito/tools/base.py +4 -3
- janito/tools/loop_protection.py +24 -22
- janito/tools/path_utils.py +7 -7
- janito/tools/tool_base.py +0 -2
- janito/tools/tools_adapter.py +15 -5
- janito/tools/url_whitelist.py +27 -26
- {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/METADATA +1 -1
- {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/RECORD +77 -77
- janito/providers/moonshotai/__init__.py +0 -1
- {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/WHEEL +0 -0
- {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/entry_points.txt +0 -0
- {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/top_level.txt +0 -0
@@ -64,6 +64,7 @@ def _load_template(profile, templates_dir):
|
|
64
64
|
# Also check user profiles directory
|
65
65
|
from pathlib import Path
|
66
66
|
import os
|
67
|
+
|
67
68
|
user_profiles_dir = Path(os.path.expanduser("~/.janito/profiles"))
|
68
69
|
user_template_path = user_profiles_dir / template_filename
|
69
70
|
if user_template_path.exists():
|
@@ -116,11 +117,11 @@ def handle_show_system_prompt(args):
|
|
116
117
|
Path(__file__).parent.parent.parent / "agent" / "templates" / "profiles"
|
117
118
|
)
|
118
119
|
profile = getattr(args, "profile", None)
|
119
|
-
|
120
|
+
|
120
121
|
# Handle --market flag mapping to Market Analyst profile
|
121
122
|
if profile is None and getattr(args, "market", False):
|
122
123
|
profile = "Market Analyst"
|
123
|
-
|
124
|
+
|
124
125
|
if not profile:
|
125
126
|
print(
|
126
127
|
"[janito] No profile specified. The main agent runs without a system prompt template.\n"
|
@@ -134,11 +135,17 @@ def handle_show_system_prompt(args):
|
|
134
135
|
if not template_content:
|
135
136
|
# Try to load directly from package resources as fallback
|
136
137
|
try:
|
137
|
-
template_content =
|
138
|
-
|
139
|
-
|
138
|
+
template_content = (
|
139
|
+
resources.files("janito.agent.templates.profiles")
|
140
|
+
.joinpath(
|
141
|
+
f"system_prompt_template_{profile.lower().replace(' ', '_')}.txt.j2"
|
142
|
+
)
|
143
|
+
.read_text(encoding="utf-8")
|
144
|
+
)
|
140
145
|
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
141
|
-
print(
|
146
|
+
print(
|
147
|
+
f"[janito] Could not find profile '{profile}'. This may be a configuration issue."
|
148
|
+
)
|
142
149
|
return
|
143
150
|
|
144
151
|
template = Template(template_content)
|
janito/cli/core/getters.py
CHANGED
janito/cli/core/model_guesser.py
CHANGED
@@ -8,44 +8,47 @@ from janito.providers.registry import LLMProviderRegistry
|
|
8
8
|
def guess_provider_from_model(model_name: str) -> str:
|
9
9
|
"""
|
10
10
|
Guess the provider based on the model name.
|
11
|
-
|
11
|
+
|
12
12
|
Args:
|
13
13
|
model_name: The name of the model to guess the provider for
|
14
|
-
|
14
|
+
|
15
15
|
Returns:
|
16
16
|
The provider name if a match is found, None otherwise
|
17
17
|
"""
|
18
18
|
if not model_name:
|
19
19
|
return None
|
20
|
-
|
20
|
+
|
21
21
|
model_name = model_name.lower()
|
22
|
-
|
22
|
+
|
23
23
|
# Check each provider's models
|
24
24
|
for provider_name in LLMProviderRegistry.list_providers():
|
25
25
|
provider_class = LLMProviderRegistry.get(provider_name)
|
26
26
|
if not provider_class:
|
27
27
|
continue
|
28
|
-
|
28
|
+
|
29
29
|
# Get model specs for this provider
|
30
30
|
try:
|
31
|
-
if hasattr(provider_class,
|
31
|
+
if hasattr(provider_class, "MODEL_SPECS"):
|
32
32
|
model_specs = provider_class.MODEL_SPECS
|
33
33
|
for spec_model_name in model_specs.keys():
|
34
34
|
if spec_model_name.lower() == model_name:
|
35
35
|
return provider_name
|
36
|
-
|
37
|
-
# Handle special cases like
|
38
|
-
if provider_name == "
|
36
|
+
|
37
|
+
# Handle special cases like moonshot
|
38
|
+
if provider_name == "moonshot":
|
39
39
|
try:
|
40
|
-
from janito.providers.
|
41
|
-
|
40
|
+
from janito.providers.moonshot.model_info import (
|
41
|
+
MOONSHOT_MODEL_SPECS,
|
42
|
+
)
|
43
|
+
|
44
|
+
for spec_model_name in MOONSHOT_MODEL_SPECS.keys():
|
42
45
|
if spec_model_name.lower() == model_name:
|
43
|
-
return "
|
46
|
+
return "moonshot"
|
44
47
|
except ImportError:
|
45
48
|
pass
|
46
|
-
|
49
|
+
|
47
50
|
except Exception:
|
48
51
|
# Skip providers that have issues accessing model specs
|
49
52
|
continue
|
50
|
-
|
51
|
-
return None
|
53
|
+
|
54
|
+
return None
|
janito/cli/core/runner.py
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
from janito.llm.driver_config import LLMDriverConfig
|
4
4
|
from janito.provider_config import get_config_provider
|
5
|
-
from janito.cli.core.model_guesser import
|
5
|
+
from janito.cli.core.model_guesser import (
|
6
|
+
guess_provider_from_model as _guess_provider_from_model,
|
7
|
+
)
|
6
8
|
from janito.cli.verbose_output import print_verbose_info
|
7
9
|
|
8
10
|
|
@@ -22,10 +24,13 @@ def _choose_provider(args):
|
|
22
24
|
if guessed_provider:
|
23
25
|
if getattr(args, "verbose", False):
|
24
26
|
print_verbose_info(
|
25
|
-
"Guessed provider",
|
27
|
+
"Guessed provider",
|
28
|
+
guessed_provider,
|
29
|
+
style="magenta",
|
30
|
+
align_content=True,
|
26
31
|
)
|
27
32
|
return guessed_provider
|
28
|
-
|
33
|
+
|
29
34
|
print(
|
30
35
|
"Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
31
36
|
)
|
@@ -151,9 +156,10 @@ def handle_runner(
|
|
151
156
|
if unrestricted:
|
152
157
|
# Patch: disable path security enforcement for this adapter instance
|
153
158
|
setattr(adapter, "unrestricted_paths", True)
|
154
|
-
|
159
|
+
|
155
160
|
# Also disable URL whitelist restrictions in unrestricted mode
|
156
161
|
from janito.tools.url_whitelist import get_url_whitelist_manager
|
162
|
+
|
157
163
|
whitelist_manager = get_url_whitelist_manager()
|
158
164
|
whitelist_manager.set_unrestricted_mode(True)
|
159
165
|
|
@@ -174,19 +180,21 @@ def handle_runner(
|
|
174
180
|
"Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
|
175
181
|
)
|
176
182
|
print_verbose_info("Agent role", agent_role, style="green")
|
177
|
-
|
183
|
+
|
178
184
|
# Skip chat mode for list commands - handle them directly
|
179
185
|
from janito.cli.core.getters import GETTER_KEYS
|
186
|
+
|
180
187
|
skip_chat_mode = False
|
181
188
|
if args is not None:
|
182
189
|
for key in GETTER_KEYS:
|
183
190
|
if getattr(args, key, False):
|
184
191
|
skip_chat_mode = True
|
185
192
|
break
|
186
|
-
|
193
|
+
|
187
194
|
if skip_chat_mode:
|
188
195
|
# Handle list commands directly without prompt
|
189
196
|
from janito.cli.core.getters import handle_getter
|
197
|
+
|
190
198
|
handle_getter(args)
|
191
199
|
elif mode == "single_shot":
|
192
200
|
from janito.cli.single_shot_mode.handler import (
|
@@ -222,4 +230,4 @@ def handle_runner(
|
|
222
230
|
|
223
231
|
|
224
232
|
def get_prompt_mode(args):
|
225
|
-
return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
|
233
|
+
return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
|
janito/cli/core/setters.py
CHANGED
@@ -71,8 +71,8 @@ def _dispatch_set_key(key, value):
|
|
71
71
|
return True
|
72
72
|
if key == "allowed_sites":
|
73
73
|
from janito.tools.url_whitelist import get_url_whitelist_manager
|
74
|
-
|
75
|
-
sites = [site.strip() for site in value.split(
|
74
|
+
|
75
|
+
sites = [site.strip() for site in value.split(",") if site.strip()]
|
76
76
|
whitelist_manager = get_url_whitelist_manager()
|
77
77
|
whitelist_manager.set_allowed_sites(sites)
|
78
78
|
global_config.file_set("allowed_sites", value)
|
@@ -103,20 +103,23 @@ def _handle_set_base_url(value):
|
|
103
103
|
|
104
104
|
def set_provider(value):
|
105
105
|
"""Set the current provider.
|
106
|
-
|
106
|
+
|
107
107
|
Args:
|
108
108
|
value (str): The provider name to set
|
109
|
-
|
109
|
+
|
110
110
|
Raises:
|
111
111
|
ValueError: If the provider is not supported
|
112
112
|
"""
|
113
113
|
try:
|
114
114
|
supported = ProviderRegistry().get_provider(value)
|
115
115
|
except Exception:
|
116
|
-
raise ValueError(
|
116
|
+
raise ValueError(
|
117
|
+
f"Provider '{value}' is not supported. Run '--list-providers' to see the supported list."
|
118
|
+
)
|
117
119
|
from janito.provider_config import set_config_provider
|
120
|
+
|
118
121
|
set_config_provider(value)
|
119
|
-
|
122
|
+
|
120
123
|
|
121
124
|
def _handle_set_config_provider(value):
|
122
125
|
try:
|
janito/cli/main_cli.py
CHANGED
@@ -134,7 +134,10 @@ definition = [
|
|
134
134
|
),
|
135
135
|
(
|
136
136
|
["--ping"],
|
137
|
-
{
|
137
|
+
{
|
138
|
+
"action": "store_true",
|
139
|
+
"help": "Ping/test connectivity for all providers (use with --list-providers)",
|
140
|
+
},
|
138
141
|
),
|
139
142
|
(
|
140
143
|
["--list-drivers"],
|
@@ -157,7 +160,6 @@ definition = [
|
|
157
160
|
"help": "List all providers with their regional API information",
|
158
161
|
},
|
159
162
|
),
|
160
|
-
|
161
163
|
(
|
162
164
|
["-l", "--list-models"],
|
163
165
|
{"action": "store_true", "help": "List all supported models"},
|
@@ -232,7 +234,10 @@ definition = [
|
|
232
234
|
),
|
233
235
|
(
|
234
236
|
["--list-resources"],
|
235
|
-
{
|
237
|
+
{
|
238
|
+
"action": "store_true",
|
239
|
+
"help": "List all resources (tools, commands, config) from loaded plugins",
|
240
|
+
},
|
236
241
|
),
|
237
242
|
]
|
238
243
|
|
@@ -292,9 +297,8 @@ class JanitoCLI:
|
|
292
297
|
|
293
298
|
self.parser = argparse.ArgumentParser(
|
294
299
|
description="Janito CLI - A tool for running LLM-powered workflows from the command line."
|
295
|
-
"\n\nExample usage: janito -p
|
300
|
+
"\n\nExample usage: janito -p moonshot -m kimi-k1-8k 'Your prompt here'\n\n"
|
296
301
|
"Use -m or --model to set the model for the session.",
|
297
|
-
|
298
302
|
)
|
299
303
|
self._define_args()
|
300
304
|
self.args = self.parser.parse_args()
|
@@ -346,8 +350,6 @@ class JanitoCLI:
|
|
346
350
|
|
347
351
|
argkwargs["version"] = f"Janito {janito_version}"
|
348
352
|
self.parser.add_argument(*argnames, **argkwargs)
|
349
|
-
|
350
|
-
|
351
353
|
|
352
354
|
def _set_all_arg_defaults(self):
|
353
355
|
# Gather all possible keys from definition, MODIFIER_KEYS, SETTER_KEYS, GETTER_KEYS
|
@@ -412,20 +414,21 @@ class JanitoCLI:
|
|
412
414
|
handle_getter(self.args)
|
413
415
|
return
|
414
416
|
# Handle /rwx prefix for enabling all permissions
|
415
|
-
if self.args.user_prompt and self.args.user_prompt[0] ==
|
417
|
+
if self.args.user_prompt and self.args.user_prompt[0] == "/rwx":
|
416
418
|
self.args.read = True
|
417
419
|
self.args.write = True
|
418
420
|
self.args.exec = True
|
419
421
|
# Remove the /rwx prefix from the prompt
|
420
422
|
self.args.user_prompt = self.args.user_prompt[1:]
|
421
|
-
elif self.args.user_prompt and self.args.user_prompt[0].startswith(
|
423
|
+
elif self.args.user_prompt and self.args.user_prompt[0].startswith("/"):
|
422
424
|
# Skip LLM processing for other commands that start with /
|
423
425
|
return
|
424
|
-
|
426
|
+
|
425
427
|
# If running in single shot mode and --profile is not provided, default to 'developer' profile
|
426
428
|
# Skip profile selection for list commands that don't need it
|
427
|
-
if
|
428
|
-
|
429
|
+
if get_prompt_mode(self.args) == "single_shot" and not getattr(
|
430
|
+
self.args, "profile", None
|
431
|
+
):
|
429
432
|
self.args.profile = "developer"
|
430
433
|
provider = self._get_provider_or_default()
|
431
434
|
if provider is None:
|
janito/cli/prompt_setup.py
CHANGED
@@ -35,10 +35,10 @@ def setup_agent_and_prompt_handler(
|
|
35
35
|
prompt handler that points to that agent.
|
36
36
|
"""
|
37
37
|
no_tools_mode = False
|
38
|
-
if hasattr(args,
|
39
|
-
no_tools_mode = getattr(args,
|
40
|
-
|
41
|
-
zero_mode = getattr(args,
|
38
|
+
if hasattr(args, "no_tools_mode"):
|
39
|
+
no_tools_mode = getattr(args, "no_tools_mode", False)
|
40
|
+
|
41
|
+
zero_mode = getattr(args, "zero", False)
|
42
42
|
agent = create_configured_agent(
|
43
43
|
provider_instance=provider_instance,
|
44
44
|
llm_driver_config=llm_driver_config,
|
@@ -139,11 +139,12 @@ class RichTerminalReporter(EventHandlerBase):
|
|
139
139
|
if not msg or not subtype:
|
140
140
|
return
|
141
141
|
if subtype == ReportSubtype.ACTION_INFO:
|
142
|
-
# Use orange for modification actions
|
142
|
+
# Use orange for all write/modification actions
|
143
143
|
modification_actions = (
|
144
144
|
getattr(ReportAction, "UPDATE", None),
|
145
145
|
getattr(ReportAction, "WRITE", None),
|
146
146
|
getattr(ReportAction, "DELETE", None),
|
147
|
+
getattr(ReportAction, "CREATE", None),
|
147
148
|
)
|
148
149
|
style = (
|
149
150
|
"orange1"
|
janito/config_manager.py
CHANGED
@@ -60,6 +60,7 @@ class ConfigManager:
|
|
60
60
|
if plugins_config:
|
61
61
|
try:
|
62
62
|
from janito.plugins.manager import PluginManager
|
63
|
+
|
63
64
|
plugin_manager = PluginManager()
|
64
65
|
plugin_manager.load_plugins_from_config({"plugins": plugins_config})
|
65
66
|
except Exception as e:
|
@@ -68,6 +69,7 @@ class ConfigManager:
|
|
68
69
|
# Try loading from user config directory
|
69
70
|
try:
|
70
71
|
from janito.plugins.manager import PluginManager
|
72
|
+
|
71
73
|
plugin_manager = PluginManager()
|
72
74
|
plugin_manager.load_plugins_from_user_config()
|
73
75
|
except Exception as e:
|
janito/docs/GETTING_STARTED.md
CHANGED
@@ -13,7 +13,7 @@ pip install janito
|
|
13
13
|
|
14
14
|
Janito supports multiple AI providers. Choose one to get started:
|
15
15
|
|
16
|
-
**
|
16
|
+
**Moonshot (Recommended for Chinese users)**
|
17
17
|
1. Go to [Moonshot AI Platform](https://platform.moonshot.cn/)
|
18
18
|
2. Sign up for an account
|
19
19
|
3. Navigate to API Keys section
|
@@ -31,10 +31,10 @@ Janito supports multiple AI providers. Choose one to get started:
|
|
31
31
|
|
32
32
|
### 3. Configure Janito
|
33
33
|
|
34
|
-
**
|
34
|
+
**Moonshot Setup:**
|
35
35
|
```bash
|
36
|
-
# Set
|
37
|
-
janito --set-api-key YOUR_API_KEY -p
|
36
|
+
# Set Moonshot as your default provider
|
37
|
+
janito --set-api-key YOUR_API_KEY -p moonshot
|
38
38
|
|
39
39
|
# Verify it's working
|
40
40
|
janito "Hello, can you introduce yourself?"
|
@@ -87,17 +87,17 @@ janito -W ./my_project "Create a REST API with FastAPI"
|
|
87
87
|
### Set as Default Provider
|
88
88
|
```bash
|
89
89
|
# Make your chosen provider the permanent default
|
90
|
-
janito --set provider=
|
90
|
+
janito --set provider=moonshot # or openai, ibm, etc.
|
91
91
|
janito --set model=kimi-k1-8k # or gpt-5, ibm/granite-3-8b-instruct, etc.
|
92
92
|
```
|
93
93
|
|
94
94
|
### Environment Variables
|
95
95
|
You can also use environment variables:
|
96
96
|
|
97
|
-
**
|
97
|
+
**Moonshot:**
|
98
98
|
```bash
|
99
|
-
export
|
100
|
-
export JANITO_PROVIDER=
|
99
|
+
export MOONSHOT_API_KEY=your_key_here
|
100
|
+
export JANITO_PROVIDER=moonshot
|
101
101
|
export JANITO_MODEL=kimi-k1-8k
|
102
102
|
```
|
103
103
|
|
@@ -119,7 +119,7 @@ export JANITO_MODEL=ibm/granite-3-3-8b-instruct
|
|
119
119
|
|
120
120
|
## Available Models by Provider
|
121
121
|
|
122
|
-
###
|
122
|
+
### Moonshot Models
|
123
123
|
- **kimi-k1-8k**: Fast responses, good for general tasks
|
124
124
|
- **kimi-k1-32k**: Better for longer contexts
|
125
125
|
- **kimi-k1-128k**: Best for very long documents
|
@@ -1 +1 @@
|
|
1
|
-
# Cerebras driver package
|
1
|
+
# Cerebras driver package
|
janito/exceptions.py
CHANGED
@@ -9,11 +9,11 @@ class ToolCallException(Exception):
|
|
9
9
|
self.error = error
|
10
10
|
self.arguments = arguments
|
11
11
|
self.original_exception = exception
|
12
|
-
|
12
|
+
|
13
13
|
# Build detailed error message
|
14
14
|
details = []
|
15
15
|
details.append(f"ToolCallException: {tool_name}: {error}")
|
16
|
-
|
16
|
+
|
17
17
|
if arguments is not None:
|
18
18
|
details.append(f"Arguments received: {arguments}")
|
19
19
|
if isinstance(arguments, dict):
|
@@ -25,8 +25,10 @@ class ToolCallException(Exception):
|
|
25
25
|
for i, value in enumerate(arguments):
|
26
26
|
details.append(f" [{i}]: {repr(value)} ({type(value).__name__})")
|
27
27
|
else:
|
28
|
-
details.append(
|
29
|
-
|
28
|
+
details.append(
|
29
|
+
f"Single argument: {repr(arguments)} ({type(arguments).__name__})"
|
30
|
+
)
|
31
|
+
|
30
32
|
super().__init__("\n".join(details))
|
31
33
|
|
32
34
|
|
janito/plugins/__init__.py
CHANGED
janito/plugins/base.py
CHANGED
@@ -11,6 +11,7 @@ from janito.tools.tool_base import ToolBase
|
|
11
11
|
@dataclass
|
12
12
|
class PluginMetadata:
|
13
13
|
"""Metadata describing a plugin."""
|
14
|
+
|
14
15
|
name: str
|
15
16
|
version: str
|
16
17
|
description: str
|
@@ -18,7 +19,7 @@ class PluginMetadata:
|
|
18
19
|
license: str = "MIT"
|
19
20
|
homepage: Optional[str] = None
|
20
21
|
dependencies: List[str] = None
|
21
|
-
|
22
|
+
|
22
23
|
def __post_init__(self):
|
23
24
|
if self.dependencies is None:
|
24
25
|
self.dependencies = []
|
@@ -27,6 +28,7 @@ class PluginMetadata:
|
|
27
28
|
@dataclass
|
28
29
|
class PluginResource:
|
29
30
|
"""Represents a resource provided by a plugin."""
|
31
|
+
|
30
32
|
name: str
|
31
33
|
type: str # "tool", "command", "config"
|
32
34
|
description: str
|
@@ -36,66 +38,66 @@ class PluginResource:
|
|
36
38
|
class Plugin(ABC):
|
37
39
|
"""
|
38
40
|
Base class for all janito plugins.
|
39
|
-
|
41
|
+
|
40
42
|
Plugins can provide tools, commands, or other functionality.
|
41
43
|
"""
|
42
|
-
|
44
|
+
|
43
45
|
def __init__(self):
|
44
46
|
self.metadata: PluginMetadata = self.get_metadata()
|
45
|
-
|
47
|
+
|
46
48
|
@abstractmethod
|
47
49
|
def get_metadata(self) -> PluginMetadata:
|
48
50
|
"""Return metadata describing this plugin."""
|
49
51
|
pass
|
50
|
-
|
52
|
+
|
51
53
|
def get_tools(self) -> List[Type[ToolBase]]:
|
52
54
|
"""
|
53
55
|
Return a list of tool classes provided by this plugin.
|
54
|
-
|
56
|
+
|
55
57
|
Returns:
|
56
58
|
List of ToolBase subclasses that should be registered
|
57
59
|
"""
|
58
60
|
return []
|
59
|
-
|
61
|
+
|
60
62
|
def get_commands(self) -> Dict[str, Any]:
|
61
63
|
"""
|
62
64
|
Return a dictionary of CLI commands provided by this plugin.
|
63
|
-
|
65
|
+
|
64
66
|
Returns:
|
65
67
|
Dict mapping command names to command handlers
|
66
68
|
"""
|
67
69
|
return {}
|
68
|
-
|
70
|
+
|
69
71
|
def initialize(self) -> None:
|
70
72
|
"""
|
71
73
|
Called when the plugin is loaded.
|
72
74
|
Override to perform any initialization needed.
|
73
75
|
"""
|
74
76
|
pass
|
75
|
-
|
77
|
+
|
76
78
|
def cleanup(self) -> None:
|
77
79
|
"""
|
78
80
|
Called when the plugin is unloaded.
|
79
81
|
Override to perform any cleanup needed.
|
80
82
|
"""
|
81
83
|
pass
|
82
|
-
|
84
|
+
|
83
85
|
def get_config_schema(self) -> Dict[str, Any]:
|
84
86
|
"""
|
85
87
|
Return JSON schema for plugin configuration.
|
86
|
-
|
88
|
+
|
87
89
|
Returns:
|
88
90
|
JSON schema dict describing configuration options
|
89
91
|
"""
|
90
92
|
return {}
|
91
|
-
|
93
|
+
|
92
94
|
def validate_config(self, config: Dict[str, Any]) -> bool:
|
93
95
|
"""
|
94
96
|
Validate plugin configuration.
|
95
|
-
|
97
|
+
|
96
98
|
Args:
|
97
99
|
config: Configuration dict to validate
|
98
|
-
|
100
|
+
|
99
101
|
Returns:
|
100
102
|
True if configuration is valid
|
101
103
|
"""
|
@@ -104,41 +106,47 @@ class Plugin(ABC):
|
|
104
106
|
def get_resources(self) -> List[PluginResource]:
|
105
107
|
"""
|
106
108
|
Return a list of resources provided by this plugin.
|
107
|
-
|
109
|
+
|
108
110
|
Returns:
|
109
111
|
List of PluginResource objects describing the resources
|
110
112
|
"""
|
111
113
|
resources = []
|
112
|
-
|
114
|
+
|
113
115
|
# Add tools as resources
|
114
116
|
for tool_class in self.get_tools():
|
115
117
|
tool_instance = tool_class()
|
116
|
-
tool_name = getattr(tool_instance,
|
117
|
-
tool_desc = getattr(tool_class,
|
118
|
-
resources.append(
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
tool_name = getattr(tool_instance, "tool_name", tool_class.__name__)
|
119
|
+
tool_desc = getattr(tool_class, "__doc__", f"Tool: {tool_name}")
|
120
|
+
resources.append(
|
121
|
+
PluginResource(
|
122
|
+
name=tool_name,
|
123
|
+
type="tool",
|
124
|
+
description=tool_desc or f"Tool provided by {self.metadata.name}",
|
125
|
+
)
|
126
|
+
)
|
127
|
+
|
124
128
|
# Add commands as resources
|
125
129
|
commands = self.get_commands()
|
126
130
|
for cmd_name, cmd_handler in commands.items():
|
127
|
-
cmd_desc = getattr(cmd_handler,
|
128
|
-
resources.append(
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
131
|
+
cmd_desc = getattr(cmd_handler, "__doc__", f"Command: {cmd_name}")
|
132
|
+
resources.append(
|
133
|
+
PluginResource(
|
134
|
+
name=cmd_name,
|
135
|
+
type="command",
|
136
|
+
description=cmd_desc or f"Command provided by {self.metadata.name}",
|
137
|
+
)
|
138
|
+
)
|
139
|
+
|
134
140
|
# Add config schema as resource
|
135
141
|
config_schema = self.get_config_schema()
|
136
142
|
if config_schema:
|
137
|
-
resources.append(
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
resources.append(
|
144
|
+
PluginResource(
|
145
|
+
name=f"{self.metadata.name}_config",
|
146
|
+
type="config",
|
147
|
+
description=f"Configuration schema for {self.metadata.name} plugin",
|
148
|
+
schema=config_schema,
|
149
|
+
)
|
150
|
+
)
|
151
|
+
|
152
|
+
return resources
|