janito 3.16.3__py3-none-any.whl → 3.17.1__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,250 +1,247 @@
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"
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 _populate_driver_config_data(args, modifiers, provider, model):
42
+ from janito.provider_config import get_effective_setting
43
+
44
+ CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
45
+ driver_config_data = {"model": model}
46
+ if getattr(args, "verbose_api", None) is not None:
47
+ driver_config_data["verbose_api"] = args.verbose_api
48
+ if getattr(args, "verbose_http", None) is not None:
49
+ driver_config_data["verbose_http"] = args.verbose_http
50
+
51
+ # Add reasoning_effort from --effort CLI argument
52
+ if getattr(args, "effort", None) is not None:
53
+ driver_config_data["reasoning_effort"] = args.effort
54
+ for field in LLMDriverConfig.__dataclass_fields__:
55
+ if field in CONFIG_LOOKUP_KEYS:
56
+ if field in modifiers and modifiers[field] is not None:
57
+ driver_config_data[field] = modifiers[field]
58
+ else:
59
+ value = get_effective_setting(provider, model, field)
60
+ if value is not None:
61
+ driver_config_data[field] = value
62
+ elif field in modifiers and field != "model":
63
+ driver_config_data[field] = modifiers[field]
64
+ return driver_config_data
65
+
66
+
67
+ def prepare_llm_driver_config(args, modifiers):
68
+ """Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
69
+
70
+ This helper additionally validates that the chosen ``--model`` (or the
71
+ resolved model coming from config precedence) is actually available for the
72
+ selected provider. If the combination is invalid an error is printed and
73
+ ``None`` is returned for the config so that the caller can abort execution
74
+ gracefully.
75
+ """
76
+ provider = _choose_provider(args)
77
+ if provider is None:
78
+ return None, None, None
79
+ from janito.provider_config import get_effective_model
80
+
81
+ model = getattr(args, "model", None)
82
+ if not model:
83
+ model = get_effective_model(provider)
84
+
85
+ # Validate that the chosen model is supported by the selected provider
86
+ if model:
87
+ from janito.provider_registry import ProviderRegistry
88
+
89
+ provider_instance = None
90
+ provider_instance = ProviderRegistry().get_instance(provider)
91
+ if provider_instance is None:
92
+ return provider, None, None
93
+ try:
94
+ if not provider_instance.is_model_available(model):
95
+ print(
96
+ f"Error: Model '{model}' is not available for provider '{provider}'."
97
+ )
98
+ # Optionally, print available models if possible
99
+ if hasattr(provider_instance, "get_model_info"):
100
+ available_models = [
101
+ m["name"]
102
+ for m in provider_instance.get_model_info().values()
103
+ if isinstance(m, dict) and "name" in m
104
+ ]
105
+ print(f"Available models: {', '.join(available_models)}")
106
+ return provider, None, None
107
+ except Exception as e:
108
+ print(f"Error validating model for provider '{provider}': {e}")
109
+ return provider, None, None
110
+ driver_config_data = _populate_driver_config_data(args, modifiers, provider, model)
111
+ llm_driver_config = LLMDriverConfig(**driver_config_data)
112
+ if getattr(llm_driver_config, "verbose_api", None):
113
+ pass
114
+
115
+ agent_role = modifiers.get("profile") or "developer"
116
+ return provider, llm_driver_config, agent_role
117
+
118
+
119
+ def handle_runner(
120
+ args,
121
+ provider,
122
+ llm_driver_config,
123
+ agent_role,
124
+ verbose_tools=False,
125
+ ):
126
+ """
127
+ Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
128
+ """
129
+ zero_mode = getattr(args, "zero", False)
130
+ from janito.provider_registry import ProviderRegistry
131
+
132
+ # Patch: disable execution/run tools if not enabled
133
+ import janito.tools
134
+ from janito.tools.tool_base import ToolPermissions
135
+
136
+ read = getattr(args, "read", False)
137
+ write = getattr(args, "write", False)
138
+ execute = getattr(args, "exec", False)
139
+ from janito.tools.permissions import set_global_allowed_permissions
140
+ from janito.tools.tool_base import ToolPermissions
141
+
142
+ allowed_permissions = ToolPermissions(read=read, write=write, execute=execute)
143
+ set_global_allowed_permissions(allowed_permissions)
144
+ # Store the default permissions for later restoration (e.g., on /restart)
145
+ from janito.tools.permissions import set_default_allowed_permissions
146
+
147
+ set_default_allowed_permissions(allowed_permissions)
148
+
149
+ # Load disabled tools from config
150
+ from janito.tools.disabled_tools import load_disabled_tools_from_config
151
+
152
+ load_disabled_tools_from_config()
153
+
154
+ # Disable bash tools when running in PowerShell
155
+ from janito.platform_discovery import PlatformDiscovery
156
+
157
+ pd = PlatformDiscovery()
158
+ if pd.detect_shell().startswith("PowerShell"):
159
+ from janito.tools.disabled_tools import DisabledToolsState
160
+
161
+ DisabledToolsState.disable_tool("run_bash_command")
162
+
163
+ unrestricted = getattr(args, "unrestricted", False)
164
+ adapter = janito.tools.get_local_tools_adapter(
165
+ workdir=getattr(args, "workdir", None)
166
+ )
167
+ if unrestricted:
168
+ # Patch: disable path security enforcement for this adapter instance
169
+ setattr(adapter, "unrestricted_paths", True)
170
+
171
+ # Also disable URL whitelist restrictions in unrestricted mode
172
+ from janito.tools.url_whitelist import get_url_whitelist_manager
173
+
174
+ whitelist_manager = get_url_whitelist_manager()
175
+ whitelist_manager.set_unrestricted_mode(True)
176
+
177
+ # Print allowed permissions in verbose mode
178
+ if getattr(args, "verbose", False):
179
+ print_verbose_info(
180
+ "Allowed Tool Permissions",
181
+ f"read={read}, write={write}, execute={execute}",
182
+ style="yellow",
183
+ )
184
+
185
+ provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
186
+ if provider_instance is None:
187
+ return
188
+ mode = get_prompt_mode(args)
189
+ if getattr(args, "verbose", False):
190
+ print_verbose_info(
191
+ "Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
192
+ )
193
+ print_verbose_info("Agent role", agent_role, style="green")
194
+
195
+ # Skip chat mode for list commands - handle them directly
196
+ from janito.cli.core.getters import GETTER_KEYS
197
+
198
+ skip_chat_mode = False
199
+ if args is not None:
200
+ for key in GETTER_KEYS:
201
+ if getattr(args, key, False):
202
+ skip_chat_mode = True
203
+ break
204
+
205
+ if skip_chat_mode:
206
+ # Handle list commands directly without prompt
207
+ from janito.cli.core.getters import handle_getter
208
+
209
+ handle_getter(args)
210
+ elif mode == "single_shot":
211
+ from janito.cli.single_shot_mode.handler import (
212
+ PromptHandler as SingleShotPromptHandler,
213
+ )
214
+
215
+ # DEBUG: Print exec_enabled propagation at runner
216
+
217
+ handler = SingleShotPromptHandler(
218
+ args,
219
+ provider_instance,
220
+ llm_driver_config,
221
+ role=agent_role,
222
+ allowed_permissions=allowed_permissions,
223
+ )
224
+ handler.handle()
225
+ else:
226
+ from janito.cli.chat_mode.session import ChatSession
227
+ from rich.console import Console
228
+
229
+ console = Console()
230
+ session = ChatSession(
231
+ console,
232
+ provider_instance,
233
+ llm_driver_config,
234
+ role=agent_role,
235
+ args=args,
236
+ verbose_tools=verbose_tools,
237
+ verbose_agent=getattr(args, "verbose_agent", False),
238
+ allowed_permissions=allowed_permissions,
239
+ )
240
+ session.run()
241
+
242
+
243
+ def get_prompt_mode(args):
244
+ # If interactive flag is set, force chat mode regardless of user_prompt
245
+ if getattr(args, "interactive", False):
246
+ return "chat_mode"
247
+ return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
janito/cli/main_cli.py CHANGED
@@ -66,6 +66,13 @@ definition = [
66
66
  "help": "Print API calls and responses of LLM driver APIs for debugging/tracing.",
67
67
  },
68
68
  ),
69
+ (
70
+ ["--verbose-http"],
71
+ {
72
+ "action": "store_true",
73
+ "help": "Enable verbose HTTP logging for the OpenAI driver (equivalent to setting OPENAI_DEBUG_HTTP=1).",
74
+ },
75
+ ),
69
76
  (
70
77
  ["--verbose-tools"],
71
78
  {
@@ -173,7 +180,13 @@ definition = [
173
180
  },
174
181
  ),
175
182
  (["-p", "--provider"], {"metavar": "PROVIDER", "help": "Select the provider"}),
176
- (["-m", "--model"], {"metavar": "MODEL", "help": "Select the model (can use model@provider syntax)"}),
183
+ (
184
+ ["-m", "--model"],
185
+ {
186
+ "metavar": "MODEL",
187
+ "help": "Select the model (can use model@provider syntax)",
188
+ },
189
+ ),
177
190
  (
178
191
  ["-t", "--temperature"],
179
192
  {"type": float, "default": None, "help": "Set the temperature"},
@@ -197,7 +210,6 @@ definition = [
197
210
  "help": "Set the reasoning effort for models that support it (low, medium, high, none)",
198
211
  },
199
212
  ),
200
-
201
213
  (
202
214
  ["-i", "--interactive"],
203
215
  {
@@ -252,6 +264,7 @@ MODIFIER_KEYS = [
252
264
  "verbose",
253
265
  "raw",
254
266
  "verbose_api",
267
+ "verbose_http",
255
268
  "verbose_tools",
256
269
  "exec",
257
270
  "read",
janito/config_manager.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import os
2
3
  from pathlib import Path
3
4
  from threading import Lock
4
5
 
@@ -95,7 +96,14 @@ class ConfigManager:
95
96
  f.write("\n")
96
97
 
97
98
  def get(self, key, default=None):
98
- # Precedence: runtime_overrides > file_config > defaults
99
+ # Precedence: runtime_overrides > environment variables > file_config > defaults
100
+ # Special handling for base_url to check BASE_URL environment variable
101
+ if key == "base_url":
102
+ env_value = os.environ.get("BASE_URL")
103
+ if env_value is not None:
104
+ return env_value
105
+
106
+ # Standard precedence for other keys
99
107
  for layer in (self.runtime_overrides, self.file_config, self.defaults):
100
108
  if key in layer and layer[key] is not None:
101
109
  return layer[key]