janito 3.4.0__py3-none-any.whl → 3.5.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/README.md +3 -0
- janito/cli/chat_mode/bindings.py +50 -0
- janito/cli/chat_mode/session.py +12 -1
- janito/cli/chat_mode/shell/commands/multi.py +5 -0
- janito/cli/chat_mode/shell/commands/security/allowed_sites.py +47 -33
- janito/cli/cli_commands/check_tools.py +212 -0
- janito/cli/cli_commands/list_plugins.py +52 -43
- janito/cli/core/getters.py +3 -0
- janito/cli/core/model_guesser.py +40 -24
- janito/cli/main_cli.py +9 -12
- janito/cli/prompt_core.py +47 -9
- janito/cli/rich_terminal_reporter.py +2 -2
- janito/drivers/openai/driver.py +1 -0
- janito/drivers/zai/driver.py +1 -0
- janito/i18n/it.py +46 -46
- janito/llm/agent.py +32 -16
- janito/llm/auth_utils.py +14 -5
- janito/llm/cancellation_manager.py +63 -0
- janito/llm/driver.py +8 -0
- janito/llm/enter_cancellation.py +107 -0
- janito/plugin_system/__init__.py +10 -0
- janito/{plugins → plugin_system}/base.py +5 -2
- janito/plugin_system/core_loader.py +217 -0
- janito/plugin_system/core_loader_fixed.py +225 -0
- janito/plugins/__init__.py +31 -12
- janito/plugins/auto_loader.py +12 -11
- janito/plugins/auto_loader_fixed.py +12 -11
- janito/plugins/builtin.py +15 -1
- janito/plugins/core/__init__.py +7 -0
- janito/plugins/core/codeanalyzer/__init__.py +43 -0
- janito/plugins/core/filemanager/__init__.py +124 -0
- janito/plugins/core/filemanager/tools/create_file.py +87 -0
- janito/plugins/core/filemanager/tools/replace_text_in_file.py +270 -0
- janito/plugins/core/imagedisplay/__init__.py +14 -0
- janito/plugins/core/imagedisplay/plugin.py +51 -0
- janito/plugins/core/imagedisplay/tools/__init__.py +1 -0
- janito/plugins/core/imagedisplay/tools/show_image.py +83 -0
- janito/{tools/adapters/local → plugins/core/imagedisplay/tools}/show_image_grid.py +13 -5
- janito/plugins/core/system/__init__.py +23 -0
- janito/plugins/core/system/tools/run_bash_command.py +204 -0
- janito/plugins/core/system/tools/run_powershell_command.py +234 -0
- janito/plugins/core_adapter.py +89 -11
- janito/plugins/dev/__init__.py +7 -0
- janito/plugins/dev/pythondev/__init__.py +37 -0
- janito/plugins/dev/visualization/__init__.py +23 -0
- janito/plugins/discovery.py +5 -5
- janito/plugins/discovery_core.py +14 -9
- janito/plugins/example_plugin.py +108 -0
- janito/plugins/manager.py +1 -1
- janito/plugins/tools/__init__.py +10 -0
- janito/{tools/adapters/local → plugins/tools}/ask_user.py +3 -3
- janito/plugins/tools/copy_file.py +87 -0
- janito/plugins/tools/core_tools_plugin.py +87 -0
- janito/plugins/tools/create_directory.py +70 -0
- janito/{tools/adapters/local → plugins/tools}/create_file.py +6 -6
- janito/plugins/tools/decorators.py +19 -0
- janito/plugins/tools/delete_text_in_file.py +134 -0
- janito/{tools/adapters/local → plugins/tools}/fetch_url.py +3 -3
- janito/plugins/tools/find_files.py +143 -0
- janito/plugins/tools/get_file_outline/__init__.py +7 -0
- janito/plugins/tools/get_file_outline/core.py +122 -0
- janito/plugins/tools/get_file_outline/java_outline.py +47 -0
- janito/plugins/tools/get_file_outline/markdown_outline.py +14 -0
- janito/plugins/tools/get_file_outline/python_outline.py +303 -0
- janito/plugins/tools/get_file_outline/search_outline.py +36 -0
- janito/plugins/tools/move_file.py +131 -0
- janito/plugins/tools/open_html_in_browser.py +51 -0
- janito/plugins/tools/open_url.py +37 -0
- janito/{tools/adapters/local → plugins/tools}/python_code_run.py +23 -7
- janito/{tools/adapters/local → plugins/tools}/python_command_run.py +21 -5
- janito/{tools/adapters/local → plugins/tools}/python_file_run.py +21 -5
- janito/plugins/tools/read_chart.py +259 -0
- janito/plugins/tools/read_files.py +58 -0
- janito/plugins/tools/remove_directory.py +55 -0
- janito/plugins/tools/remove_file.py +58 -0
- janito/{tools/adapters/local → plugins/tools}/replace_text_in_file.py +4 -4
- janito/{tools/adapters/local → plugins/tools}/run_bash_command.py +3 -3
- janito/{tools/adapters/local → plugins/tools}/run_powershell_command.py +3 -3
- janito/plugins/tools/search_text/__init__.py +7 -0
- janito/plugins/tools/search_text/core.py +205 -0
- janito/plugins/tools/search_text/match_lines.py +67 -0
- janito/plugins/tools/search_text/pattern_utils.py +73 -0
- janito/plugins/tools/search_text/traverse_directory.py +145 -0
- janito/{tools/adapters/local → plugins/tools}/show_image.py +15 -6
- janito/plugins/tools/show_image_grid.py +85 -0
- janito/plugins/tools/validate_file_syntax/__init__.py +7 -0
- janito/plugins/tools/validate_file_syntax/core.py +114 -0
- janito/plugins/tools/validate_file_syntax/css_validator.py +35 -0
- janito/plugins/tools/validate_file_syntax/html_validator.py +100 -0
- janito/plugins/tools/validate_file_syntax/jinja2_validator.py +50 -0
- janito/plugins/tools/validate_file_syntax/js_validator.py +27 -0
- janito/plugins/tools/validate_file_syntax/json_validator.py +6 -0
- janito/plugins/tools/validate_file_syntax/markdown_validator.py +109 -0
- janito/plugins/tools/validate_file_syntax/ps1_validator.py +32 -0
- janito/plugins/tools/validate_file_syntax/python_validator.py +5 -0
- janito/plugins/tools/validate_file_syntax/xml_validator.py +11 -0
- janito/plugins/tools/validate_file_syntax/yaml_validator.py +6 -0
- janito/plugins/tools/view_file.py +172 -0
- janito/plugins/ui/__init__.py +7 -0
- janito/plugins/ui/userinterface/__init__.py +16 -0
- janito/plugins/ui/userinterface/tools/ask_user.py +110 -0
- janito/plugins/web/__init__.py +7 -0
- janito/plugins/web/webtools/__init__.py +33 -0
- janito/plugins/web/webtools/tools/fetch_url.py +458 -0
- janito/providers/__init__.py +1 -0
- janito/providers/together/__init__.py +1 -0
- janito/providers/together/model_info.py +69 -0
- janito/providers/together/provider.py +108 -0
- janito/tools/__init__.py +31 -7
- janito/tools/adapters/__init__.py +6 -1
- janito/tools/adapters/local/__init__.py +7 -70
- janito/tools/cli_initializer.py +88 -0
- janito/tools/initialize.py +70 -0
- janito/tools/loop_protection_decorator.py +114 -117
- janito-3.5.1.dist-info/METADATA +229 -0
- {janito-3.4.0.dist-info → janito-3.5.1.dist-info}/RECORD +155 -86
- janito/plugins/core_loader.py +0 -120
- janito/plugins/core_loader_fixed.py +0 -125
- janito/tools/function_adapter.py +0 -65
- janito-3.4.0.dist-info/METADATA +0 -84
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/__init__.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/core.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/java_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/markdown_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/python_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/get_file_outline/search_outline.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/__init__.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/core.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/match_lines.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/pattern_utils.py +0 -0
- /janito/{tools/adapters/local → plugins/core/codeanalyzer/tools}/search_text/traverse_directory.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/copy_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/create_directory.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/delete_text_in_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/find_files.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/move_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/read_files.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/remove_directory.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/remove_file.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/__init__.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/core.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/css_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/html_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/jinja2_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/js_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/json_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/markdown_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/ps1_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/python_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/xml_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/validate_file_syntax/yaml_validator.py +0 -0
- /janito/{tools/adapters/local → plugins/core/filemanager/tools}/view_file.py +0 -0
- /janito/{tools/adapters/local → plugins/dev/visualization/tools}/read_chart.py +0 -0
- /janito/{tools/adapters/local → plugins/web/webtools/tools}/open_html_in_browser.py +0 -0
- /janito/{tools/adapters/local → plugins/web/webtools/tools}/open_url.py +0 -0
- {janito-3.4.0.dist-info → janito-3.5.1.dist-info}/WHEEL +0 -0
- {janito-3.4.0.dist-info → janito-3.5.1.dist-info}/entry_points.txt +0 -0
- {janito-3.4.0.dist-info → janito-3.5.1.dist-info}/licenses/LICENSE +0 -0
- {janito-3.4.0.dist-info → janito-3.5.1.dist-info}/top_level.txt +0 -0
janito/cli/main_cli.py
CHANGED
@@ -238,6 +238,13 @@ definition = [
|
|
238
238
|
"help": "List all resources (tools, commands, config) from loaded plugins",
|
239
239
|
},
|
240
240
|
),
|
241
|
+
(
|
242
|
+
["--check-tools"],
|
243
|
+
{
|
244
|
+
"action": "store_true",
|
245
|
+
"help": "Check all registered tools for signature validation and availability",
|
246
|
+
},
|
247
|
+
),
|
241
248
|
]
|
242
249
|
|
243
250
|
MODIFIER_KEYS = [
|
@@ -269,18 +276,7 @@ GETTER_KEYS = [
|
|
269
276
|
"region_info",
|
270
277
|
"list_providers_region",
|
271
278
|
"ping",
|
272
|
-
|
273
|
-
GETTER_KEYS = [
|
274
|
-
"show_config",
|
275
|
-
"list_providers",
|
276
|
-
"list_profiles",
|
277
|
-
"list_models",
|
278
|
-
"list_tools",
|
279
|
-
"list_config",
|
280
|
-
"list_drivers",
|
281
|
-
"region_info",
|
282
|
-
"list_providers_region",
|
283
|
-
"ping",
|
279
|
+
"check_tools",
|
284
280
|
]
|
285
281
|
|
286
282
|
|
@@ -406,6 +402,7 @@ class JanitoCLI:
|
|
406
402
|
or self.args.list_plugins_available
|
407
403
|
or self.args.list_resources
|
408
404
|
or self.args.ping
|
405
|
+
or self.args.check_tools
|
409
406
|
):
|
410
407
|
self._maybe_print_verbose_provider_model()
|
411
408
|
handle_getter(self.args)
|
janito/cli/prompt_core.py
CHANGED
@@ -207,15 +207,53 @@ class PromptHandler:
|
|
207
207
|
"""
|
208
208
|
try:
|
209
209
|
self._print_verbose_debug("Calling agent.chat()...")
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
210
|
+
|
211
|
+
# Use global cancellation manager
|
212
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
213
|
+
import time
|
214
|
+
from threading import Thread, Event
|
215
|
+
|
216
|
+
cancel_manager = get_cancellation_manager()
|
217
|
+
driver_cancel_event = cancel_manager.start_new_request()
|
218
|
+
|
219
|
+
# Timer setup with live status display
|
220
|
+
start_time = time.time()
|
221
|
+
stop_timer = Event()
|
222
|
+
|
223
|
+
# Create a status display with timer
|
224
|
+
from rich.live import Live
|
225
|
+
from rich.text import Text
|
226
|
+
|
227
|
+
def get_timer_text():
|
228
|
+
elapsed = time.time() - start_time
|
229
|
+
minutes, seconds = divmod(int(elapsed), 60)
|
230
|
+
return Text(f"⏱️ Waiting for response... {minutes:02d}:{seconds:02d}", style="cyan")
|
231
|
+
|
232
|
+
# Use Live display for updating timer
|
233
|
+
with Live(get_timer_text(), refresh_per_second=4, console=self.console) as live:
|
234
|
+
def update_timer():
|
235
|
+
while not stop_timer.wait(0.25): # Update every 250ms
|
236
|
+
live.update(get_timer_text())
|
237
|
+
|
238
|
+
timer_thread = Thread(target=update_timer, daemon=True)
|
239
|
+
timer_thread.start()
|
240
|
+
|
241
|
+
try:
|
242
|
+
final_event = self.agent.chat(prompt=user_prompt)
|
243
|
+
stop_timer.set() # Stop the timer
|
244
|
+
|
245
|
+
if hasattr(self.agent, "set_latest_event"):
|
246
|
+
self.agent.set_latest_event(final_event)
|
247
|
+
self.agent.last_event = final_event
|
248
|
+
self._print_verbose_debug(f"agent.chat() returned: {final_event}")
|
249
|
+
self._print_verbose_final_event(final_event)
|
250
|
+
if on_event and final_event is not None:
|
251
|
+
on_event(final_event)
|
252
|
+
global_event_bus.publish(final_event)
|
253
|
+
finally:
|
254
|
+
stop_timer.set() # Ensure timer stops
|
255
|
+
cancel_manager.clear_current_request()
|
256
|
+
|
219
257
|
except KeyboardInterrupt:
|
220
258
|
# Capture user interrupt / cancellation
|
221
259
|
self.console.print("[red]Interrupted by the user.[/red]")
|
@@ -161,10 +161,10 @@ class RichTerminalReporter(EventHandlerBase):
|
|
161
161
|
self.console.print(msg)
|
162
162
|
self.console.file.flush()
|
163
163
|
elif subtype == ReportSubtype.STDOUT:
|
164
|
-
self.console.print(msg)
|
164
|
+
self.console.print(msg, style=None)
|
165
165
|
self.console.file.flush()
|
166
166
|
elif subtype == ReportSubtype.STDERR:
|
167
|
-
self.console.print(
|
167
|
+
self.console.print(msg, style=None)
|
168
168
|
self.console.file.flush()
|
169
169
|
else:
|
170
170
|
self.console.print(msg)
|
janito/drivers/openai/driver.py
CHANGED
@@ -181,6 +181,7 @@ class OpenAIModelDriver(LLMDriver):
|
|
181
181
|
is_insufficient_quota = (
|
182
182
|
"insufficient_quota" in lower_err
|
183
183
|
or "exceeded your current quota" in lower_err
|
184
|
+
or "exceeded_current_quota_error" in lower_err
|
184
185
|
)
|
185
186
|
is_rate_limit = (
|
186
187
|
status_code == 429
|
janito/drivers/zai/driver.py
CHANGED
janito/i18n/it.py
CHANGED
@@ -1,46 +1,46 @@
|
|
1
|
-
# pragma: allowlist secret
|
2
|
-
translations = {
|
3
|
-
"36107ed78ab25f6fb12ad8ce13018cd1ce6735d1": "Avvio del server web...",
|
4
|
-
"70a0d194687568a47aa617fd85036ace1e69a982": "Vuoi davvero uscire? (s/n): ",
|
5
|
-
"5c9ebcbbd7632ecb328bd52958b17158afaa32c6": "F12 = Azione Rapida (segue l'azione raccomandata)",
|
6
|
-
"fe21121e2934234b68d19b2757532117d440c1e3": "Chiave API non trovata. Si prega di configurare 'api_key' nel file di configurazione.",
|
7
|
-
"c9e3759b1756eba35b381ce2b72cd659e132b01f": "Ciao, {name}!",
|
8
|
-
"ca1fee2f55baabdc2e4b0e9529c89ee024e62079": "Nessun prompt fornito nei messaggi",
|
9
|
-
"f7449d23d0c500ae2a0b31e04f92b47a4d8ae845": "max_tokens deve essere un intero, ricevuto: {resolved_max_tokens!r}",
|
10
|
-
"70a9ed8edb6da12e208431a31aa16ba54419b26f": "Risposta non valida/malformed da OpenAI (tentativo {attempt}/{max_retries}). Riprovo tra {wait_time} secondi...",
|
11
|
-
"a873085e3b06184fb5d27e842f97b06b6190976d": "Numero massimo di tentativi per risposta non valida raggiunto. Generazione errore.",
|
12
|
-
"66a34568bbe846bb1bde3619eb4d6dfa10211104": "L'API non supporta l'uso degli strumenti.",
|
13
|
-
"09b81476b75586da4116b83f8be70d77b174cec3": "
|
14
|
-
"5717a35dd2a1533fb7e15edc8c9329cb69f3410b": "Errore server API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
|
15
|
-
"02e760ba15ed863176c1290ac8a9b923963103cd": "Errore client API OpenAI {status_code}: {e}. Nessun nuovo tentativo.",
|
16
|
-
"2e52b0bbc8f16226b70e3e20f95c9245d2bcdb47": "Errore API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
|
17
|
-
"012cc970e039fdd79c452fc676202c814ffc76ae": "Numero massimo di tentativi per errore API OpenAI raggiunto. Generazione errore.",
|
18
|
-
"d0438e45667d31e0022b2497b5901cd4300f084b": "QueuedMessageHandler.handle_message si aspetta un dizionario con 'type' e 'message', ricevuto {msg_type}: {msg!r}",
|
19
|
-
"9d3460187ffa19c7c8a4020157072b1087e1bd2f": "[QueuedMessageHandler] {msg_type}: {msg}",
|
20
|
-
"3813833343430e8afa8fce33385c5e39fb24dd60": "[QueuedMessageHandler] {msg_type}: {message}",
|
21
|
-
"0be9a22226e16a40797010d23a0f581542dca40e": "[ToolExecutor] {tool_name} chiamato con argomenti: {args}",
|
22
|
-
"42c68edcb25442f518b1af77c6a2ddc07461aae0": "[ToolExecutor] Motivo chiamata: {tool_call_reason}",
|
23
|
-
"002ff598115d84595ffeee6219cb5c03d3a1d4a6": "Domanda",
|
24
|
-
"35747d13dcd91e8e8790c7f767d5ed764f541b9e": "procedi",
|
25
|
-
"33dde3a1afbc418768a69fa53168d9b0638fe1aa": "avanti",
|
26
|
-
"eee0bbba4ff92adbeb038a77df0466d660f15716": "continua",
|
27
|
-
"edee9402d198b04ac77dcf5dc9cc3dac44573782": "prossimo",
|
28
|
-
"8fdb7e2fa84f4faf0d9b92f466df424ec47a165b": "ok",
|
29
|
-
"5f8f924671cda79b5205a6bf1b776f347c4a7a07": "Opzioni di configurazione disponibili:\n",
|
30
|
-
"cef780a309cd234750764d42697882c24168ddab": "{key:15} {desc} (predefinito: {default})",
|
31
|
-
"68c2cc7f0ceaa3e499ecb4db331feb4debbbcc23": "Modello",
|
32
|
-
"c3f104d1365744b538bfde9f4adb6a6df4b80355": "Funzione",
|
33
|
-
"99a0efc6cfd85d8ff2732a6718140f822cb90472": "Stile",
|
34
|
-
"f1702b4686278becffc88baabe6f4b7a8355532c": "Messaggi",
|
35
|
-
"c38c6c1f3a2743f8626703abb302e403d20ff81c": "Token",
|
36
|
-
"a817d7eb8e0f1dab755ab5203a082e5c3c094fce": "Prompt",
|
37
|
-
"2ff255684a2277f806fcebf3fe338ed27857f350": "Completamento",
|
38
|
-
"b25928c69902557b0ef0a628490a3a1768d7b82f": "Totale",
|
39
|
-
"76e63d65c883ed50df40ac3aeef0c2d6a1c4ad60": "Azione Rapida",
|
40
|
-
"5397e0583f14f6c88de06b1ef28f460a1fb5b0ae": "Sì",
|
41
|
-
"816c52fd2bdd94a63cd0944823a6c0aa9384c103": "No",
|
42
|
-
"c47ae15370cfe1ed2781eedc1dc2547d12d9e972": "Aiuto",
|
43
|
-
"cc3dbd47e1cf9003a55d3366b3adbcd72275e525": "Nuovo Task",
|
44
|
-
"efa5a8b84e1afe65c81ecfce28c398c48f19ddc2": "Benvenuto su Janito{version_str}! Modalità chat attiva. Digita /exit per uscire.",
|
45
|
-
"b314d6e1460f86e0f21abc5aceb7935a2a0667e8": "Benvenuto su Janito{version_str} in modalità [white on magenta]VANILLA[/white on magenta]! Strumenti, prompt di sistema e temperatura sono disattivati, a meno che non siano sovrascritti.",
|
46
|
-
}
|
1
|
+
# pragma: allowlist secret
|
2
|
+
translations = {
|
3
|
+
"36107ed78ab25f6fb12ad8ce13018cd1ce6735d1": "Avvio del server web...",
|
4
|
+
"70a0d194687568a47aa617fd85036ace1e69a982": "Vuoi davvero uscire? (s/n): ",
|
5
|
+
"5c9ebcbbd7632ecb328bd52958b17158afaa32c6": "F12 = Azione Rapida (segue l'azione raccomandata)",
|
6
|
+
"fe21121e2934234b68d19b2757532117d440c1e3": "Chiave API non trovata. Si prega di configurare 'api_key' nel file di configurazione.",
|
7
|
+
"c9e3759b1756eba35b381ce2b72cd659e132b01f": "Ciao, {name}!",
|
8
|
+
"ca1fee2f55baabdc2e4b0e9529c89ee024e62079": "Nessun prompt fornito nei messaggi",
|
9
|
+
"f7449d23d0c500ae2a0b31e04f92b47a4d8ae845": "max_tokens deve essere un intero, ricevuto: {resolved_max_tokens!r}",
|
10
|
+
"70a9ed8edb6da12e208431a31aa16ba54419b26f": "Risposta non valida/malformed da OpenAI (tentativo {attempt}/{max_retries}). Riprovo tra {wait_time} secondi...",
|
11
|
+
"a873085e3b06184fb5d27e842f97b06b6190976d": "Numero massimo di tentativi per risposta non valida raggiunto. Generazione errore.",
|
12
|
+
"66a34568bbe846bb1bde3619eb4d6dfa10211104": "L'API non supporta l'uso degli strumenti.",
|
13
|
+
"09b81476b75586da4116b83f8be70d77b174cec3": "Limit di richieste API OpenAI (429) (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
|
14
|
+
"5717a35dd2a1533fb7e15edc8c9329cb69f3410b": "Errore server API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
|
15
|
+
"02e760ba15ed863176c1290ac8a9b923963103cd": "Errore client API OpenAI {status_code}: {e}. Nessun nuovo tentativo.",
|
16
|
+
"2e52b0bbc8f16226b70e3e20f95c9245d2bcdb47": "Errore API OpenAI (tentativo {attempt}/{max_retries}): {e}. Riprovo tra {wait_time} secondi...",
|
17
|
+
"012cc970e039fdd79c452fc676202c814ffc76ae": "Numero massimo di tentativi per errore API OpenAI raggiunto. Generazione errore.",
|
18
|
+
"d0438e45667d31e0022b2497b5901cd4300f084b": "QueuedMessageHandler.handle_message si aspetta un dizionario con 'type' e 'message', ricevuto {msg_type}: {msg!r}",
|
19
|
+
"9d3460187ffa19c7c8a4020157072b1087e1bd2f": "[QueuedMessageHandler] {msg_type}: {msg}",
|
20
|
+
"3813833343430e8afa8fce33385c5e39fb24dd60": "[QueuedMessageHandler] {msg_type}: {message}",
|
21
|
+
"0be9a22226e16a40797010d23a0f581542dca40e": "[ToolExecutor] {tool_name} chiamato con argomenti: {args}",
|
22
|
+
"42c68edcb25442f518b1af77c6a2ddc07461aae0": "[ToolExecutor] Motivo chiamata: {tool_call_reason}",
|
23
|
+
"002ff598115d84595ffeee6219cb5c03d3a1d4a6": "Domanda",
|
24
|
+
"35747d13dcd91e8e8790c7f767d5ed764f541b9e": "procedi",
|
25
|
+
"33dde3a1afbc418768a69fa53168d9b0638fe1aa": "avanti",
|
26
|
+
"eee0bbba4ff92adbeb038a77df0466d660f15716": "continua",
|
27
|
+
"edee9402d198b04ac77dcf5dc9cc3dac44573782": "prossimo",
|
28
|
+
"8fdb7e2fa84f4faf0d9b92f466df424ec47a165b": "ok",
|
29
|
+
"5f8f924671cda79b5205a6bf1b776f347c4a7a07": "Opzioni di configurazione disponibili:\n",
|
30
|
+
"cef780a309cd234750764d42697882c24168ddab": "{key:15} {desc} (predefinito: {default})",
|
31
|
+
"68c2cc7f0ceaa3e499ecb4db331feb4debbbcc23": "Modello",
|
32
|
+
"c3f104d1365744b538bfde9f4adb6a6df4b80355": "Funzione",
|
33
|
+
"99a0efc6cfd85d8ff2732a6718140f822cb90472": "Stile",
|
34
|
+
"f1702b4686278becffc88baabe6f4b7a8355532c": "Messaggi",
|
35
|
+
"c38c6c1f3a2743f8626703abb302e403d20ff81c": "Token",
|
36
|
+
"a817d7eb8e0f1dab755ab5203a082e5c3c094fce": "Prompt",
|
37
|
+
"2ff255684a2277f806fcebf3fe338ed27857f350": "Completamento",
|
38
|
+
"b25928c69902557b0ef0a628490a3a1768d7b82f": "Totale",
|
39
|
+
"76e63d65c883ed50df40ac3aeef0c2d6a1c4ad60": "Azione Rapida",
|
40
|
+
"5397e0583f14f6c88de06b1ef28f460a1fb5b0ae": "Sì",
|
41
|
+
"816c52fd2bdd94a63cd0944823a6c0aa9384c103": "No",
|
42
|
+
"c47ae15370cfe1ed2781eedc1dc2547d12d9e972": "Aiuto",
|
43
|
+
"cc3dbd47e1cf9003a55d3366b3adbcd72275e525": "Nuovo Task",
|
44
|
+
"efa5a8b84e1afe65c81ecfce28c398c48f19ddc2": "Benvenuto su Janito{version_str}! Modalità chat attiva. Digita /exit per uscire.",
|
45
|
+
"b314d6e1460f86e0f21abc5aceb7935a2a0667e8": "Benvenuto su Janito{version_str} in modalità [white on magenta]VANILLA[/white on magenta]! Strumenti, prompt di sistema e temperatura sono disattivati, a meno che non siano sovrascritti.",
|
46
|
+
}
|
janito/llm/agent.py
CHANGED
@@ -318,23 +318,39 @@ class LLMAgent:
|
|
318
318
|
loop_count = 1
|
319
319
|
import threading
|
320
320
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
321
|
+
# Use global cancellation manager
|
322
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
323
|
+
|
324
|
+
cancel_manager = get_cancellation_manager()
|
325
|
+
driver_cancel_event = cancel_manager.start_new_request()
|
326
|
+
|
327
|
+
# Store cancellation event on agent for external access
|
328
|
+
self.cancel_event = driver_cancel_event
|
329
|
+
|
330
|
+
try:
|
331
|
+
while True:
|
332
|
+
self._print_verbose_chat_loop(loop_count)
|
333
|
+
driver_input = self._prepare_driver_input(
|
334
|
+
config, cancel_event=driver_cancel_event
|
334
335
|
)
|
335
|
-
|
336
|
-
|
337
|
-
|
336
|
+
self.input_queue.put(driver_input)
|
337
|
+
try:
|
338
|
+
result, added_tool_results = self._process_next_response()
|
339
|
+
except KeyboardInterrupt:
|
340
|
+
cancel_manager.cancel_current_request()
|
341
|
+
raise
|
342
|
+
if getattr(self, "verbose_agent", False):
|
343
|
+
print(
|
344
|
+
f"[agent] [DEBUG] Returned from _process_next_response: result={result}, added_tool_results={added_tool_results}"
|
345
|
+
)
|
346
|
+
if self._should_exit_chat_loop(result, added_tool_results):
|
347
|
+
return result
|
348
|
+
loop_count += 1
|
349
|
+
finally:
|
350
|
+
cancel_manager.clear_current_request()
|
351
|
+
# Clean up cancellation event
|
352
|
+
if hasattr(self, "cancel_event"):
|
353
|
+
delattr(self, "cancel_event")
|
338
354
|
|
339
355
|
def _clear_driver_queues(self):
|
340
356
|
if hasattr(self, "driver") and self.driver:
|
janito/llm/auth_utils.py
CHANGED
@@ -13,9 +13,18 @@ def handle_missing_api_key(provider_name: str, env_var_name: str) -> None:
|
|
13
13
|
provider_name: Name of the provider (e.g., 'alibaba', 'openai')
|
14
14
|
env_var_name: Environment variable name (e.g., 'ALIBABA_API_KEY')
|
15
15
|
"""
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
if provider_name == "moonshot":
|
17
|
+
print(
|
18
|
+
f"[ERROR] You exceeded your current token quota for Moonshot. Please check your account balance at:"
|
19
|
+
)
|
20
|
+
print(f" https://platform.moonshot.ai/console/pay")
|
21
|
+
print()
|
22
|
+
print(f"To set a new API key, use:")
|
23
|
+
print(f" janito --set-api-key YOUR_NEW_API_KEY -p moonshot")
|
24
|
+
else:
|
25
|
+
print(
|
26
|
+
f"[ERROR] No API key found for provider '{provider_name}'. Please set the API key using:"
|
27
|
+
)
|
28
|
+
print(f" janito --set-api-key YOUR_API_KEY -p {provider_name}")
|
29
|
+
print(f"Or set the {env_var_name} environment variable.")
|
21
30
|
sys.exit(1)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
"""
|
2
|
+
Global cancellation manager for LLM requests.
|
3
|
+
Provides a centralized way to cancel ongoing requests.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import threading
|
7
|
+
from typing import Optional
|
8
|
+
|
9
|
+
|
10
|
+
class CancellationManager:
|
11
|
+
"""Manages cancellation of LLM requests across the application."""
|
12
|
+
|
13
|
+
def __init__(self):
|
14
|
+
self._current_cancel_event: Optional[threading.Event] = None
|
15
|
+
self._lock = threading.Lock()
|
16
|
+
self._keyboard_cancellation = None
|
17
|
+
|
18
|
+
def start_new_request(self) -> threading.Event:
|
19
|
+
"""Start a new request and return its cancellation event."""
|
20
|
+
with self._lock:
|
21
|
+
# Create new cancellation event for this request
|
22
|
+
self._current_cancel_event = threading.Event()
|
23
|
+
|
24
|
+
# Start keyboard monitoring
|
25
|
+
from janito.llm.enter_cancellation import get_enter_cancellation
|
26
|
+
|
27
|
+
self._keyboard_cancellation = get_enter_cancellation()
|
28
|
+
self._keyboard_cancellation.start_monitoring(self._current_cancel_event)
|
29
|
+
|
30
|
+
return self._current_cancel_event
|
31
|
+
|
32
|
+
def cancel_current_request(self) -> bool:
|
33
|
+
"""Cancel the current request if one is active."""
|
34
|
+
with self._lock:
|
35
|
+
if self._current_cancel_event is not None:
|
36
|
+
self._current_cancel_event.set()
|
37
|
+
return True
|
38
|
+
return False
|
39
|
+
|
40
|
+
def get_current_cancel_event(self) -> Optional[threading.Event]:
|
41
|
+
"""Get the current cancellation event."""
|
42
|
+
with self._lock:
|
43
|
+
return self._current_cancel_event
|
44
|
+
|
45
|
+
def clear_current_request(self):
|
46
|
+
"""Clear the current request cancellation event."""
|
47
|
+
with self._lock:
|
48
|
+
if self._keyboard_cancellation:
|
49
|
+
self._keyboard_cancellation.stop_monitoring()
|
50
|
+
self._keyboard_cancellation = None
|
51
|
+
self._current_cancel_event = None
|
52
|
+
|
53
|
+
|
54
|
+
# Global cancellation manager instance
|
55
|
+
_global_manager = None
|
56
|
+
|
57
|
+
|
58
|
+
def get_cancellation_manager() -> CancellationManager:
|
59
|
+
"""Get the global cancellation manager instance."""
|
60
|
+
global _global_manager
|
61
|
+
if _global_manager is None:
|
62
|
+
_global_manager = CancellationManager()
|
63
|
+
return _global_manager
|
janito/llm/driver.py
CHANGED
@@ -252,3 +252,11 @@ class LLMDriver(ABC):
|
|
252
252
|
def _get_message_from_result(self, result):
|
253
253
|
"""Extract the message object from the provider result. Subclasses must implement this."""
|
254
254
|
raise NotImplementedError("Subclasses must implement _get_message_from_result.")
|
255
|
+
|
256
|
+
def cancel_current_request(self):
|
257
|
+
"""Cancel the current request being processed."""
|
258
|
+
# Use global cancellation manager to cancel the current request
|
259
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
260
|
+
|
261
|
+
cancel_manager = get_cancellation_manager()
|
262
|
+
cancel_manager.cancel_current_request()
|
@@ -0,0 +1,107 @@
|
|
1
|
+
"""
|
2
|
+
Enter key cancellation for LLM requests.
|
3
|
+
Allows pressing Enter to cancel ongoing requests.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import threading
|
7
|
+
import sys
|
8
|
+
import time
|
9
|
+
from typing import Optional
|
10
|
+
|
11
|
+
|
12
|
+
class EnterCancellation:
|
13
|
+
"""Handles Enter key cancellation of LLM requests."""
|
14
|
+
|
15
|
+
def __init__(self):
|
16
|
+
self._cancel_event: Optional[threading.Event] = None
|
17
|
+
self._listener_thread: Optional[threading.Thread] = None
|
18
|
+
self._listening = False
|
19
|
+
|
20
|
+
def start_monitoring(self, cancel_event: threading.Event):
|
21
|
+
"""Start monitoring for Enter key to cancel the request."""
|
22
|
+
if self._listening:
|
23
|
+
return
|
24
|
+
|
25
|
+
self._cancel_event = cancel_event
|
26
|
+
self._listening = True
|
27
|
+
|
28
|
+
self._listener_thread = threading.Thread(
|
29
|
+
target=self._monitor_enter_key, daemon=True
|
30
|
+
)
|
31
|
+
self._listener_thread.start()
|
32
|
+
|
33
|
+
def stop_monitoring(self):
|
34
|
+
"""Stop monitoring for keyboard input."""
|
35
|
+
self._listening = False
|
36
|
+
if self._listener_thread and self._listener_thread.is_alive():
|
37
|
+
self._listener_thread.join(timeout=0.1)
|
38
|
+
|
39
|
+
def _monitor_enter_key(self):
|
40
|
+
"""Monitor for Enter key press."""
|
41
|
+
try:
|
42
|
+
self._handle_key_monitoring()
|
43
|
+
except Exception:
|
44
|
+
# Silently handle any errors
|
45
|
+
pass
|
46
|
+
|
47
|
+
def _handle_key_monitoring(self):
|
48
|
+
"""Handle the actual key monitoring logic."""
|
49
|
+
import sys
|
50
|
+
import select
|
51
|
+
|
52
|
+
try:
|
53
|
+
import msvcrt # Windows-specific keyboard input
|
54
|
+
|
55
|
+
self._monitor_windows_keys()
|
56
|
+
except ImportError:
|
57
|
+
self._monitor_unix_keys()
|
58
|
+
|
59
|
+
def _monitor_windows_keys(self):
|
60
|
+
"""Monitor keys on Windows systems."""
|
61
|
+
import msvcrt
|
62
|
+
|
63
|
+
while (
|
64
|
+
self._listening and self._cancel_event and not self._cancel_event.is_set()
|
65
|
+
):
|
66
|
+
try:
|
67
|
+
if msvcrt.kbhit():
|
68
|
+
char = msvcrt.getch()
|
69
|
+
if char in [b"\r", b"\n"]:
|
70
|
+
if self._cancel_event:
|
71
|
+
self._cancel_event.set()
|
72
|
+
break
|
73
|
+
else:
|
74
|
+
time.sleep(0.05)
|
75
|
+
except (IOError, OSError):
|
76
|
+
break
|
77
|
+
|
78
|
+
def _monitor_unix_keys(self):
|
79
|
+
"""Monitor keys on Unix-like systems."""
|
80
|
+
import sys
|
81
|
+
import select
|
82
|
+
|
83
|
+
while (
|
84
|
+
self._listening and self._cancel_event and not self._cancel_event.is_set()
|
85
|
+
):
|
86
|
+
try:
|
87
|
+
if sys.stdin in select.select([sys.stdin], [], [], 0.05)[0]:
|
88
|
+
char = sys.stdin.read(1)
|
89
|
+
if char in ["\r", "\n"]:
|
90
|
+
if self._cancel_event:
|
91
|
+
self._cancel_event.set()
|
92
|
+
break
|
93
|
+
time.sleep(0.05)
|
94
|
+
except:
|
95
|
+
time.sleep(0.05)
|
96
|
+
|
97
|
+
|
98
|
+
# Global instance
|
99
|
+
_global_enter_cancellation = None
|
100
|
+
|
101
|
+
|
102
|
+
def get_enter_cancellation() -> EnterCancellation:
|
103
|
+
"""Get the global Enter cancellation instance."""
|
104
|
+
global _global_enter_cancellation
|
105
|
+
if _global_enter_cancellation is None:
|
106
|
+
_global_enter_cancellation = EnterCancellation()
|
107
|
+
return _global_enter_cancellation
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"""
|
2
|
+
Plugin System Core Package
|
3
|
+
|
4
|
+
This package provides the foundational plugin system architecture.
|
5
|
+
It should not depend on any specific plugin implementations.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .base import Plugin, PluginMetadata, PluginResource
|
9
|
+
|
10
|
+
__all__ = ["Plugin", "PluginMetadata", "PluginResource"]
|
@@ -5,7 +5,10 @@ Base classes for janito plugins.
|
|
5
5
|
from abc import ABC, abstractmethod
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from typing import Dict, Any, List, Optional, Type, Union
|
8
|
-
from
|
8
|
+
from typing import TYPE_CHECKING
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from janito.tools.tool_base import ToolBase
|
9
12
|
|
10
13
|
|
11
14
|
@dataclass
|
@@ -50,7 +53,7 @@ class Plugin(ABC):
|
|
50
53
|
"""Return metadata describing this plugin."""
|
51
54
|
pass
|
52
55
|
|
53
|
-
def get_tools(self) -> List[Type[ToolBase]]:
|
56
|
+
def get_tools(self) -> List[Type["ToolBase"]]:
|
54
57
|
"""
|
55
58
|
Return a list of tool classes provided by this plugin.
|
56
59
|
|