janito 2.10.0__py3-none-any.whl → 2.14.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.
@@ -12,7 +12,7 @@ from queue import Queue
12
12
  from rich import print as rich_print
13
13
  from janito.tools import get_local_tools_adapter
14
14
  from janito.llm.agent import LLMAgent
15
- from janito.drivers.driver_registry import get_driver_class
15
+
16
16
  from janito.platform_discovery import PlatformDiscovery
17
17
  from janito.tools.tool_base import ToolPermissions
18
18
  from janito.tools.permissions import get_global_allowed_permissions
@@ -109,6 +109,9 @@ class ChatSession:
109
109
  )
110
110
  self._support = False
111
111
 
112
+ # Check if multi-line mode should be enabled by default
113
+ self.multi_line_mode = getattr(args, "multi", False) if args else False
114
+
112
115
  def _select_profile_and_role(self, args, role):
113
116
  profile = getattr(args, "profile", None) if args is not None else None
114
117
  role_arg = getattr(args, "role", None) if args is not None else None
@@ -213,6 +216,11 @@ class ChatSession:
213
216
  f"[green]Working Dir:[/green] {cwd_display} | {priv_status}"
214
217
  )
215
218
 
219
+ if self.multi_line_mode:
220
+ self.console.print(
221
+ "[blue]Multi-line input mode enabled (Esc+Enter or Ctrl+D to submit)[/blue]"
222
+ )
223
+
216
224
  from janito.cli.chat_mode.shell.commands._priv_check import (
217
225
  user_has_any_privileges,
218
226
  )
@@ -305,6 +313,7 @@ class ChatSession:
305
313
  bottom_toolbar=lambda: get_toolbar_func(
306
314
  self.performance_collector, 0, self.shell_state
307
315
  )(),
316
+ multiline=self.multi_line_mode,
308
317
  )
309
318
 
310
319
  def _handle_input(self, session):
@@ -0,0 +1,137 @@
1
+ """
2
+ CLI Command: List available LLM drivers and their dependencies
3
+ """
4
+
5
+ import importlib
6
+ import sys
7
+ from pathlib import Path
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+ from rich.panel import Panel
11
+ from rich.text import Text
12
+
13
+ console = Console()
14
+
15
+
16
+ def get_driver_info():
17
+ """Get information about all available drivers."""
18
+ drivers = []
19
+
20
+ # Define known driver modules
21
+ driver_modules = [
22
+ ("janito.drivers.openai.driver", "OpenAIModelDriver"),
23
+ ("janito.drivers.azure_openai.driver", "AzureOpenAIModelDriver"),
24
+ ("janito.drivers.zai.driver", "ZAIModelDriver"),
25
+ ]
26
+
27
+ for module_path, class_name in driver_modules:
28
+ try:
29
+ # Import the module
30
+ module = importlib.import_module(module_path)
31
+ driver_class = getattr(module, class_name)
32
+
33
+ # Get availability info
34
+ available = getattr(driver_class, 'available', True)
35
+ unavailable_reason = getattr(driver_class, 'unavailable_reason', None)
36
+
37
+ # Get dependencies from module imports
38
+ dependencies = []
39
+ module_file = Path(module.__file__)
40
+
41
+ # Read module file to detect imports
42
+ with open(module_file, 'r', encoding='utf-8') as f:
43
+ content = f.read()
44
+
45
+ # Simple dependency detection
46
+ if 'import openai' in content or 'from openai' in content:
47
+ dependencies.append('openai')
48
+ if 'import zai' in content or 'from zai' in content:
49
+ dependencies.append('zai')
50
+ if 'import anthropic' in content or 'from anthropic' in content:
51
+ dependencies.append('anthropic')
52
+ if 'import google' in content or 'from google' in content:
53
+ dependencies.append('google-generativeai')
54
+
55
+
56
+
57
+ # Remove duplicates while preserving order
58
+ seen = set()
59
+ dependencies = [dep for dep in dependencies if not (dep in seen or seen.add(dep))]
60
+
61
+ # Check if dependencies are available
62
+ dep_status = []
63
+ for dep in dependencies:
64
+ try:
65
+ importlib.import_module(dep)
66
+ dep_status.append(f"✅ {dep}")
67
+ except ImportError:
68
+ dep_status.append(f"❌ {dep}")
69
+
70
+ if not dependencies:
71
+ dep_status = ["No external dependencies"]
72
+
73
+ drivers.append({
74
+ 'name': class_name,
75
+ 'available': available,
76
+ 'reason': unavailable_reason,
77
+ 'dependencies': dep_status
78
+ })
79
+
80
+ except (ImportError, AttributeError) as e:
81
+ drivers.append({
82
+ 'name': class_name,
83
+ 'module': module_path,
84
+ 'available': False,
85
+ 'reason': str(e),
86
+ 'dependencies': ["❌ Module not found"]
87
+ })
88
+
89
+ return drivers
90
+
91
+
92
+ def handle_list_drivers(args=None):
93
+ """List all available LLM drivers with their status and dependencies."""
94
+ drivers = get_driver_info()
95
+
96
+ if not drivers:
97
+ console.print("[red]No drivers found[/red]")
98
+ return
99
+
100
+ # Create table
101
+ table = Table(title="Available LLM Drivers")
102
+ table.add_column("Driver", style="cyan", no_wrap=True)
103
+ table.add_column("Status", style="bold")
104
+ table.add_column("Dependencies", style="yellow")
105
+
106
+ for driver in drivers:
107
+ name = driver['name']
108
+
109
+ if driver['available']:
110
+ status = "[green]✅ Available[/green]"
111
+ if driver['reason']:
112
+ status = f"[yellow]⚠️ Available ({driver['reason']})[/yellow]"
113
+ else:
114
+ status = f"[red]❌ Unavailable[/red]"
115
+ if driver['reason']:
116
+ status = f"[red]❌ {driver['reason']}[/red]"
117
+
118
+ deps = "\n".join(driver['dependencies'])
119
+
120
+ table.add_row(name, status, deps)
121
+
122
+ console.print(table)
123
+
124
+ # Installation help
125
+ # Get unique missing dependencies
126
+ missing_deps = set()
127
+ for driver in drivers:
128
+ for dep_status in driver['dependencies']:
129
+ if dep_status.startswith('❌'):
130
+ missing_deps.add(dep_status[2:].strip())
131
+
132
+ if missing_deps:
133
+ console.print(f"\n[dim]💡 Install missing deps: pip install {' '.join(sorted(missing_deps))}[/dim]")
134
+
135
+
136
+ if __name__ == "__main__":
137
+ handle_list_drivers()
@@ -7,6 +7,7 @@ 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
8
  from janito.cli.cli_commands.show_config import handle_show_config
9
9
  from janito.cli.cli_commands.list_config import handle_list_config
10
+ from janito.cli.cli_commands.list_drivers import handle_list_drivers
10
11
  from functools import partial
11
12
  from janito.provider_registry import ProviderRegistry
12
13
 
@@ -17,6 +18,7 @@ GETTER_KEYS = [
17
18
  "list_models",
18
19
  "list_tools",
19
20
  "list_config",
21
+ "list_drivers",
20
22
  ]
21
23
 
22
24
 
@@ -42,7 +44,10 @@ def handle_getter(args, config_mgr=None):
42
44
  "list_profiles": partial(handle_list_profiles, args),
43
45
  "show_config": partial(handle_show_config, args),
44
46
  "list_config": partial(handle_list_config, args),
47
+ "list_drivers": partial(handle_list_drivers, args),
45
48
  }
46
49
  for arg in GETTER_KEYS:
47
50
  if getattr(args, arg, False) and arg in GETTER_DISPATCH:
48
- return GETTER_DISPATCH[arg]()
51
+ GETTER_DISPATCH[arg]()
52
+ import sys
53
+ sys.exit(0)
@@ -0,0 +1,51 @@
1
+ """
2
+ Module for guessing the provider based on model names.
3
+ """
4
+
5
+ from janito.providers.registry import LLMProviderRegistry
6
+
7
+
8
+ def guess_provider_from_model(model_name: str) -> str:
9
+ """
10
+ Guess the provider based on the model name.
11
+
12
+ Args:
13
+ model_name: The name of the model to guess the provider for
14
+
15
+ Returns:
16
+ The provider name if a match is found, None otherwise
17
+ """
18
+ if not model_name:
19
+ return None
20
+
21
+ model_name = model_name.lower()
22
+
23
+ # Check each provider's models
24
+ for provider_name in LLMProviderRegistry.list_providers():
25
+ provider_class = LLMProviderRegistry.get(provider_name)
26
+ if not provider_class:
27
+ continue
28
+
29
+ # Get model specs for this provider
30
+ try:
31
+ if hasattr(provider_class, 'MODEL_SPECS'):
32
+ model_specs = provider_class.MODEL_SPECS
33
+ for spec_model_name in model_specs.keys():
34
+ if spec_model_name.lower() == model_name:
35
+ return provider_name
36
+
37
+ # Handle special cases like moonshotai
38
+ if provider_name == "moonshotai":
39
+ try:
40
+ from janito.providers.moonshotai.model_info import MOONSHOTAI_MODEL_SPECS
41
+ for spec_model_name in MOONSHOTAI_MODEL_SPECS.keys():
42
+ if spec_model_name.lower() == model_name:
43
+ return "moonshotai"
44
+ except ImportError:
45
+ pass
46
+
47
+ except Exception:
48
+ # Skip providers that have issues accessing model specs
49
+ continue
50
+
51
+ return None
janito/cli/core/runner.py CHANGED
@@ -2,6 +2,7 @@
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
6
  from janito.cli.verbose_output import print_verbose_info
6
7
 
7
8
 
@@ -14,6 +15,17 @@ def _choose_provider(args):
14
15
  "Default provider", provider, style="magenta", align_content=True
15
16
  )
16
17
  elif provider is None:
18
+ # Try to guess provider based on model name if -m is provided
19
+ model = getattr(args, "model", None)
20
+ if model:
21
+ guessed_provider = _guess_provider_from_model(model)
22
+ if guessed_provider:
23
+ if getattr(args, "verbose", False):
24
+ print_verbose_info(
25
+ "Guessed provider", guessed_provider, style="magenta", align_content=True
26
+ )
27
+ return guessed_provider
28
+
17
29
  print(
18
30
  "Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
19
31
  )
@@ -191,4 +203,4 @@ def handle_runner(
191
203
 
192
204
 
193
205
  def get_prompt_mode(args):
194
- return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
206
+ return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
janito/cli/main_cli.py CHANGED
@@ -21,6 +21,13 @@ definition = [
21
21
  "help": "Disable path security: allow tool arguments to use any file/directory path (DANGEROUS)",
22
22
  },
23
23
  ),
24
+ (
25
+ ["--multi"],
26
+ {
27
+ "action": "store_true",
28
+ "help": "Start chat mode with multi-line input as default (no need for /multi command)",
29
+ },
30
+ ),
24
31
  (
25
32
  ["--profile"],
26
33
  {
@@ -110,6 +117,10 @@ definition = [
110
117
  ["--list-providers"],
111
118
  {"action": "store_true", "help": "List supported LLM providers"},
112
119
  ),
120
+ (
121
+ ["--list-drivers"],
122
+ {"action": "store_true", "help": "List available LLM drivers and their dependencies"},
123
+ ),
113
124
  (
114
125
  ["-l", "--list-models"],
115
126
  {"action": "store_true", "help": "List all supported models"},
@@ -199,6 +210,7 @@ GETTER_KEYS = [
199
210
  "list_models",
200
211
  "list_tools",
201
212
  "list_config",
213
+ "list_drivers",
202
214
  ]
203
215
 
204
216
 
@@ -314,14 +326,8 @@ class JanitoCLI:
314
326
  if run_mode == RunMode.SET:
315
327
  if self._run_set_mode():
316
328
  return
317
- # Special handling: provider is not required for list_providers, list_tools, show_config
318
- if run_mode == RunMode.GET and (
319
- self.args.list_providers
320
- or self.args.list_tools
321
- or self.args.list_profiles
322
- or self.args.show_config
323
- or self.args.list_config
324
- ):
329
+ # Special handling: provider is not required for list_providers, list_tools, show_config, list_drivers
330
+ if run_mode == RunMode.GET:
325
331
  self._maybe_print_verbose_provider_model()
326
332
  handle_getter(self.args)
327
333
  return
@@ -357,8 +363,7 @@ class JanitoCLI:
357
363
  agent_role,
358
364
  verbose_tools=self.args.verbose_tools,
359
365
  )
360
- elif run_mode == RunMode.GET:
361
- handle_getter(self.args)
366
+
362
367
 
363
368
  def _run_set_mode(self):
364
369
  if handle_api_key_set(self.args):
@@ -44,9 +44,10 @@ class OpenAIModelDriver(LLMDriver):
44
44
 
45
45
  tool_classes = self.tools_adapter.get_tool_classes()
46
46
  tool_schemas = generate_tool_schemas(tool_classes)
47
- api_kwargs["tools"] = tool_schemas
47
+ if tool_schemas: # Only add tools if we have actual schemas
48
+ api_kwargs["tools"] = tool_schemas
48
49
  except Exception as e:
49
- api_kwargs["tools"] = []
50
+ # Don't add empty tools array - some providers reject it
50
51
  if hasattr(config, "verbose_api") and config.verbose_api:
51
52
  print(f"[OpenAIModelDriver] Tool schema generation failed: {e}")
52
53
  # OpenAI-specific parameters
@@ -0,0 +1 @@
1
+ # Z.AI driver package