janito 2.2.0__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.
Files changed (130) hide show
  1. janito/__init__.py +6 -6
  2. janito/agent/setup_agent.py +14 -5
  3. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +3 -1
  4. janito/cli/chat_mode/bindings.py +6 -0
  5. janito/cli/chat_mode/session.py +16 -0
  6. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  7. janito/cli/chat_mode/shell/commands/__init__.py +3 -0
  8. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  9. janito/cli/chat_mode/shell/commands/exec.py +27 -0
  10. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  11. janito/cli/chat_mode/shell/commands/tools.py +17 -6
  12. janito/cli/chat_mode/shell/input_history.py +62 -62
  13. janito/cli/chat_mode/shell/session/manager.py +1 -0
  14. janito/cli/chat_mode/toolbar.py +1 -0
  15. janito/cli/cli_commands/list_models.py +35 -35
  16. janito/cli/cli_commands/list_providers.py +9 -9
  17. janito/cli/cli_commands/list_tools.py +53 -53
  18. janito/cli/cli_commands/model_selection.py +50 -50
  19. janito/cli/cli_commands/model_utils.py +13 -2
  20. janito/cli/cli_commands/set_api_key.py +19 -19
  21. janito/cli/cli_commands/show_config.py +51 -51
  22. janito/cli/cli_commands/show_system_prompt.py +62 -62
  23. janito/cli/config.py +2 -1
  24. janito/cli/core/__init__.py +4 -4
  25. janito/cli/core/event_logger.py +59 -59
  26. janito/cli/core/getters.py +3 -1
  27. janito/cli/core/runner.py +165 -148
  28. janito/cli/core/setters.py +5 -1
  29. janito/cli/core/unsetters.py +54 -54
  30. janito/cli/main_cli.py +12 -1
  31. janito/cli/prompt_core.py +5 -2
  32. janito/cli/rich_terminal_reporter.py +22 -3
  33. janito/cli/single_shot_mode/__init__.py +6 -6
  34. janito/cli/single_shot_mode/handler.py +11 -1
  35. janito/cli/verbose_output.py +1 -1
  36. janito/config.py +5 -5
  37. janito/config_manager.py +2 -0
  38. janito/driver_events.py +14 -0
  39. janito/drivers/anthropic/driver.py +113 -113
  40. janito/drivers/azure_openai/driver.py +38 -3
  41. janito/drivers/driver_registry.py +0 -2
  42. janito/drivers/openai/driver.py +196 -36
  43. janito/formatting_token.py +54 -54
  44. janito/i18n/__init__.py +35 -35
  45. janito/i18n/messages.py +23 -23
  46. janito/i18n/pt.py +47 -47
  47. janito/llm/__init__.py +5 -5
  48. janito/llm/agent.py +443 -443
  49. janito/llm/auth.py +1 -0
  50. janito/llm/driver.py +7 -1
  51. janito/llm/driver_config.py +1 -0
  52. janito/llm/driver_config_builder.py +34 -34
  53. janito/llm/driver_input.py +12 -12
  54. janito/llm/message_parts.py +60 -60
  55. janito/llm/model.py +38 -38
  56. janito/llm/provider.py +196 -196
  57. janito/provider_config.py +7 -3
  58. janito/provider_registry.py +176 -158
  59. janito/providers/__init__.py +1 -0
  60. janito/providers/anthropic/model_info.py +22 -22
  61. janito/providers/anthropic/provider.py +2 -2
  62. janito/providers/azure_openai/model_info.py +7 -6
  63. janito/providers/azure_openai/provider.py +30 -2
  64. janito/providers/deepseek/__init__.py +1 -1
  65. janito/providers/deepseek/model_info.py +16 -16
  66. janito/providers/deepseek/provider.py +91 -91
  67. janito/providers/google/model_info.py +21 -29
  68. janito/providers/google/provider.py +49 -38
  69. janito/providers/mistralai/provider.py +2 -2
  70. janito/providers/provider_static_info.py +2 -3
  71. janito/tools/adapters/__init__.py +1 -1
  72. janito/tools/adapters/local/adapter.py +33 -11
  73. janito/tools/adapters/local/ask_user.py +102 -102
  74. janito/tools/adapters/local/copy_file.py +84 -84
  75. janito/tools/adapters/local/create_directory.py +69 -69
  76. janito/tools/adapters/local/create_file.py +82 -82
  77. janito/tools/adapters/local/delete_text_in_file.py +4 -7
  78. janito/tools/adapters/local/fetch_url.py +97 -97
  79. janito/tools/adapters/local/find_files.py +138 -138
  80. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  81. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  82. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  83. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  84. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  85. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  86. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  87. janito/tools/adapters/local/move_file.py +3 -13
  88. janito/tools/adapters/local/python_code_run.py +166 -166
  89. janito/tools/adapters/local/python_command_run.py +164 -164
  90. janito/tools/adapters/local/python_file_run.py +163 -163
  91. janito/tools/adapters/local/remove_directory.py +6 -17
  92. janito/tools/adapters/local/remove_file.py +4 -10
  93. janito/tools/adapters/local/replace_text_in_file.py +6 -9
  94. janito/tools/adapters/local/run_bash_command.py +176 -176
  95. janito/tools/adapters/local/run_powershell_command.py +219 -219
  96. janito/tools/adapters/local/search_text/__init__.py +1 -1
  97. janito/tools/adapters/local/search_text/core.py +201 -201
  98. janito/tools/adapters/local/search_text/match_lines.py +1 -1
  99. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  100. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  101. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  102. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  103. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  104. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  105. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  106. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  107. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  108. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  109. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  110. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  111. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  112. janito/tools/adapters/local/view_file.py +167 -167
  113. janito/tools/inspect_registry.py +17 -17
  114. janito/tools/tool_base.py +105 -105
  115. janito/tools/tool_events.py +58 -58
  116. janito/tools/tool_run_exception.py +12 -12
  117. janito/tools/tool_use_tracker.py +81 -81
  118. janito/tools/tool_utils.py +45 -45
  119. janito/tools/tools_adapter.py +78 -6
  120. janito/tools/tools_schema.py +104 -104
  121. janito/version.py +4 -4
  122. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/METADATA +388 -251
  123. janito-2.3.0.dist-info/RECORD +181 -0
  124. janito/drivers/google_genai/driver.py +0 -54
  125. janito/drivers/google_genai/schema_generator.py +0 -67
  126. janito-2.2.0.dist-info/RECORD +0 -182
  127. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/WHEEL +0 -0
  128. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/entry_points.txt +0 -0
  129. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/licenses/LICENSE +0 -0
  130. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/top_level.txt +0 -0
@@ -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
- return
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
@@ -1,148 +1,165 @@
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.verbose_output import print_verbose_info
6
-
7
-
8
- def _choose_provider(args):
9
- provider = getattr(args, "provider", None)
10
- if provider is None:
11
- provider = get_config_provider()
12
- if provider and getattr(args, "verbose", False):
13
- print_verbose_info(
14
- "Default provider", provider, style="magenta", align_content=True
15
- )
16
- elif provider is None:
17
- print(
18
- "Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
19
- )
20
- return None
21
- return provider
22
-
23
-
24
- def _populate_driver_config_data(args, modifiers, provider, model):
25
- from janito.provider_config import get_effective_setting
26
-
27
- CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
28
- driver_config_data = {"model": model}
29
- if getattr(args, "verbose_api", None) is not None:
30
- driver_config_data["verbose_api"] = args.verbose_api
31
- for field in LLMDriverConfig.__dataclass_fields__:
32
- if field in CONFIG_LOOKUP_KEYS:
33
- if field in modifiers and modifiers[field] is not None:
34
- driver_config_data[field] = modifiers[field]
35
- else:
36
- value = get_effective_setting(provider, model, field)
37
- if value is not None:
38
- driver_config_data[field] = value
39
- elif field in modifiers and field != "model":
40
- driver_config_data[field] = modifiers[field]
41
- return driver_config_data
42
-
43
-
44
- def prepare_llm_driver_config(args, modifiers):
45
- """Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
46
-
47
- This helper additionally validates that the chosen ``--model`` (or the
48
- resolved model coming from config precedence) is actually available for the
49
- selected provider. If the combination is invalid an error is printed and
50
- ``None`` is returned for the config so that the caller can abort execution
51
- gracefully.
52
- """
53
- provider = _choose_provider(args)
54
- if provider is None:
55
- return None, None, None
56
- from janito.provider_config import get_effective_model
57
-
58
- model = getattr(args, "model", None)
59
- if not model:
60
- model = get_effective_model(provider)
61
-
62
- # Validate that the chosen model is supported by the selected provider
63
- if model:
64
- from janito.provider_registry import ProviderRegistry
65
-
66
- provider_instance = None
67
- provider_instance = ProviderRegistry().get_instance(provider)
68
- if provider_instance is None:
69
- return provider, None, None
70
- try:
71
- if not provider_instance.is_model_available(model):
72
- print(
73
- f"Error: Model '{model}' is not available for provider '{provider}'."
74
- )
75
- # Optionally, print available models if possible
76
- if hasattr(provider_instance, 'get_model_info'):
77
- available_models = [
78
- m["name"]
79
- for m in provider_instance.get_model_info().values()
80
- if isinstance(m, dict) and "name" in m
81
- ]
82
- print(f"Available models: {', '.join(available_models)}")
83
- return provider, None, None
84
- except Exception as e:
85
- print(f"Error validating model for provider '{provider}': {e}")
86
- return provider, None, None
87
- driver_config_data = _populate_driver_config_data(args, modifiers, provider, model)
88
- llm_driver_config = LLMDriverConfig(**driver_config_data)
89
- if getattr(llm_driver_config, "verbose_api", None):
90
- pass
91
- agent_role = modifiers.get("role", "software developer")
92
- return provider, llm_driver_config, agent_role
93
-
94
-
95
- def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False, exec_enabled=False):
96
- """
97
- Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
98
- """
99
- zero_mode = getattr(args, "zero", False)
100
- from janito.provider_registry import ProviderRegistry
101
-
102
- # Patch: disable execution/run tools if not enabled
103
- if not exec_enabled:
104
- import janito.tools
105
- adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
106
- if hasattr(adapter, "disable_execution_tools"):
107
- adapter.disable_execution_tools()
108
- else:
109
- import janito.tools
110
- adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
111
-
112
- provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
113
- if provider_instance is None:
114
- return
115
- mode = get_prompt_mode(args)
116
- if getattr(args, "verbose", False):
117
- print_verbose_info(
118
- "Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
119
- )
120
- print_verbose_info("Agent role", agent_role, style="green")
121
- if mode == "single_shot":
122
- from janito.cli.single_shot_mode.handler import (
123
- PromptHandler as SingleShotPromptHandler,
124
- )
125
-
126
- handler = SingleShotPromptHandler(
127
- args, provider_instance, llm_driver_config, role=agent_role
128
- )
129
- handler.handle()
130
- else:
131
- from janito.cli.chat_mode.session import ChatSession
132
- from rich.console import Console
133
-
134
- console = Console()
135
- session = ChatSession(
136
- console,
137
- provider_instance,
138
- llm_driver_config,
139
- role=agent_role,
140
- args=args,
141
- verbose_tools=verbose_tools,
142
- verbose_agent=getattr(args, "verbose_agent", False),
143
- )
144
- session.run()
145
-
146
-
147
- def get_prompt_mode(args):
148
- 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.verbose_output import print_verbose_info
6
+
7
+
8
+ def _choose_provider(args):
9
+ provider = getattr(args, "provider", None)
10
+ if provider is None:
11
+ provider = get_config_provider()
12
+ if provider and getattr(args, "verbose", False):
13
+ print_verbose_info(
14
+ "Default provider", provider, style="magenta", align_content=True
15
+ )
16
+ elif provider is None:
17
+ print(
18
+ "Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
19
+ )
20
+ return None
21
+ return provider
22
+
23
+
24
+ def _populate_driver_config_data(args, modifiers, provider, model):
25
+ from janito.provider_config import get_effective_setting
26
+
27
+ CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
28
+ driver_config_data = {"model": model}
29
+ if getattr(args, "verbose_api", None) is not None:
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
35
+ for field in LLMDriverConfig.__dataclass_fields__:
36
+ if field in CONFIG_LOOKUP_KEYS:
37
+ if field in modifiers and modifiers[field] is not None:
38
+ driver_config_data[field] = modifiers[field]
39
+ else:
40
+ value = get_effective_setting(provider, model, field)
41
+ if value is not None:
42
+ driver_config_data[field] = value
43
+ elif field in modifiers and field != "model":
44
+ driver_config_data[field] = modifiers[field]
45
+ return driver_config_data
46
+
47
+
48
+ def prepare_llm_driver_config(args, modifiers):
49
+ """Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
50
+
51
+ This helper additionally validates that the chosen ``--model`` (or the
52
+ resolved model coming from config precedence) is actually available for the
53
+ selected provider. If the combination is invalid an error is printed and
54
+ ``None`` is returned for the config so that the caller can abort execution
55
+ gracefully.
56
+ """
57
+ provider = _choose_provider(args)
58
+ if provider is None:
59
+ return None, None, None
60
+ from janito.provider_config import get_effective_model
61
+
62
+ model = getattr(args, "model", None)
63
+ if not model:
64
+ model = get_effective_model(provider)
65
+
66
+ # Validate that the chosen model is supported by the selected provider
67
+ if model:
68
+ from janito.provider_registry import ProviderRegistry
69
+
70
+ provider_instance = None
71
+ provider_instance = ProviderRegistry().get_instance(provider)
72
+ if provider_instance is None:
73
+ return provider, None, None
74
+ try:
75
+ if not provider_instance.is_model_available(model):
76
+ print(
77
+ f"Error: Model '{model}' is not available for provider '{provider}'."
78
+ )
79
+ # Optionally, print available models if possible
80
+ if hasattr(provider_instance, 'get_model_info'):
81
+ available_models = [
82
+ m["name"]
83
+ for m in provider_instance.get_model_info().values()
84
+ if isinstance(m, dict) and "name" in m
85
+ ]
86
+ print(f"Available models: {', '.join(available_models)}")
87
+ return provider, None, None
88
+ except Exception as e:
89
+ print(f"Error validating model for provider '{provider}': {e}")
90
+ return provider, None, None
91
+ driver_config_data = _populate_driver_config_data(args, modifiers, provider, model)
92
+ llm_driver_config = LLMDriverConfig(**driver_config_data)
93
+ if getattr(llm_driver_config, "verbose_api", None):
94
+ pass
95
+ agent_role = modifiers.get("role", "software developer")
96
+ return provider, llm_driver_config, agent_role
97
+
98
+
99
+ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False, exec_enabled=False):
100
+ """
101
+ Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
102
+ """
103
+ zero_mode = getattr(args, "zero", False)
104
+ from janito.provider_registry import ProviderRegistry
105
+
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))
109
+ if not exec_enabled:
110
+ if hasattr(adapter, "disable_execution_tools"):
111
+ adapter.disable_execution_tools()
112
+ else:
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
125
+
126
+ provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
127
+ if provider_instance is None:
128
+ return
129
+ mode = get_prompt_mode(args)
130
+ if getattr(args, "verbose", False):
131
+ print_verbose_info(
132
+ "Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
133
+ )
134
+ print_verbose_info("Agent role", agent_role, style="green")
135
+ if mode == "single_shot":
136
+ from janito.cli.single_shot_mode.handler import (
137
+ PromptHandler as SingleShotPromptHandler,
138
+ )
139
+
140
+ # DEBUG: Print exec_enabled propagation at runner
141
+
142
+ handler = SingleShotPromptHandler(
143
+ args, provider_instance, llm_driver_config, role=agent_role, exec_enabled=exec_enabled
144
+ )
145
+ handler.handle()
146
+ else:
147
+ from janito.cli.chat_mode.session import ChatSession
148
+ from rich.console import Console
149
+
150
+ console = Console()
151
+ session = ChatSession(
152
+ console,
153
+ provider_instance,
154
+ llm_driver_config,
155
+ role=agent_role,
156
+ args=args,
157
+ verbose_tools=verbose_tools,
158
+ verbose_agent=getattr(args, "verbose_agent", False),
159
+ exec_enabled=exec_enabled,
160
+ )
161
+ session.run()
162
+
163
+
164
+ def get_prompt_mode(args):
165
+ return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
@@ -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:
@@ -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
- return
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
- self.console.print(f"[bold cyan]Waiting for {provider}...[/bold cyan]", end="")
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 = event.response if hasattr(event, "response") else None
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
  )
@@ -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.model_name}{role_part}",
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: