janito 2.7.0__py3-none-any.whl → 2.9.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/__init__.py +0 -1
- janito/__main__.py +0 -1
- janito/_version.py +0 -3
- janito/agent/setup_agent.py +77 -10
- janito/agent/templates/profiles/{system_prompt_template_plain_software_developer.txt.j2 → system_prompt_template_Developer_with_Python_Tools.txt.j2} +5 -1
- janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +3 -12
- janito/cli/__init__.py +0 -1
- janito/cli/chat_mode/bindings.py +1 -1
- janito/cli/chat_mode/chat_entry.py +0 -2
- janito/cli/chat_mode/prompt_style.py +0 -3
- janito/cli/chat_mode/script_runner.py +9 -5
- janito/cli/chat_mode/session.py +100 -37
- janito/cli/chat_mode/session_profile_select.py +61 -52
- janito/cli/chat_mode/shell/commands/__init__.py +1 -5
- janito/cli/chat_mode/shell/commands/_priv_check.py +1 -0
- janito/cli/chat_mode/shell/commands/_priv_status.py +13 -0
- janito/cli/chat_mode/shell/commands/bang.py +10 -3
- janito/cli/chat_mode/shell/commands/conversation_restart.py +24 -7
- janito/cli/chat_mode/shell/commands/execute.py +22 -7
- janito/cli/chat_mode/shell/commands/help.py +4 -1
- janito/cli/chat_mode/shell/commands/model.py +13 -5
- janito/cli/chat_mode/shell/commands/privileges.py +21 -0
- janito/cli/chat_mode/shell/commands/prompt.py +0 -2
- janito/cli/chat_mode/shell/commands/read.py +22 -5
- janito/cli/chat_mode/shell/commands/tools.py +15 -4
- janito/cli/chat_mode/shell/commands/write.py +22 -5
- janito/cli/chat_mode/shell/input_history.py +3 -1
- janito/cli/chat_mode/shell/session/manager.py +0 -2
- janito/cli/chat_mode/toolbar.py +25 -19
- janito/cli/cli_commands/list_config.py +31 -0
- janito/cli/cli_commands/list_models.py +1 -1
- janito/cli/cli_commands/list_profiles.py +79 -0
- janito/cli/cli_commands/list_providers.py +1 -0
- janito/cli/cli_commands/list_tools.py +35 -7
- janito/cli/cli_commands/model_utils.py +5 -3
- janito/cli/cli_commands/show_config.py +16 -11
- janito/cli/cli_commands/show_system_prompt.py +23 -9
- janito/cli/config.py +0 -13
- janito/cli/core/getters.py +16 -1
- janito/cli/core/runner.py +25 -8
- janito/cli/core/setters.py +13 -76
- janito/cli/main_cli.py +60 -27
- janito/cli/prompt_core.py +19 -18
- janito/cli/prompt_setup.py +6 -3
- janito/cli/rich_terminal_reporter.py +19 -5
- janito/cli/single_shot_mode/handler.py +14 -5
- janito/cli/verbose_output.py +5 -1
- janito/config.py +1 -0
- janito/config_manager.py +15 -2
- janito/drivers/azure_openai/driver.py +27 -30
- janito/drivers/openai/driver.py +53 -36
- janito/formatting_token.py +12 -4
- janito/llm/agent.py +15 -6
- janito/llm/driver.py +1 -0
- janito/llm/provider.py +1 -1
- janito/provider_registry.py +31 -70
- janito/providers/__init__.py +1 -0
- janito/providers/anthropic/model_info.py +0 -1
- janito/providers/anthropic/provider.py +9 -14
- janito/providers/azure_openai/provider.py +10 -5
- janito/providers/deepseek/provider.py +5 -4
- janito/providers/google/model_info.py +4 -2
- janito/providers/google/provider.py +11 -5
- janito/providers/groq/__init__.py +1 -0
- janito/providers/groq/model_info.py +45 -0
- janito/providers/groq/provider.py +76 -0
- janito/providers/moonshotai/provider.py +11 -4
- janito/providers/openai/model_info.py +0 -1
- janito/providers/openai/provider.py +6 -7
- janito/tools/__init__.py +2 -0
- janito/tools/adapters/local/__init__.py +2 -1
- janito/tools/adapters/local/adapter.py +21 -4
- janito/tools/adapters/local/ask_user.py +1 -0
- janito/tools/adapters/local/copy_file.py +1 -0
- janito/tools/adapters/local/create_directory.py +1 -0
- janito/tools/adapters/local/create_file.py +1 -0
- janito/tools/adapters/local/delete_text_in_file.py +2 -1
- janito/tools/adapters/local/fetch_url.py +1 -0
- janito/tools/adapters/local/find_files.py +7 -6
- janito/tools/adapters/local/get_file_outline/core.py +1 -0
- janito/tools/adapters/local/get_file_outline/java_outline.py +22 -15
- janito/tools/adapters/local/get_file_outline/search_outline.py +1 -0
- janito/tools/adapters/local/move_file.py +1 -0
- janito/tools/adapters/local/open_html_in_browser.py +15 -5
- janito/tools/adapters/local/open_url.py +1 -0
- janito/tools/adapters/local/python_code_run.py +1 -0
- janito/tools/adapters/local/python_command_run.py +1 -0
- janito/tools/adapters/local/python_file_run.py +1 -0
- janito/tools/adapters/local/read_files.py +19 -4
- janito/tools/adapters/local/remove_directory.py +1 -0
- janito/tools/adapters/local/remove_file.py +1 -0
- janito/tools/adapters/local/replace_text_in_file.py +4 -3
- janito/tools/adapters/local/run_bash_command.py +1 -0
- janito/tools/adapters/local/run_powershell_command.py +1 -0
- janito/tools/adapters/local/search_text/core.py +18 -17
- janito/tools/adapters/local/search_text/match_lines.py +5 -5
- janito/tools/adapters/local/search_text/pattern_utils.py +1 -1
- janito/tools/adapters/local/search_text/traverse_directory.py +7 -7
- janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +8 -1
- janito/tools/disabled_tools.py +68 -0
- janito/tools/path_security.py +18 -11
- janito/tools/permissions.py +6 -0
- janito/tools/permissions_parse.py +4 -3
- janito/tools/tool_base.py +11 -5
- janito/tools/tool_use_tracker.py +1 -4
- janito/tools/tool_utils.py +1 -1
- janito/tools/tools_adapter.py +57 -25
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/METADATA +11 -19
- janito-2.9.0.dist-info/RECORD +205 -0
- janito/cli/chat_mode/shell/commands/livelogs.py +0 -49
- janito/drivers/mistralai/driver.py +0 -41
- janito/providers/mistralai/model_info.py +0 -37
- janito/providers/mistralai/provider.py +0 -72
- janito/providers/provider_static_info.py +0 -21
- janito-2.7.0.dist-info/RECORD +0 -202
- /janito/agent/templates/profiles/{system_prompt_template_assistant.txt.j2 → system_prompt_template_model_conversation_without_tools_or_context.txt.j2} +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/WHEEL +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/entry_points.txt +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/top_level.txt +0 -0
janito/cli/core/setters.py
CHANGED
@@ -27,25 +27,24 @@ def handle_set(args, config_mgr=None):
|
|
27
27
|
print(f"Error parsing --set value: {e}")
|
28
28
|
return True
|
29
29
|
|
30
|
+
|
30
31
|
def _validate_set_arg_format(set_arg):
|
31
32
|
if "=" not in set_arg:
|
32
|
-
print(
|
33
|
-
"Error: --set requires KEY=VALUE (e.g., --set provider=provider_name)."
|
34
|
-
)
|
33
|
+
print("Error: --set requires KEY=VALUE (e.g., --set provider=provider_name).")
|
35
34
|
return False
|
36
35
|
return True
|
37
36
|
|
37
|
+
|
38
38
|
def _parse_set_arg(set_arg):
|
39
39
|
key, value = set_arg.split("=", 1)
|
40
40
|
return key.strip(), value.strip()
|
41
41
|
|
42
|
+
|
42
43
|
def _dispatch_set_key(key, value):
|
43
44
|
if key == "provider":
|
44
45
|
return _handle_set_config_provider(value)
|
45
46
|
if key == "model":
|
46
47
|
return _handle_set_global_model(value)
|
47
|
-
if "." in key and key.endswith(".model"):
|
48
|
-
return _handle_set_provider_model(key, value)
|
49
48
|
if key == "max_tokens":
|
50
49
|
return _handle_set_max_tokens(value)
|
51
50
|
if key == "base_url":
|
@@ -54,18 +53,24 @@ def _dispatch_set_key(key, value):
|
|
54
53
|
global_config.file_set("azure_deployment_name", value)
|
55
54
|
print(f"Azure deployment name set to '{value}'.")
|
56
55
|
return True
|
57
|
-
if ".max_tokens" in key or ".base_url" in key:
|
58
|
-
return _handle_set_provider_level_setting(key, value)
|
59
56
|
if key == "tool_permissions":
|
60
57
|
from janito.tools.permissions_parse import parse_permissions_string
|
61
58
|
from janito.tools.permissions import set_global_allowed_permissions
|
59
|
+
|
62
60
|
perms = parse_permissions_string(value)
|
63
61
|
global_config.file_set("tool_permissions", value)
|
64
62
|
set_global_allowed_permissions(perms)
|
65
63
|
print(f"Tool permissions set to '{value}' (parsed: {perms})")
|
66
64
|
return True
|
65
|
+
if key == "disabled_tools":
|
66
|
+
from janito.tools.disabled_tools import set_disabled_tools
|
67
|
+
|
68
|
+
set_disabled_tools(value)
|
69
|
+
global_config.file_set("disabled_tools", value)
|
70
|
+
print(f"Disabled tools set to '{value}'")
|
71
|
+
return True
|
67
72
|
print(
|
68
|
-
f"Error: Unknown config key '{key}'. Supported: provider, model,
|
73
|
+
f"Error: Unknown config key '{key}'. Supported: provider, model, max_tokens, base_url, azure_deployment_name, tool_permissions, disabled_tools"
|
69
74
|
)
|
70
75
|
return True
|
71
76
|
|
@@ -87,48 +92,6 @@ def _handle_set_base_url(value):
|
|
87
92
|
return True
|
88
93
|
|
89
94
|
|
90
|
-
def _handle_set_provider_level_setting(key, value):
|
91
|
-
parts = key.split(".")
|
92
|
-
if len(parts) == 2:
|
93
|
-
provider, par_key = parts
|
94
|
-
if par_key == "max_tokens":
|
95
|
-
try:
|
96
|
-
ival = int(value)
|
97
|
-
except Exception:
|
98
|
-
print("Error: max_tokens must be set to an integer value.")
|
99
|
-
return True
|
100
|
-
global_config.set_provider_config(provider, "max_tokens", ival)
|
101
|
-
print(f"max_tokens for provider '{provider}' set to {ival}.")
|
102
|
-
return True
|
103
|
-
if par_key == "base_url":
|
104
|
-
global_config.set_provider_config(provider, "base_url", value)
|
105
|
-
print(f"base_url for provider '{provider}' set to {value}.")
|
106
|
-
return True
|
107
|
-
elif len(parts) == 3:
|
108
|
-
provider, model, mk = parts
|
109
|
-
if mk == "max_tokens":
|
110
|
-
try:
|
111
|
-
ival = int(value)
|
112
|
-
except Exception:
|
113
|
-
print("Error: max_tokens must be set to an integer value.")
|
114
|
-
return True
|
115
|
-
global_config.set_provider_model_config(provider, model, "max_tokens", ival)
|
116
|
-
print(
|
117
|
-
f"max_tokens for provider '{provider}', model '{model}' set to {ival}."
|
118
|
-
)
|
119
|
-
return True
|
120
|
-
if mk == "base_url":
|
121
|
-
global_config.set_provider_model_config(provider, model, "base_url", value)
|
122
|
-
print(
|
123
|
-
f"base_url for provider '{provider}', model '{model}' set to {value}."
|
124
|
-
)
|
125
|
-
return True
|
126
|
-
print(
|
127
|
-
f"Error: Unknown config key '{key}'. Supported: provider, model, <provider>.model, max_tokens, base_url, <provider>.max_tokens, <provider>.base_url, <provider>.<model>.max_tokens, <provider>.<model>.base_url"
|
128
|
-
)
|
129
|
-
return True
|
130
|
-
|
131
|
-
|
132
95
|
def _handle_set_config_provider(value):
|
133
96
|
try:
|
134
97
|
supported = ProviderRegistry().get_provider(value)
|
@@ -144,32 +107,6 @@ def _handle_set_config_provider(value):
|
|
144
107
|
return True
|
145
108
|
|
146
109
|
|
147
|
-
def _handle_set_provider_model(key, value):
|
148
|
-
provider_name, suffix = key.rsplit(".", 1)
|
149
|
-
if suffix != "model":
|
150
|
-
print(
|
151
|
-
f"Error: Only <provider>.model is supported for provider-specific model override. Not: '{key}'"
|
152
|
-
)
|
153
|
-
return True
|
154
|
-
try:
|
155
|
-
provider_cls = ProviderRegistry().get_provider(provider_name)
|
156
|
-
provider_instance = provider_cls()
|
157
|
-
except Exception:
|
158
|
-
print(
|
159
|
-
f"Error: Provider '{provider_name}' is not supported. Run '--list-providers' to see the supported list."
|
160
|
-
)
|
161
|
-
return True
|
162
|
-
model_info = provider_instance.get_model_info(value)
|
163
|
-
if not model_info:
|
164
|
-
print(
|
165
|
-
f"Error: Model '{value}' is not defined for provider '{provider_name}'. Run '-p {provider_name} -l' to see models."
|
166
|
-
)
|
167
|
-
return True
|
168
|
-
global_config.set_provider_config(provider_name, "model", value)
|
169
|
-
print(f"Default model for provider '{provider_name}' set to '{value}'.")
|
170
|
-
return True
|
171
|
-
|
172
|
-
|
173
110
|
def _handle_set_global_model(value):
|
174
111
|
# Try to validate model choice (against current provider if possible)
|
175
112
|
provider_name = global_config.get("provider")
|
janito/cli/main_cli.py
CHANGED
@@ -21,7 +21,6 @@ definition = [
|
|
21
21
|
"help": "Disable path security: allow tool arguments to use any file/directory path (DANGEROUS)",
|
22
22
|
},
|
23
23
|
),
|
24
|
-
|
25
24
|
(
|
26
25
|
["--profile"],
|
27
26
|
{
|
@@ -99,6 +98,14 @@ definition = [
|
|
99
98
|
(["--version"], {"action": "version", "version": None}),
|
100
99
|
(["--list-tools"], {"action": "store_true", "help": "List all registered tools"}),
|
101
100
|
(["--show-config"], {"action": "store_true", "help": "Show the current config"}),
|
101
|
+
(
|
102
|
+
["--list-config"],
|
103
|
+
{"action": "store_true", "help": "List all configuration files"},
|
104
|
+
),
|
105
|
+
(
|
106
|
+
["--list-profiles"],
|
107
|
+
{"action": "store_true", "help": "List available system prompt profiles"},
|
108
|
+
),
|
102
109
|
(
|
103
110
|
["--list-providers"],
|
104
111
|
{"action": "store_true", "help": "List supported LLM providers"},
|
@@ -114,7 +121,7 @@ definition = [
|
|
114
121
|
"help": "Set API key for the provider (requires -p PROVIDER)",
|
115
122
|
},
|
116
123
|
),
|
117
|
-
(["--set"], {"metavar": "
|
124
|
+
(["--set"], {"metavar": "KEY=VALUE", "help": "Set a config key"}),
|
118
125
|
(["-s", "--system"], {"metavar": "SYSTEM_PROMPT", "help": "Set a system prompt"}),
|
119
126
|
(
|
120
127
|
["-S", "--show-system"],
|
@@ -141,22 +148,7 @@ definition = [
|
|
141
148
|
},
|
142
149
|
),
|
143
150
|
(
|
144
|
-
["--
|
145
|
-
{
|
146
|
-
"action": "store_true",
|
147
|
-
"default": False,
|
148
|
-
"help": "Enable the builtin lightweight web file viewer for terminal links (disabled by default)",
|
149
|
-
},
|
150
|
-
),
|
151
|
-
(
|
152
|
-
["---port"],
|
153
|
-
{
|
154
|
-
"type": int,
|
155
|
-
"default": 8088,
|
156
|
-
"help": "Port for the server (default: 8088)",
|
157
|
-
},
|
158
|
-
),
|
159
|
-
(["--effort"],
|
151
|
+
["--effort"],
|
160
152
|
{
|
161
153
|
"choices": ["low", "medium", "high", "none"],
|
162
154
|
"default": None,
|
@@ -175,6 +167,13 @@ definition = [
|
|
175
167
|
"help": "Print debug info on event subscribe/submit methods",
|
176
168
|
},
|
177
169
|
),
|
170
|
+
(
|
171
|
+
["-c", "--config"],
|
172
|
+
{
|
173
|
+
"metavar": "NAME",
|
174
|
+
"help": "Use custom configuration file ~/.janito/configs/NAME.json instead of default config.json",
|
175
|
+
},
|
176
|
+
),
|
178
177
|
]
|
179
178
|
|
180
179
|
MODIFIER_KEYS = [
|
@@ -184,11 +183,8 @@ MODIFIER_KEYS = [
|
|
184
183
|
"profile",
|
185
184
|
"system",
|
186
185
|
"temperature",
|
187
|
-
|
188
186
|
"verbose",
|
189
187
|
"raw",
|
190
|
-
"web",
|
191
|
-
"_port",
|
192
188
|
"verbose_api",
|
193
189
|
"verbose_tools",
|
194
190
|
"exec",
|
@@ -196,7 +192,14 @@ MODIFIER_KEYS = [
|
|
196
192
|
"write",
|
197
193
|
]
|
198
194
|
SETTER_KEYS = ["set", "set_provider", "set_api_key", "unset"]
|
199
|
-
GETTER_KEYS = [
|
195
|
+
GETTER_KEYS = [
|
196
|
+
"show_config",
|
197
|
+
"list_providers",
|
198
|
+
"list_profiles",
|
199
|
+
"list_models",
|
200
|
+
"list_tools",
|
201
|
+
"list_config",
|
202
|
+
]
|
200
203
|
|
201
204
|
|
202
205
|
class RunMode(enum.Enum):
|
@@ -217,14 +220,38 @@ class JanitoCLI:
|
|
217
220
|
self._define_args()
|
218
221
|
self.args = self.parser.parse_args()
|
219
222
|
self._set_all_arg_defaults()
|
223
|
+
# Support custom config file via -c/--config
|
224
|
+
if getattr(self.args, "config", None):
|
225
|
+
from janito import config as global_config
|
226
|
+
from janito.config_manager import ConfigManager
|
227
|
+
import sys
|
228
|
+
import importlib
|
229
|
+
|
230
|
+
config_name = self.args.config
|
231
|
+
# Re-initialize the global config singleton
|
232
|
+
new_config = ConfigManager(config_name=config_name)
|
233
|
+
# Ensure the config path is updated when the singleton already existed
|
234
|
+
from pathlib import Path
|
235
|
+
|
236
|
+
new_config.config_path = (
|
237
|
+
Path.home() / ".janito" / "configs" / f"{config_name}.json"
|
238
|
+
)
|
239
|
+
# Reload config from the selected file
|
240
|
+
new_config._load_file_config()
|
241
|
+
# Patch the global singleton reference
|
242
|
+
import janito.config as config_module
|
243
|
+
|
244
|
+
config_module.config = new_config
|
245
|
+
sys.modules["janito.config"].config = new_config
|
220
246
|
# Support reading prompt from stdin if no user_prompt is given
|
221
247
|
import sys
|
248
|
+
|
222
249
|
if not sys.stdin.isatty():
|
223
250
|
stdin_input = sys.stdin.read().strip()
|
224
251
|
if stdin_input:
|
225
252
|
if self.args.user_prompt and len(self.args.user_prompt) > 0:
|
226
253
|
# Prefix the prompt argument to the stdin input
|
227
|
-
combined =
|
254
|
+
combined = " ".join(self.args.user_prompt) + " " + stdin_input
|
228
255
|
self.args.user_prompt = [combined]
|
229
256
|
else:
|
230
257
|
self.args.user_prompt = [stdin_input]
|
@@ -289,13 +316,19 @@ class JanitoCLI:
|
|
289
316
|
return
|
290
317
|
# Special handling: provider is not required for list_providers, list_tools, show_config
|
291
318
|
if run_mode == RunMode.GET and (
|
292
|
-
self.args.list_providers
|
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
|
293
324
|
):
|
294
325
|
self._maybe_print_verbose_provider_model()
|
295
326
|
handle_getter(self.args)
|
296
327
|
return
|
297
328
|
# If running in single shot mode and --profile is not provided, default to 'developer' profile
|
298
|
-
if get_prompt_mode(self.args) == "single_shot" and not getattr(
|
329
|
+
if get_prompt_mode(self.args) == "single_shot" and not getattr(
|
330
|
+
self.args, "profile", None
|
331
|
+
):
|
299
332
|
self.args.profile = "developer"
|
300
333
|
provider = self._get_provider_or_default()
|
301
334
|
if provider is None:
|
@@ -316,14 +349,14 @@ class JanitoCLI:
|
|
316
349
|
if run_mode == RunMode.RUN:
|
317
350
|
self._maybe_print_verbose_run_mode()
|
318
351
|
# DEBUG: Print exec_enabled propagation at main_cli
|
319
|
-
|
352
|
+
|
320
353
|
handle_runner(
|
321
354
|
self.args,
|
322
355
|
provider,
|
323
356
|
llm_driver_config,
|
324
357
|
agent_role,
|
325
358
|
verbose_tools=self.args.verbose_tools,
|
326
|
-
|
359
|
+
)
|
327
360
|
elif run_mode == RunMode.GET:
|
328
361
|
handle_getter(self.args)
|
329
362
|
|
janito/cli/prompt_core.py
CHANGED
@@ -8,7 +8,12 @@ from janito.performance_collector import PerformanceCollector
|
|
8
8
|
from rich.status import Status
|
9
9
|
from rich.console import Console
|
10
10
|
from typing import Any, Optional, Callable
|
11
|
-
from janito.driver_events import
|
11
|
+
from janito.driver_events import (
|
12
|
+
RequestStarted,
|
13
|
+
RequestFinished,
|
14
|
+
RequestStatus,
|
15
|
+
RateLimitRetry,
|
16
|
+
)
|
12
17
|
from janito.tools.tool_events import ToolCallError
|
13
18
|
import threading
|
14
19
|
from janito.cli.verbose_output import print_verbose_header
|
@@ -56,7 +61,10 @@ class PromptHandler:
|
|
56
61
|
if isinstance(inner_event, RequestFinished):
|
57
62
|
if getattr(inner_event, "status", None) == "error":
|
58
63
|
return self._handle_request_finished_error(inner_event, status)
|
59
|
-
if getattr(inner_event, "status", None) in (
|
64
|
+
if getattr(inner_event, "status", None) in (
|
65
|
+
RequestStatus.EMPTY_RESPONSE,
|
66
|
+
RequestStatus.TIMEOUT,
|
67
|
+
):
|
60
68
|
return self._handle_empty_or_timeout(inner_event, status)
|
61
69
|
status.update("[bold green]Received response![bold green]")
|
62
70
|
return "break"
|
@@ -78,7 +86,9 @@ class PromptHandler:
|
|
78
86
|
return None
|
79
87
|
|
80
88
|
def _handle_rate_limit_retry(self, inner_event, status):
|
81
|
-
status.update(
|
89
|
+
status.update(
|
90
|
+
f"[yellow]Rate limited. Waiting {inner_event.retry_delay:.0f}s before retry (attempt {inner_event.attempt}).[yellow]"
|
91
|
+
)
|
82
92
|
return None
|
83
93
|
|
84
94
|
def _handle_request_finished_error(self, inner_event, status):
|
@@ -89,9 +99,7 @@ class PromptHandler:
|
|
89
99
|
"Status 429" in error_msg
|
90
100
|
and "Service tier capacity exceeded for this model" in error_msg
|
91
101
|
):
|
92
|
-
status.update(
|
93
|
-
"[yellow]Service tier capacity exceeded, retrying...[yellow]"
|
94
|
-
)
|
102
|
+
status.update("[yellow]Service tier capacity exceeded, retrying...[yellow]")
|
95
103
|
return "break"
|
96
104
|
status.update(f"[bold red]Error: {error_msg}[bold red]")
|
97
105
|
self.console.print(f"[red]Error: {error_msg}[red]")
|
@@ -99,18 +107,12 @@ class PromptHandler:
|
|
99
107
|
|
100
108
|
def _handle_tool_call_error(self, inner_event, status):
|
101
109
|
error_msg = (
|
102
|
-
inner_event.error
|
103
|
-
if hasattr(inner_event, "error")
|
104
|
-
else "Unknown tool error"
|
110
|
+
inner_event.error if hasattr(inner_event, "error") else "Unknown tool error"
|
105
111
|
)
|
106
112
|
tool_name = (
|
107
|
-
inner_event.tool_name
|
108
|
-
if hasattr(inner_event, "tool_name")
|
109
|
-
else "unknown"
|
110
|
-
)
|
111
|
-
status.update(
|
112
|
-
f"[bold red]Tool Error in '{tool_name}': {error_msg}[bold red]"
|
113
|
+
inner_event.tool_name if hasattr(inner_event, "tool_name") else "unknown"
|
113
114
|
)
|
115
|
+
status.update(f"[bold red]Tool Error in '{tool_name}': {error_msg}[bold red]")
|
114
116
|
self.console.print(f"[red]Tool Error in '{tool_name}': {error_msg}[red]")
|
115
117
|
return "break"
|
116
118
|
|
@@ -118,9 +120,7 @@ class PromptHandler:
|
|
118
120
|
details = getattr(inner_event, "details", None) or {}
|
119
121
|
block_reason = details.get("block_reason")
|
120
122
|
block_msg = details.get("block_reason_message")
|
121
|
-
msg = details.get(
|
122
|
-
"message", "LLM returned an empty or incomplete response."
|
123
|
-
)
|
123
|
+
msg = details.get("message", "LLM returned an empty or incomplete response.")
|
124
124
|
driver_name = getattr(inner_event, "driver_name", "unknown driver")
|
125
125
|
if block_reason or block_msg:
|
126
126
|
status.update(
|
@@ -221,6 +221,7 @@ class PromptHandler:
|
|
221
221
|
self.console.print("[red]Interrupted by the user.[/red]")
|
222
222
|
try:
|
223
223
|
from janito.driver_events import RequestFinished, RequestStatus
|
224
|
+
|
224
225
|
# Record a synthetic "cancelled" final event so that downstream
|
225
226
|
# handlers (e.g. single_shot_mode.handler._post_prompt_actions)
|
226
227
|
# can reliably detect that the prompt was interrupted by the
|
janito/cli/prompt_setup.py
CHANGED
@@ -4,6 +4,7 @@ both single–shot and chat modes can reuse. Having one central place avoids th
|
|
4
4
|
code duplication that previously existed in `chat_mode.session.ChatSession` and
|
5
5
|
`single_shot_mode.handler.PromptHandler`.
|
6
6
|
"""
|
7
|
+
|
7
8
|
from __future__ import annotations
|
8
9
|
|
9
10
|
from janito.agent.setup_agent import create_configured_agent
|
@@ -21,7 +22,6 @@ def setup_agent_and_prompt_handler(
|
|
21
22
|
role: Optional[str] = None,
|
22
23
|
verbose_tools: bool = False,
|
23
24
|
verbose_agent: bool = False,
|
24
|
-
|
25
25
|
allowed_permissions: Optional[list[str]] = None,
|
26
26
|
profile: Optional[str] = None,
|
27
27
|
profile_system_prompt: Optional[str] = None,
|
@@ -34,16 +34,19 @@ def setup_agent_and_prompt_handler(
|
|
34
34
|
across *single-shot* and *chat* modes – both of which need an agent plus a
|
35
35
|
prompt handler that points to that agent.
|
36
36
|
"""
|
37
|
+
no_tools_mode = False
|
38
|
+
if hasattr(args, 'no_tools_mode'):
|
39
|
+
no_tools_mode = getattr(args, 'no_tools_mode', False)
|
37
40
|
agent = create_configured_agent(
|
38
41
|
provider_instance=provider_instance,
|
39
42
|
llm_driver_config=llm_driver_config,
|
40
43
|
role=role,
|
41
44
|
verbose_tools=verbose_tools,
|
42
45
|
verbose_agent=verbose_agent,
|
43
|
-
|
44
46
|
allowed_permissions=allowed_permissions,
|
45
47
|
profile=profile,
|
46
48
|
profile_system_prompt=profile_system_prompt,
|
49
|
+
no_tools_mode=no_tools_mode,
|
47
50
|
)
|
48
51
|
|
49
52
|
prompt_handler = GenericPromptHandler(
|
@@ -53,4 +56,4 @@ def setup_agent_and_prompt_handler(
|
|
53
56
|
)
|
54
57
|
prompt_handler.agent = agent
|
55
58
|
|
56
|
-
return agent, prompt_handler
|
59
|
+
return agent, prompt_handler
|
@@ -12,6 +12,7 @@ from janito.llm import message_parts
|
|
12
12
|
|
13
13
|
import sys
|
14
14
|
|
15
|
+
|
15
16
|
class RichTerminalReporter(EventHandlerBase):
|
16
17
|
"""
|
17
18
|
Handles UI rendering for janito events using Rich.
|
@@ -31,6 +32,7 @@ class RichTerminalReporter(EventHandlerBase):
|
|
31
32
|
import janito.report_events as report_events
|
32
33
|
|
33
34
|
import janito.tools.tool_events as tool_events
|
35
|
+
|
34
36
|
super().__init__(driver_events, report_events, tool_events)
|
35
37
|
self._waiting_printed = False
|
36
38
|
|
@@ -53,7 +55,9 @@ class RichTerminalReporter(EventHandlerBase):
|
|
53
55
|
model = getattr(event, "model_name", None)
|
54
56
|
if not model:
|
55
57
|
model = "?"
|
56
|
-
self.console.print(
|
58
|
+
self.console.print(
|
59
|
+
f"[bold cyan]Waiting for {provider} (model: {model})...[/bold cyan]", end=""
|
60
|
+
)
|
57
61
|
|
58
62
|
def on_ResponseReceived(self, event):
|
59
63
|
parts = event.parts if hasattr(event, "parts") else None
|
@@ -70,7 +74,7 @@ class RichTerminalReporter(EventHandlerBase):
|
|
70
74
|
"""
|
71
75
|
Clears the entire current line in the terminal and returns the cursor to column 1.
|
72
76
|
"""
|
73
|
-
sys.stdout.write(
|
77
|
+
sys.stdout.write("\033[2K\r")
|
74
78
|
sys.stdout.flush()
|
75
79
|
|
76
80
|
def on_RequestFinished(self, event):
|
@@ -118,9 +122,15 @@ class RichTerminalReporter(EventHandlerBase):
|
|
118
122
|
action = getattr(event, "action", None)
|
119
123
|
tool = getattr(event, "tool", None)
|
120
124
|
context = getattr(event, "context", None)
|
121
|
-
if
|
125
|
+
if (
|
126
|
+
subtype == ReportSubtype.ERROR
|
127
|
+
and msg
|
128
|
+
and "[SECURITY] Path access denied" in msg
|
129
|
+
):
|
122
130
|
# Highlight security errors with a distinct style
|
123
|
-
self.console.print(
|
131
|
+
self.console.print(
|
132
|
+
Panel(f"{msg}", title="[red]SECURITY VIOLATION[/red]", style="bold red")
|
133
|
+
)
|
124
134
|
self.console.file.flush()
|
125
135
|
return
|
126
136
|
|
@@ -135,7 +145,11 @@ class RichTerminalReporter(EventHandlerBase):
|
|
135
145
|
getattr(ReportAction, "WRITE", None),
|
136
146
|
getattr(ReportAction, "DELETE", None),
|
137
147
|
)
|
138
|
-
style =
|
148
|
+
style = (
|
149
|
+
"orange1"
|
150
|
+
if getattr(event, "action", None) in modification_actions
|
151
|
+
else "cyan"
|
152
|
+
)
|
139
153
|
self.console.print(Text(msg, style=style), end="")
|
140
154
|
self.console.file.flush()
|
141
155
|
elif subtype in (
|
@@ -11,12 +11,19 @@ import time
|
|
11
11
|
|
12
12
|
|
13
13
|
class PromptHandler:
|
14
|
-
def __init__(
|
14
|
+
def __init__(
|
15
|
+
self,
|
16
|
+
args,
|
17
|
+
provider_instance,
|
18
|
+
llm_driver_config,
|
19
|
+
role=None,
|
20
|
+
allowed_permissions=None,
|
21
|
+
):
|
15
22
|
self.args = args
|
16
23
|
self.provider_instance = provider_instance
|
17
24
|
self.llm_driver_config = llm_driver_config
|
18
25
|
self.role = role
|
19
|
-
|
26
|
+
# Instantiate agent together with prompt handler using the shared helper
|
20
27
|
self.agent, self.generic_handler = setup_agent_and_prompt_handler(
|
21
28
|
args=args,
|
22
29
|
provider_instance=provider_instance,
|
@@ -24,7 +31,6 @@ class PromptHandler:
|
|
24
31
|
role=role,
|
25
32
|
verbose_tools=getattr(args, "verbose_tools", False),
|
26
33
|
verbose_agent=getattr(args, "verbose_agent", False),
|
27
|
-
|
28
34
|
allowed_permissions=allowed_permissions,
|
29
35
|
profile=getattr(args, "profile", None),
|
30
36
|
)
|
@@ -43,6 +49,7 @@ class PromptHandler:
|
|
43
49
|
"[yellow]Warning: Some characters in your input were not valid UTF-8 and have been replaced.[/yellow]"
|
44
50
|
)
|
45
51
|
import time
|
52
|
+
|
46
53
|
try:
|
47
54
|
start_time = time.time()
|
48
55
|
self.generic_handler.handle_prompt(
|
@@ -67,13 +74,15 @@ class PromptHandler:
|
|
67
74
|
import sys
|
68
75
|
from janito.formatting_token import print_token_message_summary
|
69
76
|
from janito.perf_singleton import performance_collector
|
77
|
+
|
70
78
|
usage = performance_collector.get_last_request_usage()
|
71
79
|
# If running in stdin mode, do not print token usage
|
72
80
|
if sys.stdin.isatty():
|
73
|
-
print_token_message_summary(
|
81
|
+
print_token_message_summary(
|
82
|
+
shared_console, msg_count=1, usage=usage, elapsed=elapsed
|
83
|
+
)
|
74
84
|
self._cleanup_driver_and_console()
|
75
85
|
|
76
|
-
|
77
86
|
def _cleanup_driver_and_console(self):
|
78
87
|
if hasattr(self.agent, "join_driver"):
|
79
88
|
if (
|
janito/cli/verbose_output.py
CHANGED
@@ -19,7 +19,11 @@ def print_verbose_header(agent, args):
|
|
19
19
|
parts = [
|
20
20
|
f"Janito {VERSION}",
|
21
21
|
f"Provider: {agent.llm_provider.__class__.__name__}",
|
22
|
-
(
|
22
|
+
(
|
23
|
+
f"Model: {agent.llm_provider.driver_config.extra.get('azure_deployment_name', agent.llm_provider.driver_config.model)}{role_part}"
|
24
|
+
if agent.llm_provider.__class__.__name__ == "AzureOpenAIProvider"
|
25
|
+
else f"Model: {getattr(agent.llm_provider.driver_config, 'model', '-')}{role_part}"
|
26
|
+
),
|
23
27
|
f"Driver: {agent.llm_provider.__class__.__module__.split('.')[-2] if len(agent.llm_provider.__class__.__module__.split('.')) > 1 else agent.llm_provider.__class__.__name__}",
|
24
28
|
]
|
25
29
|
if hasattr(args, "think") and args.think:
|
janito/config.py
CHANGED
@@ -2,4 +2,5 @@
|
|
2
2
|
from janito.config_manager import ConfigManager
|
3
3
|
|
4
4
|
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
+
# If you want to use a custom config, re-initialize this singleton with config_name or config_path before use.
|
5
6
|
config = ConfigManager(config_path=None)
|
janito/config_manager.py
CHANGED
@@ -20,13 +20,22 @@ class ConfigManager:
|
|
20
20
|
cls._instance = super(ConfigManager, cls).__new__(cls)
|
21
21
|
return cls._instance
|
22
22
|
|
23
|
-
def __init__(
|
23
|
+
def __init__(
|
24
|
+
self, config_path=None, defaults=None, runtime_overrides=None, config_name=None
|
25
|
+
):
|
24
26
|
# Lazy single-init
|
25
27
|
if hasattr(self, "_initialized") and self._initialized:
|
26
28
|
return
|
27
29
|
self._initialized = True
|
28
30
|
|
29
|
-
|
31
|
+
if config_name:
|
32
|
+
self.config_path = (
|
33
|
+
Path.home() / ".janito" / "configs" / f"{config_name}.json"
|
34
|
+
)
|
35
|
+
else:
|
36
|
+
self.config_path = Path(
|
37
|
+
config_path or Path.home() / ".janito" / "config.json"
|
38
|
+
)
|
30
39
|
self.defaults = dict(defaults) if defaults else {}
|
31
40
|
self.file_config = {}
|
32
41
|
self.runtime_overrides = dict(runtime_overrides) if runtime_overrides else {}
|
@@ -40,11 +49,15 @@ class ConfigManager:
|
|
40
49
|
try:
|
41
50
|
from janito.tools.permissions_parse import parse_permissions_string
|
42
51
|
from janito.tools.permissions import set_global_allowed_permissions
|
52
|
+
|
43
53
|
perms = parse_permissions_string(perm_str)
|
44
54
|
set_global_allowed_permissions(perms)
|
45
55
|
except Exception as e:
|
46
56
|
print(f"Warning: Failed to apply tool_permissions from config: {e}")
|
47
57
|
|
58
|
+
# Load disabled tools from config - skip during startup to avoid circular imports
|
59
|
+
# This will be handled by the CLI when needed
|
60
|
+
|
48
61
|
def _load_file_config(self):
|
49
62
|
if self.config_path.exists():
|
50
63
|
with open(self.config_path, "r", encoding="utf-8") as f:
|