janito 3.12.1__py3-none-any.whl → 3.12.3__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/cli/core/runner.py CHANGED
@@ -1,266 +1,250 @@
1
- """Handles LLM driver config preparation and execution modes."""
2
-
3
- from janito.llm.driver_config import LLMDriverConfig
4
- from janito.provider_config import get_config_provider
5
- from janito.cli.core.model_guesser import (
6
- guess_provider_from_model as _guess_provider_from_model,
7
- )
8
- from janito.cli.verbose_output import print_verbose_info
9
-
10
-
11
- def _choose_provider(args):
12
- provider = getattr(args, "provider", None)
13
- if provider is None:
14
- provider = get_config_provider()
15
- if provider and getattr(args, "verbose", False):
16
- print_verbose_info(
17
- "Default provider", provider, style="magenta", align_content=True
18
- )
19
- elif provider is None:
20
- # Try to guess provider based on model name if -m is provided
21
- model = getattr(args, "model", None)
22
- if model:
23
- guessed_provider = _guess_provider_from_model(model)
24
- if guessed_provider:
25
- if getattr(args, "verbose", False):
26
- print_verbose_info(
27
- "Guessed provider",
28
- guessed_provider,
29
- style="magenta",
30
- align_content=True,
31
- )
32
- return guessed_provider
33
-
34
- print(
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."
36
- )
37
- return None
38
- return provider
39
-
40
-
41
- def _select_coder_model_for_provider(provider: str) -> str:
42
- """Auto-select the best coder model for the given provider when --developer mode is used."""
43
- coder_models = {
44
- "alibaba": "qwen3-coder-plus",
45
- "cerebras": "qwen-3-coder-480b",
46
- }
47
-
48
- return coder_models.get(provider)
49
-
50
-
51
- def _populate_driver_config_data(args, modifiers, provider, model):
52
- from janito.provider_config import get_effective_setting
53
-
54
- CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
55
- driver_config_data = {"model": model}
56
- if getattr(args, "verbose_api", None) is not None:
57
- driver_config_data["verbose_api"] = args.verbose_api
58
-
59
- # Add reasoning_effort from --effort CLI argument
60
- if getattr(args, "effort", None) is not None:
61
- driver_config_data["reasoning_effort"] = args.effort
62
- for field in LLMDriverConfig.__dataclass_fields__:
63
- if field in CONFIG_LOOKUP_KEYS:
64
- if field in modifiers and modifiers[field] is not None:
65
- driver_config_data[field] = modifiers[field]
66
- else:
67
- value = get_effective_setting(provider, model, field)
68
- if value is not None:
69
- driver_config_data[field] = value
70
- elif field in modifiers and field != "model":
71
- driver_config_data[field] = modifiers[field]
72
- return driver_config_data
73
-
74
-
75
- def prepare_llm_driver_config(args, modifiers):
76
- """Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
77
-
78
- This helper additionally validates that the chosen ``--model`` (or the
79
- resolved model coming from config precedence) is actually available for the
80
- selected provider. If the combination is invalid an error is printed and
81
- ``None`` is returned for the config so that the caller can abort execution
82
- gracefully.
83
- """
84
- provider = _choose_provider(args)
85
- if provider is None:
86
- return None, None, None
87
- from janito.provider_config import get_effective_model
88
-
89
- model = getattr(args, "model", None)
90
- if not model:
91
- model = get_effective_model(provider)
92
-
93
- # Auto-select coder model when --developer mode is used and no model is specified
94
- if not model and getattr(args, "developer", False):
95
- model = _select_coder_model_for_provider(provider)
96
- if model and getattr(args, "verbose", False):
97
- print_verbose_info(
98
- "Auto-selected coder model",
99
- f"{model} for provider {provider} (developer mode)",
100
- style="magenta",
101
- align_content=True,
102
- )
103
-
104
- # Validate that the chosen model is supported by the selected provider
105
- if model:
106
- from janito.provider_registry import ProviderRegistry
107
-
108
- provider_instance = None
109
- provider_instance = ProviderRegistry().get_instance(provider)
110
- if provider_instance is None:
111
- return provider, None, None
112
- try:
113
- if not provider_instance.is_model_available(model):
114
- print(
115
- f"Error: Model '{model}' is not available for provider '{provider}'."
116
- )
117
- # Optionally, print available models if possible
118
- if hasattr(provider_instance, "get_model_info"):
119
- available_models = [
120
- m["name"]
121
- for m in provider_instance.get_model_info().values()
122
- if isinstance(m, dict) and "name" in m
123
- ]
124
- print(f"Available models: {', '.join(available_models)}")
125
- return provider, None, None
126
- except Exception as e:
127
- print(f"Error validating model for provider '{provider}': {e}")
128
- return provider, None, None
129
- driver_config_data = _populate_driver_config_data(args, modifiers, provider, model)
130
- llm_driver_config = LLMDriverConfig(**driver_config_data)
131
- if getattr(llm_driver_config, "verbose_api", None):
132
- pass
133
-
134
- agent_role = modifiers.get("profile") or "developer"
135
- return provider, llm_driver_config, agent_role
136
-
137
-
138
- def handle_runner(
139
- args,
140
- provider,
141
- llm_driver_config,
142
- agent_role,
143
- verbose_tools=False,
144
- ):
145
- """
146
- Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
147
- """
148
- zero_mode = getattr(args, "zero", False)
149
- from janito.provider_registry import ProviderRegistry
150
-
151
- # Patch: disable execution/run tools if not enabled
152
- import janito.tools
153
- from janito.tools.tool_base import ToolPermissions
154
-
155
- read = getattr(args, "read", False)
156
- write = getattr(args, "write", False)
157
- execute = getattr(args, "exec", False)
158
- from janito.tools.permissions import set_global_allowed_permissions
159
- from janito.tools.tool_base import ToolPermissions
160
-
161
- allowed_permissions = ToolPermissions(read=read, write=write, execute=execute)
162
- set_global_allowed_permissions(allowed_permissions)
163
- # Store the default permissions for later restoration (e.g., on /restart)
164
- from janito.tools.permissions import set_default_allowed_permissions
165
-
166
- set_default_allowed_permissions(allowed_permissions)
167
-
168
- # Load disabled tools from config
169
- from janito.tools.disabled_tools import load_disabled_tools_from_config
170
-
171
- load_disabled_tools_from_config()
172
-
173
- # Disable bash tools when running in PowerShell
174
- from janito.platform_discovery import PlatformDiscovery
175
-
176
- pd = PlatformDiscovery()
177
- if pd.detect_shell().startswith("PowerShell"):
178
- from janito.tools.disabled_tools import DisabledToolsState
179
-
180
- DisabledToolsState.disable_tool("run_bash_command")
181
-
182
- unrestricted = getattr(args, "unrestricted", False)
183
- adapter = janito.tools.get_local_tools_adapter(
184
- workdir=getattr(args, "workdir", None)
185
- )
186
- if unrestricted:
187
- # Patch: disable path security enforcement for this adapter instance
188
- setattr(adapter, "unrestricted_paths", True)
189
-
190
- # Also disable URL whitelist restrictions in unrestricted mode
191
- from janito.tools.url_whitelist import get_url_whitelist_manager
192
-
193
- whitelist_manager = get_url_whitelist_manager()
194
- whitelist_manager.set_unrestricted_mode(True)
195
-
196
- # Print allowed permissions in verbose mode
197
- if getattr(args, "verbose", False):
198
- print_verbose_info(
199
- "Allowed Tool Permissions",
200
- f"read={read}, write={write}, execute={execute}",
201
- style="yellow",
202
- )
203
-
204
- provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
205
- if provider_instance is None:
206
- return
207
- mode = get_prompt_mode(args)
208
- if getattr(args, "verbose", False):
209
- print_verbose_info(
210
- "Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
211
- )
212
- print_verbose_info("Agent role", agent_role, style="green")
213
-
214
- # Skip chat mode for list commands - handle them directly
215
- from janito.cli.core.getters import GETTER_KEYS
216
-
217
- skip_chat_mode = False
218
- if args is not None:
219
- for key in GETTER_KEYS:
220
- if getattr(args, key, False):
221
- skip_chat_mode = True
222
- break
223
-
224
- if skip_chat_mode:
225
- # Handle list commands directly without prompt
226
- from janito.cli.core.getters import handle_getter
227
-
228
- handle_getter(args)
229
- elif mode == "single_shot":
230
- from janito.cli.single_shot_mode.handler import (
231
- PromptHandler as SingleShotPromptHandler,
232
- )
233
-
234
- # DEBUG: Print exec_enabled propagation at runner
235
-
236
- handler = SingleShotPromptHandler(
237
- args,
238
- provider_instance,
239
- llm_driver_config,
240
- role=agent_role,
241
- allowed_permissions=allowed_permissions,
242
- )
243
- handler.handle()
244
- else:
245
- from janito.cli.chat_mode.session import ChatSession
246
- from rich.console import Console
247
-
248
- console = Console()
249
- session = ChatSession(
250
- console,
251
- provider_instance,
252
- llm_driver_config,
253
- role=agent_role,
254
- args=args,
255
- verbose_tools=verbose_tools,
256
- verbose_agent=getattr(args, "verbose_agent", False),
257
- allowed_permissions=allowed_permissions,
258
- )
259
- session.run()
260
-
261
-
262
- def get_prompt_mode(args):
263
- # If interactive flag is set, force chat mode regardless of user_prompt
264
- if getattr(args, "interactive", False):
265
- return "chat_mode"
266
- return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
1
+ """Handles LLM driver config preparation and execution modes."""
2
+
3
+ from janito.llm.driver_config import LLMDriverConfig
4
+ from janito.provider_config import get_config_provider
5
+ from janito.cli.core.model_guesser import (
6
+ guess_provider_from_model as _guess_provider_from_model,
7
+ )
8
+ from janito.cli.verbose_output import print_verbose_info
9
+
10
+
11
+ def _choose_provider(args):
12
+ provider = getattr(args, "provider", None)
13
+ if provider is None:
14
+ provider = get_config_provider()
15
+ if provider and getattr(args, "verbose", False):
16
+ print_verbose_info(
17
+ "Default provider", provider, style="magenta", align_content=True
18
+ )
19
+ elif provider is None:
20
+ # Try to guess provider based on model name if -m is provided
21
+ model = getattr(args, "model", None)
22
+ if model:
23
+ guessed_provider = _guess_provider_from_model(model)
24
+ if guessed_provider:
25
+ if getattr(args, "verbose", False):
26
+ print_verbose_info(
27
+ "Guessed provider",
28
+ guessed_provider,
29
+ style="magenta",
30
+ align_content=True,
31
+ )
32
+ return guessed_provider
33
+
34
+ print(
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."
36
+ )
37
+ return None
38
+ return provider
39
+
40
+
41
+
42
+
43
+
44
+ def _populate_driver_config_data(args, modifiers, provider, model):
45
+ from janito.provider_config import get_effective_setting
46
+
47
+ CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
48
+ driver_config_data = {"model": model}
49
+ if getattr(args, "verbose_api", None) is not None:
50
+ driver_config_data["verbose_api"] = args.verbose_api
51
+
52
+ # Add reasoning_effort from --effort CLI argument
53
+ if getattr(args, "effort", None) is not None:
54
+ driver_config_data["reasoning_effort"] = args.effort
55
+ for field in LLMDriverConfig.__dataclass_fields__:
56
+ if field in CONFIG_LOOKUP_KEYS:
57
+ if field in modifiers and modifiers[field] is not None:
58
+ driver_config_data[field] = modifiers[field]
59
+ else:
60
+ value = get_effective_setting(provider, model, field)
61
+ if value is not None:
62
+ driver_config_data[field] = value
63
+ elif field in modifiers and field != "model":
64
+ driver_config_data[field] = modifiers[field]
65
+ return driver_config_data
66
+
67
+
68
+ def prepare_llm_driver_config(args, modifiers):
69
+ """Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
70
+
71
+ This helper additionally validates that the chosen ``--model`` (or the
72
+ resolved model coming from config precedence) is actually available for the
73
+ selected provider. If the combination is invalid an error is printed and
74
+ ``None`` is returned for the config so that the caller can abort execution
75
+ gracefully.
76
+ """
77
+ provider = _choose_provider(args)
78
+ if provider is None:
79
+ return None, None, None
80
+ from janito.provider_config import get_effective_model
81
+
82
+ model = getattr(args, "model", None)
83
+ if not model:
84
+ model = get_effective_model(provider)
85
+
86
+
87
+
88
+ # Validate that the chosen model is supported by the selected provider
89
+ if model:
90
+ from janito.provider_registry import ProviderRegistry
91
+
92
+ provider_instance = None
93
+ provider_instance = ProviderRegistry().get_instance(provider)
94
+ if provider_instance is None:
95
+ return provider, None, None
96
+ try:
97
+ if not provider_instance.is_model_available(model):
98
+ print(
99
+ f"Error: Model '{model}' is not available for provider '{provider}'."
100
+ )
101
+ # Optionally, print available models if possible
102
+ if hasattr(provider_instance, "get_model_info"):
103
+ available_models = [
104
+ m["name"]
105
+ for m in provider_instance.get_model_info().values()
106
+ if isinstance(m, dict) and "name" in m
107
+ ]
108
+ print(f"Available models: {', '.join(available_models)}")
109
+ return provider, None, None
110
+ except Exception as e:
111
+ print(f"Error validating model for provider '{provider}': {e}")
112
+ return provider, None, None
113
+ driver_config_data = _populate_driver_config_data(args, modifiers, provider, model)
114
+ llm_driver_config = LLMDriverConfig(**driver_config_data)
115
+ if getattr(llm_driver_config, "verbose_api", None):
116
+ pass
117
+
118
+ agent_role = modifiers.get("profile") or "developer"
119
+ return provider, llm_driver_config, agent_role
120
+
121
+
122
+ def handle_runner(
123
+ args,
124
+ provider,
125
+ llm_driver_config,
126
+ agent_role,
127
+ verbose_tools=False,
128
+ ):
129
+ """
130
+ Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
131
+ """
132
+ zero_mode = getattr(args, "zero", False)
133
+ from janito.provider_registry import ProviderRegistry
134
+
135
+ # Patch: disable execution/run tools if not enabled
136
+ import janito.tools
137
+ from janito.tools.tool_base import ToolPermissions
138
+
139
+ read = getattr(args, "read", False)
140
+ write = getattr(args, "write", False)
141
+ execute = getattr(args, "exec", False)
142
+ from janito.tools.permissions import set_global_allowed_permissions
143
+ from janito.tools.tool_base import ToolPermissions
144
+
145
+ allowed_permissions = ToolPermissions(read=read, write=write, execute=execute)
146
+ set_global_allowed_permissions(allowed_permissions)
147
+ # Store the default permissions for later restoration (e.g., on /restart)
148
+ from janito.tools.permissions import set_default_allowed_permissions
149
+
150
+ set_default_allowed_permissions(allowed_permissions)
151
+
152
+ # Load disabled tools from config
153
+ from janito.tools.disabled_tools import load_disabled_tools_from_config
154
+
155
+ load_disabled_tools_from_config()
156
+
157
+ # Disable bash tools when running in PowerShell
158
+ from janito.platform_discovery import PlatformDiscovery
159
+
160
+ pd = PlatformDiscovery()
161
+ if pd.detect_shell().startswith("PowerShell"):
162
+ from janito.tools.disabled_tools import DisabledToolsState
163
+
164
+ DisabledToolsState.disable_tool("run_bash_command")
165
+
166
+ unrestricted = getattr(args, "unrestricted", False)
167
+ adapter = janito.tools.get_local_tools_adapter(
168
+ workdir=getattr(args, "workdir", None)
169
+ )
170
+ if unrestricted:
171
+ # Patch: disable path security enforcement for this adapter instance
172
+ setattr(adapter, "unrestricted_paths", True)
173
+
174
+ # Also disable URL whitelist restrictions in unrestricted mode
175
+ from janito.tools.url_whitelist import get_url_whitelist_manager
176
+
177
+ whitelist_manager = get_url_whitelist_manager()
178
+ whitelist_manager.set_unrestricted_mode(True)
179
+
180
+ # Print allowed permissions in verbose mode
181
+ if getattr(args, "verbose", False):
182
+ print_verbose_info(
183
+ "Allowed Tool Permissions",
184
+ f"read={read}, write={write}, execute={execute}",
185
+ style="yellow",
186
+ )
187
+
188
+ provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
189
+ if provider_instance is None:
190
+ return
191
+ mode = get_prompt_mode(args)
192
+ if getattr(args, "verbose", False):
193
+ print_verbose_info(
194
+ "Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
195
+ )
196
+ print_verbose_info("Agent role", agent_role, style="green")
197
+
198
+ # Skip chat mode for list commands - handle them directly
199
+ from janito.cli.core.getters import GETTER_KEYS
200
+
201
+ skip_chat_mode = False
202
+ if args is not None:
203
+ for key in GETTER_KEYS:
204
+ if getattr(args, key, False):
205
+ skip_chat_mode = True
206
+ break
207
+
208
+ if skip_chat_mode:
209
+ # Handle list commands directly without prompt
210
+ from janito.cli.core.getters import handle_getter
211
+
212
+ handle_getter(args)
213
+ elif mode == "single_shot":
214
+ from janito.cli.single_shot_mode.handler import (
215
+ PromptHandler as SingleShotPromptHandler,
216
+ )
217
+
218
+ # DEBUG: Print exec_enabled propagation at runner
219
+
220
+ handler = SingleShotPromptHandler(
221
+ args,
222
+ provider_instance,
223
+ llm_driver_config,
224
+ role=agent_role,
225
+ allowed_permissions=allowed_permissions,
226
+ )
227
+ handler.handle()
228
+ else:
229
+ from janito.cli.chat_mode.session import ChatSession
230
+ from rich.console import Console
231
+
232
+ console = Console()
233
+ session = ChatSession(
234
+ console,
235
+ provider_instance,
236
+ llm_driver_config,
237
+ role=agent_role,
238
+ args=args,
239
+ verbose_tools=verbose_tools,
240
+ verbose_agent=getattr(args, "verbose_agent", False),
241
+ allowed_permissions=allowed_permissions,
242
+ )
243
+ session.run()
244
+
245
+
246
+ def get_prompt_mode(args):
247
+ # If interactive flag is set, force chat mode regardless of user_prompt
248
+ if getattr(args, "interactive", False):
249
+ return "chat_mode"
250
+ return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"