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.
Files changed (78) hide show
  1. janito/README.md +9 -9
  2. janito/agent/setup_agent.py +29 -16
  3. janito/cli/chat_mode/script_runner.py +1 -1
  4. janito/cli/chat_mode/session.py +160 -56
  5. janito/cli/chat_mode/session_profile_select.py +8 -2
  6. janito/cli/chat_mode/shell/commands/execute.py +4 -2
  7. janito/cli/chat_mode/shell/commands/help.py +2 -0
  8. janito/cli/chat_mode/shell/commands/privileges.py +6 -2
  9. janito/cli/chat_mode/shell/commands/provider.py +7 -4
  10. janito/cli/chat_mode/shell/commands/read.py +4 -2
  11. janito/cli/chat_mode/shell/commands/security/__init__.py +1 -1
  12. janito/cli/chat_mode/shell/commands/security/allowed_sites.py +16 -13
  13. janito/cli/chat_mode/shell/commands/security_command.py +14 -10
  14. janito/cli/chat_mode/shell/commands/tools.py +4 -2
  15. janito/cli/chat_mode/shell/commands/unrestricted.py +17 -12
  16. janito/cli/chat_mode/shell/commands/write.py +4 -2
  17. janito/cli/chat_mode/toolbar.py +4 -4
  18. janito/cli/cli_commands/enable_disable_plugin.py +48 -25
  19. janito/cli/cli_commands/list_models.py +2 -2
  20. janito/cli/cli_commands/list_plugins.py +18 -18
  21. janito/cli/cli_commands/list_profiles.py +6 -6
  22. janito/cli/cli_commands/list_providers.py +1 -1
  23. janito/cli/cli_commands/model_utils.py +45 -20
  24. janito/cli/cli_commands/ping_providers.py +10 -10
  25. janito/cli/cli_commands/set_api_key.py +5 -3
  26. janito/cli/cli_commands/show_config.py +13 -7
  27. janito/cli/cli_commands/show_system_prompt.py +13 -6
  28. janito/cli/core/getters.py +1 -0
  29. janito/cli/core/model_guesser.py +18 -15
  30. janito/cli/core/runner.py +15 -7
  31. janito/cli/core/setters.py +9 -6
  32. janito/cli/main_cli.py +15 -12
  33. janito/cli/prompt_setup.py +4 -4
  34. janito/cli/rich_terminal_reporter.py +2 -1
  35. janito/config_manager.py +2 -0
  36. janito/docs/GETTING_STARTED.md +9 -9
  37. janito/drivers/cerebras/__init__.py +1 -1
  38. janito/exceptions.py +6 -4
  39. janito/plugins/__init__.py +2 -2
  40. janito/plugins/base.py +48 -40
  41. janito/plugins/builtin.py +13 -9
  42. janito/plugins/config.py +16 -19
  43. janito/plugins/discovery.py +73 -66
  44. janito/plugins/manager.py +62 -60
  45. janito/provider_registry.py +10 -10
  46. janito/providers/__init__.py +1 -1
  47. janito/providers/alibaba/model_info.py +3 -5
  48. janito/providers/alibaba/provider.py +3 -1
  49. janito/providers/cerebras/__init__.py +1 -1
  50. janito/providers/cerebras/model_info.py +12 -27
  51. janito/providers/cerebras/provider.py +11 -9
  52. janito/providers/mistral/__init__.py +1 -1
  53. janito/providers/mistral/model_info.py +1 -1
  54. janito/providers/mistral/provider.py +1 -1
  55. janito/providers/moonshot/__init__.py +1 -0
  56. janito/providers/{moonshotai → moonshot}/model_info.py +3 -3
  57. janito/providers/{moonshotai → moonshot}/provider.py +8 -8
  58. janito/providers/openai/provider.py +3 -1
  59. janito/report_events.py +0 -1
  60. janito/tools/adapters/local/create_file.py +1 -1
  61. janito/tools/adapters/local/fetch_url.py +45 -29
  62. janito/tools/adapters/local/python_command_run.py +2 -1
  63. janito/tools/adapters/local/python_file_run.py +1 -0
  64. janito/tools/adapters/local/run_powershell_command.py +1 -1
  65. janito/tools/adapters/local/validate_file_syntax/jinja2_validator.py +14 -11
  66. janito/tools/base.py +4 -3
  67. janito/tools/loop_protection.py +24 -22
  68. janito/tools/path_utils.py +7 -7
  69. janito/tools/tool_base.py +0 -2
  70. janito/tools/tools_adapter.py +15 -5
  71. janito/tools/url_whitelist.py +27 -26
  72. {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/METADATA +1 -1
  73. {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/RECORD +77 -77
  74. janito/providers/moonshotai/__init__.py +0 -1
  75. {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/WHEEL +0 -0
  76. {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/entry_points.txt +0 -0
  77. {janito-2.27.1.dist-info → janito-2.29.0.dist-info}/licenses/LICENSE +0 -0
  78. {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 = resources.files("janito.agent.templates.profiles").joinpath(
138
- f"system_prompt_template_{profile.lower().replace(' ', '_')}.txt.j2"
139
- ).read_text(encoding="utf-8")
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(f"[janito] Could not find profile '{profile}'. This may be a configuration issue.")
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)
@@ -35,6 +35,7 @@ def get_current_provider():
35
35
  """Get the current provider from the global config."""
36
36
  return global_config.get("provider", "none")
37
37
 
38
+
38
39
  def handle_getter(args, config_mgr=None):
39
40
  provider_instance = None
40
41
  if getattr(args, "list_models", False):
@@ -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, 'MODEL_SPECS'):
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 moonshotai
38
- if provider_name == "moonshotai":
36
+
37
+ # Handle special cases like moonshot
38
+ if provider_name == "moonshot":
39
39
  try:
40
- from janito.providers.moonshotai.model_info import MOONSHOTAI_MODEL_SPECS
41
- for spec_model_name in MOONSHOTAI_MODEL_SPECS.keys():
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 "moonshotai"
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 guess_provider_from_model as _guess_provider_from_model
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", guessed_provider, style="magenta", align_content=True
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"
@@ -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(',') if site.strip()]
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(f"Provider '{value}' is not supported. Run '--list-providers' to see the supported list.")
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
- {"action": "store_true", "help": "Ping/test connectivity for all providers (use with --list-providers)"},
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
- {"action": "store_true", "help": "List all resources (tools, commands, config) from loaded plugins"},
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 moonshotai -m kimi-k1-8k 'Your prompt here'\n\n"
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] == '/rwx':
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 (get_prompt_mode(self.args) == "single_shot" and
428
- not getattr(self.args, "profile", None)):
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:
@@ -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, 'no_tools_mode'):
39
- no_tools_mode = getattr(args, 'no_tools_mode', False)
40
-
41
- zero_mode = getattr(args, 'zero', False)
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, cyan otherwise
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:
@@ -13,7 +13,7 @@ pip install janito
13
13
 
14
14
  Janito supports multiple AI providers. Choose one to get started:
15
15
 
16
- **MoonshotAI (Recommended for Chinese users)**
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
- **MoonshotAI Setup:**
34
+ **Moonshot Setup:**
35
35
  ```bash
36
- # Set MoonshotAI as your default provider
37
- janito --set-api-key YOUR_API_KEY -p moonshotai
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=moonshotai # or openai, ibm, etc.
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
- **MoonshotAI:**
97
+ **Moonshot:**
98
98
  ```bash
99
- export MOONSHOTAI_API_KEY=your_key_here
100
- export JANITO_PROVIDER=moonshotai
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
- ### MoonshotAI Models
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(f"Single argument: {repr(arguments)} ({type(arguments).__name__})")
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
 
@@ -12,6 +12,6 @@ from .discovery import discover_plugins
12
12
  __all__ = [
13
13
  "PluginManager",
14
14
  "Plugin",
15
- "PluginMetadata",
15
+ "PluginMetadata",
16
16
  "discover_plugins",
17
- ]
17
+ ]
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, 'tool_name', tool_class.__name__)
117
- tool_desc = getattr(tool_class, '__doc__', f"Tool: {tool_name}")
118
- resources.append(PluginResource(
119
- name=tool_name,
120
- type="tool",
121
- description=tool_desc or f"Tool provided by {self.metadata.name}"
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, '__doc__', f"Command: {cmd_name}")
128
- resources.append(PluginResource(
129
- name=cmd_name,
130
- type="command",
131
- description=cmd_desc or f"Command provided by {self.metadata.name}"
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(PluginResource(
138
- name=f"{self.metadata.name}_config",
139
- type="config",
140
- description=f"Configuration schema for {self.metadata.name} plugin",
141
- schema=config_schema
142
- ))
143
-
144
- return resources
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