janito 2.1.1__py3-none-any.whl → 2.3.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 +6 -6
- janito/agent/setup_agent.py +14 -5
- janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +3 -1
- janito/cli/chat_mode/bindings.py +6 -0
- janito/cli/chat_mode/session.py +16 -0
- janito/cli/chat_mode/shell/autocomplete.py +21 -21
- janito/cli/chat_mode/shell/commands/__init__.py +3 -2
- janito/cli/chat_mode/shell/commands/clear.py +12 -12
- janito/cli/chat_mode/shell/commands/exec.py +27 -0
- janito/cli/chat_mode/shell/commands/multi.py +51 -51
- janito/cli/chat_mode/shell/commands/tools.py +17 -6
- janito/cli/chat_mode/shell/input_history.py +62 -62
- janito/cli/chat_mode/shell/session/manager.py +1 -0
- janito/cli/chat_mode/toolbar.py +3 -1
- janito/cli/cli_commands/list_models.py +35 -35
- janito/cli/cli_commands/list_providers.py +9 -9
- janito/cli/cli_commands/list_tools.py +53 -53
- janito/cli/cli_commands/model_selection.py +50 -50
- janito/cli/cli_commands/model_utils.py +13 -2
- janito/cli/cli_commands/set_api_key.py +19 -19
- janito/cli/cli_commands/show_config.py +51 -51
- janito/cli/cli_commands/show_system_prompt.py +62 -62
- janito/cli/config.py +2 -1
- janito/cli/core/__init__.py +4 -4
- janito/cli/core/event_logger.py +59 -59
- janito/cli/core/getters.py +3 -1
- janito/cli/core/runner.py +27 -6
- janito/cli/core/setters.py +5 -1
- janito/cli/core/unsetters.py +54 -54
- janito/cli/main_cli.py +12 -1
- janito/cli/prompt_core.py +5 -2
- janito/cli/rich_terminal_reporter.py +22 -3
- janito/cli/single_shot_mode/__init__.py +6 -6
- janito/cli/single_shot_mode/handler.py +11 -1
- janito/cli/verbose_output.py +1 -1
- janito/config.py +5 -5
- janito/config_manager.py +2 -0
- janito/driver_events.py +14 -0
- janito/drivers/anthropic/driver.py +113 -113
- janito/drivers/azure_openai/driver.py +38 -3
- janito/drivers/driver_registry.py +0 -2
- janito/drivers/openai/driver.py +196 -36
- janito/formatting_token.py +54 -54
- janito/i18n/__init__.py +35 -35
- janito/i18n/messages.py +23 -23
- janito/i18n/pt.py +47 -47
- janito/llm/__init__.py +5 -5
- janito/llm/agent.py +443 -443
- janito/llm/auth.py +1 -0
- janito/llm/driver.py +7 -1
- janito/llm/driver_config.py +1 -0
- janito/llm/driver_config_builder.py +34 -34
- janito/llm/driver_input.py +12 -12
- janito/llm/message_parts.py +60 -60
- janito/llm/model.py +38 -38
- janito/llm/provider.py +196 -196
- janito/provider_config.py +7 -3
- janito/provider_registry.py +29 -5
- janito/providers/__init__.py +1 -0
- janito/providers/anthropic/model_info.py +22 -22
- janito/providers/anthropic/provider.py +2 -2
- janito/providers/azure_openai/model_info.py +7 -6
- janito/providers/azure_openai/provider.py +44 -2
- janito/providers/deepseek/__init__.py +1 -1
- janito/providers/deepseek/model_info.py +16 -16
- janito/providers/deepseek/provider.py +91 -91
- janito/providers/google/model_info.py +21 -29
- janito/providers/google/provider.py +49 -38
- janito/providers/mistralai/provider.py +2 -2
- janito/providers/openai/model_info.py +0 -11
- janito/providers/openai/provider.py +1 -1
- janito/providers/provider_static_info.py +2 -3
- janito/providers/registry.py +26 -26
- janito/tools/adapters/__init__.py +1 -1
- janito/tools/adapters/local/__init__.py +62 -62
- janito/tools/adapters/local/adapter.py +33 -11
- janito/tools/adapters/local/ask_user.py +102 -102
- janito/tools/adapters/local/copy_file.py +84 -84
- janito/tools/adapters/local/create_directory.py +69 -69
- janito/tools/adapters/local/create_file.py +82 -82
- janito/tools/adapters/local/delete_text_in_file.py +4 -7
- janito/tools/adapters/local/fetch_url.py +97 -97
- janito/tools/adapters/local/find_files.py +138 -140
- janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
- janito/tools/adapters/local/get_file_outline/core.py +117 -151
- janito/tools/adapters/local/get_file_outline/java_outline.py +40 -0
- janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
- janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
- janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
- janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
- janito/tools/adapters/local/move_file.py +3 -13
- janito/tools/adapters/local/open_html_in_browser.py +24 -29
- janito/tools/adapters/local/open_url.py +3 -2
- janito/tools/adapters/local/python_code_run.py +166 -166
- janito/tools/adapters/local/python_command_run.py +164 -164
- janito/tools/adapters/local/python_file_run.py +163 -163
- janito/tools/adapters/local/remove_directory.py +6 -17
- janito/tools/adapters/local/remove_file.py +9 -15
- janito/tools/adapters/local/replace_text_in_file.py +6 -9
- janito/tools/adapters/local/run_bash_command.py +176 -176
- janito/tools/adapters/local/run_powershell_command.py +219 -219
- janito/tools/adapters/local/search_text/__init__.py +1 -1
- janito/tools/adapters/local/search_text/core.py +201 -201
- janito/tools/adapters/local/search_text/match_lines.py +1 -1
- janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
- janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
- janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
- janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
- janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
- janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
- janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
- janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
- janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
- janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
- janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
- janito/tools/adapters/local/view_file.py +167 -167
- janito/tools/inspect_registry.py +17 -17
- janito/tools/tool_base.py +105 -105
- janito/tools/tool_events.py +58 -58
- janito/tools/tool_run_exception.py +12 -12
- janito/tools/tool_use_tracker.py +81 -81
- janito/tools/tool_utils.py +45 -45
- janito/tools/tools_adapter.py +78 -6
- janito/tools/tools_schema.py +104 -104
- janito/version.py +4 -4
- {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/METADATA +388 -232
- janito-2.3.0.dist-info/RECORD +181 -0
- janito-2.3.0.dist-info/licenses/LICENSE +21 -0
- janito/cli/chat_mode/shell/commands/last.py +0 -137
- janito/drivers/google_genai/driver.py +0 -54
- janito/drivers/google_genai/schema_generator.py +0 -67
- janito-2.1.1.dist-info/RECORD +0 -181
- {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/WHEEL +0 -0
- {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/entry_points.txt +0 -0
- {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/top_level.txt +0 -0
janito/cli/core/getters.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Handlers for get-type CLI commands (show_config, list_providers, models, tools)."""
|
2
|
+
import sys
|
2
3
|
|
3
4
|
from janito.cli.cli_commands.list_providers import handle_list_providers
|
4
5
|
from janito.cli.cli_commands.list_models import handle_list_models
|
@@ -15,10 +16,11 @@ def handle_getter(args, config_mgr=None):
|
|
15
16
|
if getattr(args, "list_models", False):
|
16
17
|
provider = getattr(args, "provider", None)
|
17
18
|
if not provider:
|
19
|
+
import sys
|
18
20
|
print(
|
19
21
|
"Error: No provider selected. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
20
22
|
)
|
21
|
-
|
23
|
+
sys.exit(1)
|
22
24
|
provider_instance = ProviderRegistry().get_instance(provider)
|
23
25
|
GETTER_DISPATCH = {
|
24
26
|
"list_providers": partial(handle_list_providers, args),
|
janito/cli/core/runner.py
CHANGED
@@ -28,6 +28,10 @@ def _populate_driver_config_data(args, modifiers, provider, model):
|
|
28
28
|
driver_config_data = {"model": model}
|
29
29
|
if getattr(args, "verbose_api", None) is not None:
|
30
30
|
driver_config_data["verbose_api"] = args.verbose_api
|
31
|
+
|
32
|
+
# Add reasoning_effort from --effort CLI argument
|
33
|
+
if getattr(args, "effort", None) is not None:
|
34
|
+
driver_config_data["reasoning_effort"] = args.effort
|
31
35
|
for field in LLMDriverConfig.__dataclass_fields__:
|
32
36
|
if field in CONFIG_LOOKUP_KEYS:
|
33
37
|
if field in modifiers and modifiers[field] is not None:
|
@@ -64,8 +68,10 @@ def prepare_llm_driver_config(args, modifiers):
|
|
64
68
|
from janito.provider_registry import ProviderRegistry
|
65
69
|
|
66
70
|
provider_instance = None
|
71
|
+
provider_instance = ProviderRegistry().get_instance(provider)
|
72
|
+
if provider_instance is None:
|
73
|
+
return provider, None, None
|
67
74
|
try:
|
68
|
-
provider_instance = ProviderRegistry().get_instance(provider)
|
69
75
|
if not provider_instance.is_model_available(model):
|
70
76
|
print(
|
71
77
|
f"Error: Model '{model}' is not available for provider '{provider}'."
|
@@ -98,16 +104,28 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
98
104
|
from janito.provider_registry import ProviderRegistry
|
99
105
|
|
100
106
|
# Patch: disable execution/run tools if not enabled
|
107
|
+
import janito.tools
|
108
|
+
adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
|
101
109
|
if not exec_enabled:
|
102
|
-
import janito.tools
|
103
|
-
adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
|
104
110
|
if hasattr(adapter, "disable_execution_tools"):
|
105
111
|
adapter.disable_execution_tools()
|
106
112
|
else:
|
107
|
-
|
108
|
-
|
113
|
+
# Try to re-register execution tools if possible (print warning if not supported)
|
114
|
+
if hasattr(adapter, "register_tool"):
|
115
|
+
# This is a no-op if already registered, but we can attempt to re-register known execution tools
|
116
|
+
try:
|
117
|
+
from janito.tools.adapters.local import PythonCodeRunTool, PythonCommandRunTool, PythonFileRunTool, RunBashCommandTool, RunPowershellCommandTool
|
118
|
+
for tool_cls in [PythonCodeRunTool, PythonCommandRunTool, PythonFileRunTool, RunBashCommandTool, RunPowershellCommandTool]:
|
119
|
+
try:
|
120
|
+
adapter.register_tool(tool_cls)
|
121
|
+
except Exception:
|
122
|
+
pass # Already registered or error
|
123
|
+
except Exception:
|
124
|
+
pass
|
109
125
|
|
110
126
|
provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
|
127
|
+
if provider_instance is None:
|
128
|
+
return
|
111
129
|
mode = get_prompt_mode(args)
|
112
130
|
if getattr(args, "verbose", False):
|
113
131
|
print_verbose_info(
|
@@ -119,8 +137,10 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
119
137
|
PromptHandler as SingleShotPromptHandler,
|
120
138
|
)
|
121
139
|
|
140
|
+
# DEBUG: Print exec_enabled propagation at runner
|
141
|
+
|
122
142
|
handler = SingleShotPromptHandler(
|
123
|
-
args, provider_instance, llm_driver_config, role=agent_role
|
143
|
+
args, provider_instance, llm_driver_config, role=agent_role, exec_enabled=exec_enabled
|
124
144
|
)
|
125
145
|
handler.handle()
|
126
146
|
else:
|
@@ -136,6 +156,7 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
136
156
|
args=args,
|
137
157
|
verbose_tools=verbose_tools,
|
138
158
|
verbose_agent=getattr(args, "verbose_agent", False),
|
159
|
+
exec_enabled=exec_enabled,
|
139
160
|
)
|
140
161
|
session.run()
|
141
162
|
|
janito/cli/core/setters.py
CHANGED
@@ -37,10 +37,14 @@ def handle_set(args, config_mgr=None):
|
|
37
37
|
return _handle_set_max_tokens(value)
|
38
38
|
if key == "base_url":
|
39
39
|
return _handle_set_base_url(value)
|
40
|
+
if key in ["azure_deployment_name", "azure-deployment-name"]:
|
41
|
+
global_config.file_set("azure_deployment_name", value)
|
42
|
+
print(f"Azure deployment name set to '{value}'.")
|
43
|
+
return True
|
40
44
|
if ".max_tokens" in key or ".base_url" in key:
|
41
45
|
return _handle_set_provider_level_setting(key, value)
|
42
46
|
print(
|
43
|
-
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"
|
47
|
+
f"Error: Unknown config key '{key}'. Supported: provider, model, <provider>.model, max_tokens, base_url, azure_deployment_name, <provider>.max_tokens, <provider>.base_url, <provider>.<model>.max_tokens, <provider>.<model>.base_url"
|
44
48
|
)
|
45
49
|
return True
|
46
50
|
except Exception as e:
|
janito/cli/core/unsetters.py
CHANGED
@@ -1,54 +1,54 @@
|
|
1
|
-
from janito.config import config as global_config
|
2
|
-
|
3
|
-
|
4
|
-
def handle_unset(args):
|
5
|
-
unset_arg = getattr(args, "unset", None)
|
6
|
-
if not unset_arg:
|
7
|
-
return False
|
8
|
-
key = unset_arg.strip().replace("-", "_")
|
9
|
-
if "." in key:
|
10
|
-
# Provider or model-specific keys
|
11
|
-
parts = key.split(".")
|
12
|
-
if len(parts) == 2:
|
13
|
-
provider, subkey = parts
|
14
|
-
current_val = (
|
15
|
-
global_config.file_config.get("providers", {})
|
16
|
-
.get(provider, {})
|
17
|
-
.get(subkey)
|
18
|
-
)
|
19
|
-
if current_val is not None:
|
20
|
-
del global_config.file_config["providers"][provider][subkey]
|
21
|
-
global_config.save()
|
22
|
-
print(f"{key}={current_val} was removed.")
|
23
|
-
return True
|
24
|
-
elif len(parts) == 3:
|
25
|
-
provider, model, subkey = parts
|
26
|
-
model_conf = (
|
27
|
-
global_config.file_config.get("providers", {})
|
28
|
-
.get(provider, {})
|
29
|
-
.get("models", {})
|
30
|
-
.get(model, {})
|
31
|
-
)
|
32
|
-
current_val = model_conf.get(subkey)
|
33
|
-
if current_val is not None:
|
34
|
-
del global_config.file_config["providers"][provider]["models"][model][
|
35
|
-
subkey
|
36
|
-
]
|
37
|
-
global_config.save()
|
38
|
-
print(f"{key}={current_val} was removed.")
|
39
|
-
return True
|
40
|
-
else:
|
41
|
-
current_val = global_config.file_config.get(key)
|
42
|
-
if current_val is not None:
|
43
|
-
del global_config.file_config[key]
|
44
|
-
global_config.save()
|
45
|
-
print(f"{key}={current_val} was removed.")
|
46
|
-
return True
|
47
|
-
if "=" in unset_arg:
|
48
|
-
provided_key = unset_arg.split("=")[0].strip()
|
49
|
-
print(
|
50
|
-
f"Error: --unset expected a key, not key=value. Did you mean: --unset {provided_key}?"
|
51
|
-
)
|
52
|
-
else:
|
53
|
-
print(f"Error: no value set for {key} (cannot remove)")
|
54
|
-
return True
|
1
|
+
from janito.config import config as global_config
|
2
|
+
|
3
|
+
|
4
|
+
def handle_unset(args):
|
5
|
+
unset_arg = getattr(args, "unset", None)
|
6
|
+
if not unset_arg:
|
7
|
+
return False
|
8
|
+
key = unset_arg.strip().replace("-", "_")
|
9
|
+
if "." in key:
|
10
|
+
# Provider or model-specific keys
|
11
|
+
parts = key.split(".")
|
12
|
+
if len(parts) == 2:
|
13
|
+
provider, subkey = parts
|
14
|
+
current_val = (
|
15
|
+
global_config.file_config.get("providers", {})
|
16
|
+
.get(provider, {})
|
17
|
+
.get(subkey)
|
18
|
+
)
|
19
|
+
if current_val is not None:
|
20
|
+
del global_config.file_config["providers"][provider][subkey]
|
21
|
+
global_config.save()
|
22
|
+
print(f"{key}={current_val} was removed.")
|
23
|
+
return True
|
24
|
+
elif len(parts) == 3:
|
25
|
+
provider, model, subkey = parts
|
26
|
+
model_conf = (
|
27
|
+
global_config.file_config.get("providers", {})
|
28
|
+
.get(provider, {})
|
29
|
+
.get("models", {})
|
30
|
+
.get(model, {})
|
31
|
+
)
|
32
|
+
current_val = model_conf.get(subkey)
|
33
|
+
if current_val is not None:
|
34
|
+
del global_config.file_config["providers"][provider]["models"][model][
|
35
|
+
subkey
|
36
|
+
]
|
37
|
+
global_config.save()
|
38
|
+
print(f"{key}={current_val} was removed.")
|
39
|
+
return True
|
40
|
+
else:
|
41
|
+
current_val = global_config.file_config.get(key)
|
42
|
+
if current_val is not None:
|
43
|
+
del global_config.file_config[key]
|
44
|
+
global_config.save()
|
45
|
+
print(f"{key}={current_val} was removed.")
|
46
|
+
return True
|
47
|
+
if "=" in unset_arg:
|
48
|
+
provided_key = unset_arg.split("=")[0].strip()
|
49
|
+
print(
|
50
|
+
f"Error: --unset expected a key, not key=value. Did you mean: --unset {provided_key}?"
|
51
|
+
)
|
52
|
+
else:
|
53
|
+
print(f"Error: no value set for {key} (cannot remove)")
|
54
|
+
return True
|
janito/cli/main_cli.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import argparse
|
2
|
+
import sys
|
2
3
|
import enum
|
3
4
|
from janito.cli.core.setters import handle_api_key_set, handle_set
|
4
5
|
from janito.cli.core.getters import handle_getter
|
@@ -118,6 +119,13 @@ definition = [
|
|
118
119
|
"help": "Port for the termweb server (default: 8088)",
|
119
120
|
},
|
120
121
|
),
|
122
|
+
(["--effort"],
|
123
|
+
{
|
124
|
+
"choices": ["low", "medium", "high", "none"],
|
125
|
+
"default": None,
|
126
|
+
"help": "Set the reasoning effort for models that support it (low, medium, high, none)",
|
127
|
+
},
|
128
|
+
),
|
121
129
|
(["user_prompt"], {"nargs": argparse.REMAINDER, "help": "Prompt to submit"}),
|
122
130
|
(
|
123
131
|
["-e", "--event-log"],
|
@@ -138,6 +146,7 @@ MODIFIER_KEYS = [
|
|
138
146
|
"role",
|
139
147
|
"system",
|
140
148
|
"temperature",
|
149
|
+
|
141
150
|
"verbose",
|
142
151
|
"raw",
|
143
152
|
"web",
|
@@ -238,7 +247,7 @@ class JanitoCLI:
|
|
238
247
|
print(
|
239
248
|
"Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
240
249
|
)
|
241
|
-
|
250
|
+
sys.exit(1)
|
242
251
|
modifiers = self.collect_modifiers()
|
243
252
|
self._maybe_print_verbose_modifiers(modifiers)
|
244
253
|
setup_event_logger_if_needed(self.args)
|
@@ -251,6 +260,8 @@ class JanitoCLI:
|
|
251
260
|
self._maybe_print_verbose_llm_config(llm_driver_config, run_mode)
|
252
261
|
if run_mode == RunMode.RUN:
|
253
262
|
self._maybe_print_verbose_run_mode()
|
263
|
+
# DEBUG: Print exec_enabled propagation at main_cli
|
264
|
+
|
254
265
|
handle_runner(
|
255
266
|
self.args,
|
256
267
|
provider,
|
janito/cli/prompt_core.py
CHANGED
@@ -8,7 +8,7 @@ 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 RequestStarted, RequestFinished, RequestStatus
|
11
|
+
from janito.driver_events import RequestStarted, RequestFinished, RequestStatus, RateLimitRetry
|
12
12
|
from janito.tools.tool_events import ToolCallError
|
13
13
|
import threading
|
14
14
|
from janito.cli.verbose_output import print_verbose_header
|
@@ -59,13 +59,16 @@ class PromptHandler:
|
|
59
59
|
else:
|
60
60
|
self.console.print(inner_event.result)
|
61
61
|
return None
|
62
|
+
if isinstance(inner_event, RateLimitRetry):
|
63
|
+
status.update(f"[yellow]Rate limited. Waiting {inner_event.retry_delay:.0f}s before retry (attempt {inner_event.attempt}).[yellow]")
|
64
|
+
return None
|
62
65
|
if isinstance(inner_event, RequestFinished):
|
63
66
|
status.update("[bold green]Received response![bold green]")
|
64
67
|
return "break"
|
65
68
|
elif (
|
66
69
|
isinstance(inner_event, RequestFinished)
|
67
70
|
and getattr(inner_event, "status", None) == "error"
|
68
|
-
):
|
71
|
+
): # noqa
|
69
72
|
error_msg = (
|
70
73
|
inner_event.error if hasattr(inner_event, "error") else "Unknown error"
|
71
74
|
)
|
@@ -32,17 +32,25 @@ class RichTerminalReporter(EventHandlerBase):
|
|
32
32
|
self._waiting_printed = False
|
33
33
|
|
34
34
|
def on_RequestStarted(self, event):
|
35
|
-
# Print waiting message with provider name
|
35
|
+
# Print waiting message with provider and model name
|
36
36
|
provider = None
|
37
|
+
model = None
|
37
38
|
if hasattr(event, "payload") and isinstance(event.payload, dict):
|
38
39
|
provider = event.payload.get("provider_name")
|
40
|
+
model = event.payload.get("model") or event.payload.get("model_name")
|
39
41
|
if not provider:
|
40
42
|
provider = getattr(event, "provider_name", None)
|
41
43
|
if not provider:
|
42
44
|
provider = getattr(event, "driver_name", None)
|
43
45
|
if not provider:
|
44
46
|
provider = "LLM"
|
45
|
-
|
47
|
+
if not model:
|
48
|
+
model = getattr(event, "model", None)
|
49
|
+
if not model:
|
50
|
+
model = getattr(event, "model_name", None)
|
51
|
+
if not model:
|
52
|
+
model = "?"
|
53
|
+
self.console.print(f"[bold cyan]Waiting for {provider} (model: {model})...[/bold cyan]", end="")
|
46
54
|
|
47
55
|
def on_ResponseReceived(self, event):
|
48
56
|
parts = event.parts if hasattr(event, "parts") else None
|
@@ -58,7 +66,18 @@ class RichTerminalReporter(EventHandlerBase):
|
|
58
66
|
def on_RequestFinished(self, event):
|
59
67
|
self.console.print("") # Print end of line after waiting message
|
60
68
|
self._waiting_printed = False
|
61
|
-
response =
|
69
|
+
response = getattr(event, "response", None)
|
70
|
+
error = getattr(event, "error", None)
|
71
|
+
exception = getattr(event, "exception", None)
|
72
|
+
|
73
|
+
# Print error and exception if present
|
74
|
+
if error:
|
75
|
+
self.console.print(f"[bold red]Error:[/] {error}")
|
76
|
+
self.console.file.flush()
|
77
|
+
if exception:
|
78
|
+
self.console.print(f"[red]Exception:[/] {exception}")
|
79
|
+
self.console.file.flush()
|
80
|
+
|
62
81
|
if response is not None:
|
63
82
|
if self.raw_mode:
|
64
83
|
self.console.print(Pretty(response, expand_all=True))
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# janito.cli.single_shot_mode package
|
2
|
-
from .handler import PromptHandler
|
3
|
-
|
4
|
-
__all__ = [
|
5
|
-
"PromptHandler",
|
6
|
-
]
|
1
|
+
# janito.cli.single_shot_mode package
|
2
|
+
from .handler import PromptHandler
|
3
|
+
|
4
|
+
__all__ = [
|
5
|
+
"PromptHandler",
|
6
|
+
]
|
@@ -15,21 +15,31 @@ from janito.cli.console import shared_console
|
|
15
15
|
|
16
16
|
|
17
17
|
class PromptHandler:
|
18
|
-
def __init__(self, args, provider_instance, llm_driver_config, role=None):
|
18
|
+
def __init__(self, args, provider_instance, llm_driver_config, role=None, exec_enabled=False):
|
19
19
|
self.args = args
|
20
20
|
self.provider_instance = provider_instance
|
21
21
|
self.llm_driver_config = llm_driver_config
|
22
22
|
self.role = role
|
23
|
+
self.exec_enabled = exec_enabled
|
23
24
|
from janito.agent.setup_agent import create_configured_agent
|
24
25
|
|
26
|
+
# DEBUG: Print exec_enabled propagation
|
25
27
|
self.agent = create_configured_agent(
|
26
28
|
provider_instance=provider_instance,
|
27
29
|
llm_driver_config=llm_driver_config,
|
28
30
|
role=role,
|
29
31
|
verbose_tools=getattr(args, "verbose_tools", False),
|
30
32
|
verbose_agent=getattr(args, "verbose_agent", False),
|
33
|
+
exec_enabled=exec_enabled,
|
31
34
|
)
|
32
35
|
# Setup conversation/history if needed
|
36
|
+
# Dynamically enable/disable execution tools in the registry
|
37
|
+
try:
|
38
|
+
registry = __import__('janito.tools', fromlist=['get_local_tools_adapter']).get_local_tools_adapter()
|
39
|
+
if hasattr(registry, 'set_execution_tools_enabled'):
|
40
|
+
registry.set_execution_tools_enabled(exec_enabled)
|
41
|
+
except Exception as e:
|
42
|
+
shared_console.print(f"[yellow]Warning: Could not update execution tools dynamically in single-shot mode: {e}[/yellow]")
|
33
43
|
self.generic_handler = GenericPromptHandler(
|
34
44
|
args, [], provider_instance=provider_instance
|
35
45
|
)
|
janito/cli/verbose_output.py
CHANGED
@@ -19,7 +19,7 @@ def print_verbose_header(agent, args):
|
|
19
19
|
parts = [
|
20
20
|
f"Janito {VERSION}",
|
21
21
|
f"Provider: {agent.llm_provider.__class__.__name__}",
|
22
|
-
f"Model: {agent.llm_provider.
|
22
|
+
(f"Model: {agent.llm_provider.driver_config.extra.get('azure_deployment_name', agent.llm_provider.driver_config.model)}{role_part}" if agent.llm_provider.__class__.__name__ == 'AzureOpenAIProvider' else f"Model: {getattr(agent.llm_provider.driver_config, 'model', '-')}{role_part}"),
|
23
23
|
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
24
|
]
|
25
25
|
if hasattr(args, "think") and args.think:
|
janito/config.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Shared Janito ConfigManager singleton
|
2
|
-
from janito.config_manager import ConfigManager
|
3
|
-
|
4
|
-
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
-
config = ConfigManager(config_path=None)
|
1
|
+
# Shared Janito ConfigManager singleton
|
2
|
+
from janito.config_manager import ConfigManager
|
3
|
+
|
4
|
+
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
+
config = ConfigManager(config_path=None)
|
janito/config_manager.py
CHANGED
@@ -46,6 +46,7 @@ class ConfigManager:
|
|
46
46
|
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
47
47
|
with open(self.config_path, "w", encoding="utf-8") as f:
|
48
48
|
json.dump(self.file_config, f, indent=2)
|
49
|
+
f.write("\n")
|
49
50
|
|
50
51
|
def get(self, key, default=None):
|
51
52
|
# Precedence: runtime_overrides > file_config > defaults
|
@@ -63,6 +64,7 @@ class ConfigManager:
|
|
63
64
|
self.file_config[key] = value
|
64
65
|
with open(self.config_path, "w", encoding="utf-8") as f:
|
65
66
|
json.dump(self.file_config, f, indent=2)
|
67
|
+
f.write("\n")
|
66
68
|
|
67
69
|
def all(self, layered=False):
|
68
70
|
merged = dict(self.defaults)
|
janito/driver_events.py
CHANGED
@@ -90,6 +90,20 @@ class ToolCallFinished(DriverEvent):
|
|
90
90
|
return self.name
|
91
91
|
|
92
92
|
|
93
|
+
@attr.s(auto_attribs=True, kw_only=True)
|
94
|
+
@attr.s(auto_attribs=True, kw_only=True)
|
95
|
+
class RateLimitRetry(DriverEvent):
|
96
|
+
"""Emitted by a driver when it encounters a provider rate-limit (HTTP 429) and
|
97
|
+
decides to retry the request after a delay. This allows UIs or logging layers
|
98
|
+
to give feedback to the user while the driver automatically waits.
|
99
|
+
"""
|
100
|
+
|
101
|
+
attempt: int = 0 # Retry attempt number (starting at 1)
|
102
|
+
retry_delay: float = 0 # Delay in seconds before the next attempt
|
103
|
+
error: str = None # The original error message
|
104
|
+
details: dict = None # Additional details extracted from the provider response
|
105
|
+
|
106
|
+
|
93
107
|
@attr.s(auto_attribs=True, kw_only=True)
|
94
108
|
class ResponseReceived(DriverEvent):
|
95
109
|
parts: list = None
|