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
janito/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
- """
2
- janito: A Python package for managing and interacting with Large Language Model (LLM) providers and their APIs.
3
- Provides a CLI for credential management and an extensible driver system for LLMs.
4
- """
5
-
6
- __version__ = "2.2.0"
1
+ """
2
+ janito: A Python package for managing and interacting with Large Language Model (LLM) providers and their APIs.
3
+ Provides a CLI for credential management and an extensible driver system for LLMs.
4
+ """
5
+
6
+ __version__ = "2.3.0"
@@ -20,6 +20,7 @@ def setup_agent(
20
20
  output_queue=None,
21
21
  verbose_tools=False,
22
22
  verbose_agent=False,
23
+ exec_enabled=False,
23
24
  ):
24
25
  """
25
26
  Creates an agent using a rendered system prompt template, passing an explicit role.
@@ -62,17 +63,23 @@ def setup_agent(
62
63
  f"Template file not found in either {template_path} or package resource."
63
64
  )
64
65
 
66
+ import time
65
67
  template = Template(template_content)
66
68
  # Prepare context for Jinja2 rendering from llm_driver_config
67
69
  # Compose context for Jinja2 rendering without using to_dict or temperature
68
70
  context = {}
69
71
  context["role"] = role or "software developer"
70
- # Inject current platform environment information
71
- pd = PlatformDiscovery()
72
- context["platform"] = pd.get_platform_name()
73
- context["python_version"] = pd.get_python_version()
74
- context["shell_info"] = pd.detect_shell()
72
+ # Inject current platform environment information only if exec_enabled
73
+ context["exec_enabled"] = bool(exec_enabled)
74
+ if exec_enabled:
75
+ pd = PlatformDiscovery()
76
+ context["platform"] = pd.get_platform_name()
77
+ context["python_version"] = pd.get_python_version()
78
+ context["shell_info"] = pd.detect_shell()
79
+ start_render = time.time()
75
80
  rendered_prompt = template.render(**context)
81
+ end_render = time.time()
82
+
76
83
  # Create the agent as before, now passing the explicit role
77
84
  # Do NOT pass temperature; do not depend on to_dict
78
85
  agent = LLMAgent(
@@ -97,6 +104,7 @@ def create_configured_agent(
97
104
  verbose_agent=False,
98
105
  templates_dir=None,
99
106
  zero_mode=False,
107
+ exec_enabled=False,
100
108
  ):
101
109
  """
102
110
  Normalizes agent setup for all CLI modes.
@@ -133,6 +141,7 @@ def create_configured_agent(
133
141
  output_queue=output_queue,
134
142
  verbose_tools=verbose_tools,
135
143
  verbose_agent=verbose_agent,
144
+ exec_enabled=exec_enabled,
136
145
  )
137
146
  if driver is not None:
138
147
  agent.driver = driver # Attach driver to agent for thread management
@@ -6,11 +6,13 @@ You are: {{ role }}
6
6
  You will answer following a pattern of: discovery, description, implementation (when a change is requested) and validation.
7
7
 
8
8
  {# Improves tool selection and platform specific constrains, eg, path format, C:\ vs /path #}
9
+ {% if exec_enabled %}
9
10
  You will be using the following environment:
10
11
  Platform: {{ platform }}
11
12
  Python version: {{ python_version }}
12
13
  Shell/Environment: {{ shell_info }}
13
-
14
+ {% endif %}
15
+
14
16
  Before answering map the questions to artifacts found in the current directory - the current project.
15
17
 
16
18
  Respond according to the following guidelines:
@@ -28,6 +28,12 @@ class KeyBindingsFactory:
28
28
  buf.text = "/restart"
29
29
  buf.validate_and_handle()
30
30
 
31
+ @bindings.add("f2")
32
+ def _(event):
33
+ buf = event.app.current_buffer
34
+ buf.text = "/exec on"
35
+ buf.validate_and_handle()
36
+
31
37
  @bindings.add("f12")
32
38
  def _(event):
33
39
  buf = event.app.current_buffer
@@ -20,6 +20,7 @@ from janito.cli.chat_mode.shell.autocomplete import ShellCommandCompleter
20
20
 
21
21
  class ChatShellState:
22
22
  def __init__(self, mem_history, conversation_history):
23
+ self.allow_execution = False # Controls whether execution tools are enabled
23
24
  self.mem_history = mem_history
24
25
  self.conversation_history = conversation_history
25
26
  self.paste_mode = False
@@ -52,7 +53,13 @@ class ChatSession:
52
53
  args=None,
53
54
  verbose_tools=False,
54
55
  verbose_agent=False,
56
+ exec_enabled=False
55
57
  ):
58
+ # Set allow_execution from exec_enabled or args
59
+ if args is not None and hasattr(args, "exec"):
60
+ allow_execution = bool(getattr(args, "exec", False))
61
+ else:
62
+ allow_execution = exec_enabled
56
63
  from janito.cli.prompt_core import PromptHandler as GenericPromptHandler
57
64
 
58
65
  self._prompt_handler = GenericPromptHandler(
@@ -82,12 +89,21 @@ class ChatSession:
82
89
  role=role,
83
90
  verbose_tools=verbose_tools,
84
91
  verbose_agent=verbose_agent,
92
+ exec_enabled=allow_execution
85
93
  )
86
94
  from janito.conversation_history import LLMConversationHistory
87
95
 
88
96
  self.shell_state = ChatShellState(self.mem_history, LLMConversationHistory())
89
97
  self.shell_state.agent = agent
98
+ self.shell_state.allow_execution = allow_execution
90
99
  self.agent = agent
100
+ # Filter execution tools at startup
101
+ try:
102
+ registry = getattr(__import__('janito.tools', fromlist=['get_local_tools_adapter']), 'get_local_tools_adapter')()
103
+ if hasattr(registry, 'set_execution_tools_enabled'):
104
+ registry.set_execution_tools_enabled(allow_execution)
105
+ except Exception as e:
106
+ self.console.print(f"[yellow]Warning: Could not filter execution tools at startup: {e}[/yellow]")
91
107
  from janito.perf_singleton import performance_collector
92
108
 
93
109
  self.performance_collector = performance_collector
@@ -1,21 +1,21 @@
1
- from prompt_toolkit.completion import Completer, Completion
2
- from janito.cli.chat_mode.shell.commands import get_shell_command_names
3
-
4
-
5
- class ShellCommandCompleter(Completer):
6
- """
7
- Provides autocomplete suggestions for shell commands starting with '/'.
8
- Uses the COMMAND_HANDLERS registry for available commands.
9
- """
10
-
11
- def __init__(self):
12
- # Only commands starting with '/'
13
- self.commands = get_shell_command_names()
14
-
15
- def get_completions(self, document, complete_event):
16
- text = document.text_before_cursor
17
- if text.startswith("/"):
18
- prefix = text[1:]
19
- for cmd in self.commands:
20
- if cmd[1:].startswith(prefix):
21
- yield Completion(cmd, start_position=-(len(prefix) + 1))
1
+ from prompt_toolkit.completion import Completer, Completion
2
+ from janito.cli.chat_mode.shell.commands import get_shell_command_names
3
+
4
+
5
+ class ShellCommandCompleter(Completer):
6
+ """
7
+ Provides autocomplete suggestions for shell commands starting with '/'.
8
+ Uses the COMMAND_HANDLERS registry for available commands.
9
+ """
10
+
11
+ def __init__(self):
12
+ # Only commands starting with '/'
13
+ self.commands = get_shell_command_names()
14
+
15
+ def get_completions(self, document, complete_event):
16
+ text = document.text_before_cursor
17
+ if text.startswith("/"):
18
+ prefix = text[1:]
19
+ for cmd in self.commands:
20
+ if cmd[1:].startswith(prefix):
21
+ yield Completion(cmd, start_position=-(len(prefix) + 1))
@@ -13,6 +13,9 @@ from .help import HelpShellHandler
13
13
  from janito.cli.console import shared_console
14
14
 
15
15
  COMMAND_HANDLERS = {
16
+ "/exec": __import__(
17
+ "janito.cli.chat_mode.shell.commands.exec", fromlist=["ExecShellHandler"]
18
+ ).ExecShellHandler,
16
19
  "/clear": __import__(
17
20
  "janito.cli.chat_mode.shell.commands.clear", fromlist=["ClearShellHandler"]
18
21
  ).ClearShellHandler,
@@ -1,12 +1,12 @@
1
- from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
2
- from janito.cli.console import shared_console
3
-
4
-
5
- class ClearShellHandler(ShellCmdHandler):
6
- help_text = "Clear the terminal screen using Rich console."
7
-
8
- def run(self):
9
- shared_console.clear()
10
- # Optionally show a message after clearing
11
- # shared_console.print("[green]Screen cleared.[/green]")
12
- return None
1
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
2
+ from janito.cli.console import shared_console
3
+
4
+
5
+ class ClearShellHandler(ShellCmdHandler):
6
+ help_text = "Clear the terminal screen using Rich console."
7
+
8
+ def run(self):
9
+ shared_console.clear()
10
+ # Optionally show a message after clearing
11
+ # shared_console.print("[green]Screen cleared.[/green]")
12
+ return None
@@ -0,0 +1,27 @@
1
+ from janito.cli.console import shared_console
2
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
3
+
4
+ class ExecShellHandler(ShellCmdHandler):
5
+ help_text = "/exec on|off: Enable or disable code and command execution tools. Usage: /exec on or /exec off."
6
+
7
+ def run(self):
8
+ if not self.shell_state:
9
+ shared_console.print("[red]Shell state unavailable.[/red]")
10
+ return
11
+ arg = (self.after_cmd_line or "").strip().lower()
12
+ if arg not in ("on", "off"):
13
+ shared_console.print("[yellow]Usage: /exec on|off[/yellow]")
14
+ return
15
+ enable = arg == "on"
16
+ self.shell_state.allow_execution = enable
17
+ # Dynamically enable/disable execution tools in the registry
18
+ try:
19
+ registry = __import__('janito.tools', fromlist=['get_local_tools_adapter']).get_local_tools_adapter()
20
+ if hasattr(registry, 'set_execution_tools_enabled'):
21
+ registry.set_execution_tools_enabled(enable)
22
+ except Exception as e:
23
+ shared_console.print(f"[yellow]Warning: Could not update execution tools dynamically: {e}[/yellow]")
24
+ if enable:
25
+ shared_console.print("[green]Execution tools ENABLED. You can now use code and command execution tools.[/green]")
26
+ else:
27
+ shared_console.print("[yellow]Execution tools DISABLED. Code and command execution tools are now blocked.[/yellow]")
@@ -1,51 +1,51 @@
1
- from prompt_toolkit.shortcuts import prompt
2
- from prompt_toolkit.application.current import get_app
3
- from prompt_toolkit.document import Document
4
- from prompt_toolkit.key_binding import KeyBindings
5
- from janito.cli.console import shared_console
6
- from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
7
-
8
-
9
- class MultiShellHandler(ShellCmdHandler):
10
- help_text = "Prompt for multi-line input and display the result. Usage: /multi"
11
-
12
- def run(self):
13
- shared_console.print(
14
- "[bold blue]Entering multi-line input mode. Press Esc+Enter or Ctrl+D to submit, Ctrl+C to cancel.[/bold blue]"
15
- )
16
- # Prompt for multi-line input
17
- bindings = KeyBindings()
18
- submitted = {"value": None}
19
-
20
- @bindings.add("escape", "enter")
21
- def _(event):
22
- buffer = event.app.current_buffer
23
- submitted["value"] = buffer.text
24
- event.app.exit(result=buffer.text)
25
-
26
- # Support Ctrl+D
27
- @bindings.add("c-d")
28
- def _(event):
29
- buffer = event.app.current_buffer
30
- submitted["value"] = buffer.text
31
- event.app.exit(result=buffer.text)
32
-
33
- try:
34
- user_input = prompt(
35
- "Multi-line > ",
36
- multiline=True,
37
- key_bindings=bindings,
38
- )
39
- except (EOFError, KeyboardInterrupt):
40
- shared_console.print("[red]Multi-line input cancelled.[/red]")
41
- return
42
-
43
- # Save input to history if available
44
- user_input_history = getattr(self.shell_state, "user_input_history", None)
45
- if user_input_history is not None:
46
- user_input_history.append(user_input)
47
- # Store input for main chat loop to consume as if just entered by the user
48
- self.shell_state.injected_input = user_input
49
- shared_console.print(
50
- "[green]Multi-line input will be sent as your next chat prompt.[/green]"
51
- )
1
+ from prompt_toolkit.shortcuts import prompt
2
+ from prompt_toolkit.application.current import get_app
3
+ from prompt_toolkit.document import Document
4
+ from prompt_toolkit.key_binding import KeyBindings
5
+ from janito.cli.console import shared_console
6
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
7
+
8
+
9
+ class MultiShellHandler(ShellCmdHandler):
10
+ help_text = "Prompt for multi-line input and display the result. Usage: /multi"
11
+
12
+ def run(self):
13
+ shared_console.print(
14
+ "[bold blue]Entering multi-line input mode. Press Esc+Enter or Ctrl+D to submit, Ctrl+C to cancel.[/bold blue]"
15
+ )
16
+ # Prompt for multi-line input
17
+ bindings = KeyBindings()
18
+ submitted = {"value": None}
19
+
20
+ @bindings.add("escape", "enter")
21
+ def _(event):
22
+ buffer = event.app.current_buffer
23
+ submitted["value"] = buffer.text
24
+ event.app.exit(result=buffer.text)
25
+
26
+ # Support Ctrl+D
27
+ @bindings.add("c-d")
28
+ def _(event):
29
+ buffer = event.app.current_buffer
30
+ submitted["value"] = buffer.text
31
+ event.app.exit(result=buffer.text)
32
+
33
+ try:
34
+ user_input = prompt(
35
+ "Multi-line > ",
36
+ multiline=True,
37
+ key_bindings=bindings,
38
+ )
39
+ except (EOFError, KeyboardInterrupt):
40
+ shared_console.print("[red]Multi-line input cancelled.[/red]")
41
+ return
42
+
43
+ # Save input to history if available
44
+ user_input_history = getattr(self.shell_state, "user_input_history", None)
45
+ if user_input_history is not None:
46
+ user_input_history.append(user_input)
47
+ # Store input for main chat loop to consume as if just entered by the user
48
+ self.shell_state.injected_input = user_input
49
+ shared_console.print(
50
+ "[green]Multi-line input will be sent as your next chat prompt.[/green]"
51
+ )
@@ -6,18 +6,29 @@ class ToolsShellHandler(ShellCmdHandler):
6
6
 
7
7
  def run(self):
8
8
  try:
9
+ # Initialize allow_execution before use
10
+ allow_execution = False
11
+ if hasattr(self, 'shell_state') and self.shell_state is not None:
12
+ allow_execution = getattr(self.shell_state, 'allow_execution', False)
13
+
9
14
  import janito.tools # Ensure all tools are registered
10
15
  registry = janito.tools.get_local_tools_adapter()
11
16
  tools = registry.list_tools()
12
17
  shared_console.print("Registered tools:" if tools else "No tools registered.")
18
+ # Get tool instances for annotation
19
+ tool_instances = {t.tool_name: t for t in registry.get_tools()}
13
20
  for tool in tools:
14
- shared_console.print(f"- {tool}")
21
+ inst = tool_instances.get(tool, None)
22
+ is_exec = getattr(inst, 'provides_execution', False) if inst else False
23
+ if is_exec and not allow_execution:
24
+ shared_console.print(f"- {tool} (disabled)")
25
+ else:
26
+ shared_console.print(f"- {tool}")
15
27
 
16
- # Check for execution tools
17
- # We assume shell_state.allow_execution is set if -x is used
18
- allow_execution = False
19
- if hasattr(self, 'shell_state') and self.shell_state is not None:
20
- allow_execution = getattr(self.shell_state, 'allow_execution', False)
28
+ if allow_execution:
29
+ shared_console.print("[green]Execution tools are ENABLED.[/green]")
30
+ else:
31
+ shared_console.print("[yellow]Execution tools are DISABLED. Use /exec on to enable them.[/yellow]")
21
32
 
22
33
  # Find all possible execution tools (by convention: provides_execution = True)
23
34
  exec_tools = []
@@ -1,62 +1,62 @@
1
- import os
2
- import json
3
- from datetime import datetime
4
- from typing import List, Any, Dict
5
-
6
-
7
- class UserInputHistory:
8
- """
9
- Handles loading, saving, and appending of user input history for the shell.
10
- Each day's history is stored in a line-delimited JSONL file (.jsonl) under .janito/input_history/.
11
- Each line is a JSON dict, e.g., {"input": ..., "ts": ...}
12
- """
13
-
14
- def __init__(self, history_dir=None):
15
- self.history_dir = history_dir or os.path.join(".janito", "input_history")
16
- os.makedirs(self.history_dir, exist_ok=True)
17
-
18
- def _get_today_file(self):
19
- today_str = datetime.now().strftime("%y%m%d")
20
- return os.path.join(self.history_dir, f"{today_str}.jsonl")
21
-
22
- def load(self) -> List[Dict[str, Any]]:
23
- """Load today's input history as a list of dicts."""
24
- history_file = self._get_today_file()
25
- history = []
26
- try:
27
- with open(history_file, "r", encoding="utf-8") as f:
28
- for line in f:
29
- line = line.strip()
30
- if not line:
31
- continue
32
- try:
33
- history.append(json.loads(line))
34
- except json.JSONDecodeError:
35
- continue
36
- except FileNotFoundError:
37
- pass
38
- return history
39
-
40
- def sanitize_surrogates(self, s):
41
- if isinstance(s, str):
42
- return s.encode("utf-8", errors="replace").decode("utf-8")
43
- return s
44
-
45
- def append(self, input_str: str):
46
- """Append a new input as a JSON dict to today's history file."""
47
- history_file = self._get_today_file()
48
- input_str = self.sanitize_surrogates(input_str)
49
- entry = {"input": input_str, "ts": datetime.now().isoformat()}
50
- with open(history_file, "a", encoding="utf-8") as f:
51
- f.write(json.dumps(entry, ensure_ascii=False) + "\n")
52
-
53
- def save(self, history_list: List[Any]):
54
- """Overwrite today's history file with the given list (for compatibility)."""
55
- history_file = self._get_today_file()
56
- with open(history_file, "w", encoding="utf-8") as f:
57
- for item in history_list:
58
- if isinstance(item, dict):
59
- f.write(json.dumps(item, ensure_ascii=False) + "\n")
60
- else:
61
- entry = {"input": str(item), "ts": datetime.now().isoformat()}
62
- f.write(json.dumps(entry, ensure_ascii=False) + "\n")
1
+ import os
2
+ import json
3
+ from datetime import datetime
4
+ from typing import List, Any, Dict
5
+
6
+
7
+ class UserInputHistory:
8
+ """
9
+ Handles loading, saving, and appending of user input history for the shell.
10
+ Each day's history is stored in a line-delimited JSONL file (.jsonl) under .janito/input_history/.
11
+ Each line is a JSON dict, e.g., {"input": ..., "ts": ...}
12
+ """
13
+
14
+ def __init__(self, history_dir=None):
15
+ self.history_dir = history_dir or os.path.join(".janito", "input_history")
16
+ os.makedirs(self.history_dir, exist_ok=True)
17
+
18
+ def _get_today_file(self):
19
+ today_str = datetime.now().strftime("%y%m%d")
20
+ return os.path.join(self.history_dir, f"{today_str}.jsonl")
21
+
22
+ def load(self) -> List[Dict[str, Any]]:
23
+ """Load today's input history as a list of dicts."""
24
+ history_file = self._get_today_file()
25
+ history = []
26
+ try:
27
+ with open(history_file, "r", encoding="utf-8") as f:
28
+ for line in f:
29
+ line = line.strip()
30
+ if not line:
31
+ continue
32
+ try:
33
+ history.append(json.loads(line))
34
+ except json.JSONDecodeError:
35
+ continue
36
+ except FileNotFoundError:
37
+ pass
38
+ return history
39
+
40
+ def sanitize_surrogates(self, s):
41
+ if isinstance(s, str):
42
+ return s.encode("utf-8", errors="replace").decode("utf-8")
43
+ return s
44
+
45
+ def append(self, input_str: str):
46
+ """Append a new input as a JSON dict to today's history file."""
47
+ history_file = self._get_today_file()
48
+ input_str = self.sanitize_surrogates(input_str)
49
+ entry = {"input": input_str, "ts": datetime.now().isoformat()}
50
+ with open(history_file, "a", encoding="utf-8") as f:
51
+ f.write(json.dumps(entry, ensure_ascii=False) + "\n")
52
+
53
+ def save(self, history_list: List[Any]):
54
+ """Overwrite today's history file with the given list (for compatibility)."""
55
+ history_file = self._get_today_file()
56
+ with open(history_file, "w", encoding="utf-8") as f:
57
+ for item in history_list:
58
+ if isinstance(item, dict):
59
+ f.write(json.dumps(item, ensure_ascii=False) + "\n")
60
+ else:
61
+ entry = {"input": str(item), "ts": datetime.now().isoformat()}
62
+ f.write(json.dumps(entry, ensure_ascii=False) + "\n")
@@ -95,6 +95,7 @@ def save_conversation(messages, prompts, usage_info=None, path=None):
95
95
 
96
96
  with open(path, "w", encoding="utf-8") as f:
97
97
  json.dump(data, f, indent=2, default=usage_serializer)
98
+ f.write("\n")
98
99
 
99
100
 
100
101
  def last_conversation_exists(path=".janito/last_conversation.json"):
@@ -24,6 +24,7 @@ def assemble_bindings_line(width):
24
24
  return (
25
25
  f" <key-label>CTRL-C</key-label>: Interrupt Request/Exit Shell | "
26
26
  f"<key-label>F1</key-label>: Restart conversation | "
27
+ f"<key-label>F2</key-label>: Exec | "
27
28
  f"<b>/help</b>: Help | "
28
29
  f"<key-label>F12</key-label>: Do It "
29
30
  )
@@ -1,35 +1,35 @@
1
- """
2
- CLI Command: List models for the specified/current provider
3
- """
4
-
5
- from janito.cli.cli_commands.model_utils import _print_models_table
6
- import sys
7
-
8
- _provider_instance = None
9
-
10
-
11
- def get_provider_instance():
12
- global _provider_instance
13
- if _provider_instance is None:
14
- _provider_instance = setup_provider()
15
- return _provider_instance
16
-
17
-
18
- def handle_list_models(args, provider_instance):
19
- provider_name = getattr(provider_instance, "name", None)
20
- if not provider_name:
21
- print(
22
- "Error: Provider must be specified with --provider or set as default before listing models."
23
- )
24
- sys.exit(1)
25
- try:
26
- models = list(provider_instance.get_model_info().values())
27
- if models and isinstance(models[0], dict):
28
- _print_models_table(models, provider_name)
29
- else:
30
- print(f"Supported models for provider '{provider_name}':")
31
- for m in models:
32
- print(f"- {m}")
33
- except Exception as e:
34
- print(f"Error listing models for provider '{provider_name}': {e}")
35
- sys.exit(0)
1
+ """
2
+ CLI Command: List models for the specified/current provider
3
+ """
4
+
5
+ from janito.cli.cli_commands.model_utils import _print_models_table
6
+ import sys
7
+
8
+ _provider_instance = None
9
+
10
+
11
+ def get_provider_instance():
12
+ global _provider_instance
13
+ if _provider_instance is None:
14
+ _provider_instance = setup_provider()
15
+ return _provider_instance
16
+
17
+
18
+ def handle_list_models(args, provider_instance):
19
+ provider_name = getattr(provider_instance, "name", None)
20
+ if not provider_name:
21
+ print(
22
+ "Error: Provider must be specified with --provider or set as default before listing models."
23
+ )
24
+ sys.exit(1)
25
+ try:
26
+ models = list(provider_instance.get_model_info().values())
27
+ if models and isinstance(models[0], dict):
28
+ _print_models_table(models, provider_name)
29
+ else:
30
+ print(f"Supported models for provider '{provider_name}':")
31
+ for m in models:
32
+ print(f"- {m}")
33
+ except Exception as e:
34
+ print(f"Error listing models for provider '{provider_name}': {e}")
35
+ sys.exit(0)
@@ -1,9 +1,9 @@
1
- """
2
- CLI Command: List supported LLM providers
3
- """
4
-
5
- from janito.provider_registry import list_providers
6
-
7
-
8
- def handle_list_providers(args=None):
9
- list_providers()
1
+ """
2
+ CLI Command: List supported LLM providers
3
+ """
4
+
5
+ from janito.provider_registry import list_providers
6
+
7
+
8
+ def handle_list_providers(args=None):
9
+ list_providers()