janito 2.4.0__py3-none-any.whl → 2.5.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 (30) hide show
  1. janito/agent/setup_agent.py +3 -3
  2. janito/agent/templates/profiles/system_prompt_template_assistant.txt.j2 +1 -0
  3. janito/cli/chat_mode/script_runner.py +153 -0
  4. janito/cli/chat_mode/session.py +56 -36
  5. janito/cli/chat_mode/session_profile_select.py +1 -1
  6. janito/cli/chat_mode/shell/commands/__init__.py +6 -2
  7. janito/cli/chat_mode/shell/commands/bang.py +36 -0
  8. janito/cli/chat_mode/shell/commands/conversation_restart.py +1 -24
  9. janito/cli/chat_mode/shell/commands/help.py +1 -1
  10. janito/cli/chat_mode/shell/commands/prompt.py +0 -8
  11. janito/cli/chat_mode/shell/input_history.py +1 -1
  12. janito/cli/chat_mode/shell/session/manager.py +0 -68
  13. janito/cli/core/runner.py +4 -4
  14. janito/cli/main_cli.py +12 -5
  15. janito/cli/prompt_setup.py +2 -2
  16. janito/cli/rich_terminal_reporter.py +21 -6
  17. janito/cli/single_shot_mode/handler.py +13 -7
  18. janito/drivers/driver_registry.py +0 -2
  19. janito/formatting_token.py +7 -6
  20. janito/provider_registry.py +1 -1
  21. janito/providers/__init__.py +0 -2
  22. janito/providers/provider_static_info.py +0 -3
  23. janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
  24. janito/tools/tool_base.py +0 -10
  25. {janito-2.4.0.dist-info → janito-2.5.0.dist-info}/METADATA +2 -15
  26. {janito-2.4.0.dist-info → janito-2.5.0.dist-info}/RECORD +30 -27
  27. {janito-2.4.0.dist-info → janito-2.5.0.dist-info}/WHEEL +0 -0
  28. {janito-2.4.0.dist-info → janito-2.5.0.dist-info}/entry_points.txt +0 -0
  29. {janito-2.4.0.dist-info → janito-2.5.0.dist-info}/licenses/LICENSE +0 -0
  30. {janito-2.4.0.dist-info → janito-2.5.0.dist-info}/top_level.txt +0 -0
@@ -20,7 +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
  allowed_permissions=None,
25
25
  profile=None,
26
26
  profile_system_prompt=None,
@@ -170,7 +170,7 @@ def create_configured_agent(
170
170
  verbose_agent=False,
171
171
  templates_dir=None,
172
172
  zero_mode=False,
173
- exec_enabled=False,
173
+
174
174
  allowed_permissions=None,
175
175
  profile=None,
176
176
  profile_system_prompt=None,
@@ -212,7 +212,7 @@ def create_configured_agent(
212
212
  output_queue=output_queue,
213
213
  verbose_tools=verbose_tools,
214
214
  verbose_agent=verbose_agent,
215
- exec_enabled=exec_enabled,
215
+
216
216
  allowed_permissions=allowed_permissions,
217
217
  profile=profile,
218
218
  profile_system_prompt=profile_system_prompt,
@@ -0,0 +1 @@
1
+ You are a helpful assistant.
@@ -0,0 +1,153 @@
1
+ """
2
+ Scripted runner for Janito chat mode.
3
+
4
+ This utility allows you to execute the interactive ``ChatSession`` logic with
5
+ an *in-memory* list of user inputs, making it much easier to write automated
6
+ unit or integration tests for the chat CLI without resorting to fragile
7
+ pseudo-terminal tricks.
8
+
9
+ The runner monkey-patches the private ``_handle_input`` method so that the
10
+ chat loop thinks it is receiving interactive input, while in reality the
11
+ values come from the provided list. All output is captured through a
12
+ ``rich.console.Console`` instance configured with ``record=True`` so the test
13
+ can later inspect the rendered text.
14
+
15
+ Typical usage
16
+ -------------
17
+ >>> from janito.cli.chat_mode.script_runner import ChatScriptRunner
18
+ >>> inputs = ["Hello!", "/exit"]
19
+ >>> runner = ChatScriptRunner(inputs)
20
+ >>> transcript = runner.run()
21
+ >>> assert "Hello!" in transcript
22
+
23
+ The ``ChatScriptRunner`` purposefully replaces the internal call to the agent
24
+ with a real agent call by default. If you want to use a stub, you must modify the runner implementation.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ from types import MethodType
29
+ from typing import List, Optional
30
+
31
+ from rich.console import Console
32
+
33
+ from janito.cli.chat_mode.session import ChatSession
34
+ from janito.provider_registry import ProviderRegistry
35
+ from janito.llm.driver_config import LLMDriverConfig
36
+
37
+ __all__ = ["ChatScriptRunner"]
38
+
39
+
40
+ auth_warning = (
41
+ "[yellow]ChatScriptRunner is executing in stubbed-agent mode; no calls to an "
42
+ "external LLM provider will be made.[/yellow]"
43
+ )
44
+
45
+
46
+
47
+ class ChatScriptRunner:
48
+ """Run a **ChatSession** non-interactively using a predefined set of inputs."""
49
+
50
+ def __init__(
51
+ self,
52
+ inputs: List[str],
53
+ *,
54
+ console: Optional[Console] = None,
55
+ provider: str = "openai",
56
+ model: str = "gpt-4.1",
57
+ use_real_agent: bool = True,
58
+ **chat_session_kwargs,
59
+ ) -> None:
60
+ """Create the runner.
61
+
62
+ Parameters
63
+ ----------
64
+ inputs:
65
+ Ordered list of strings that will be fed to the chat loop.
66
+ console:
67
+ Optional *rich* console. If *None*, a new one is created with
68
+ *record=True* so that output can later be retrieved through
69
+ :py:meth:`rich.console.Console.export_text`.
70
+ use_real_agent:
71
+ chat_session_kwargs:
72
+ Extra keyword arguments forwarded to :class:`janito.cli.chat_mode.session.ChatSession`.
73
+ """
74
+ self._input_queue = list(inputs)
75
+ self.console = console or Console(record=True)
76
+ self.provider = provider
77
+ self.model = model
78
+ self.use_real_agent = use_real_agent
79
+ # Ensure we always pass a non-interactive *args* namespace so that the
80
+ # normal ChatSession logic skips the Questionary profile prompt which
81
+ # is incompatible with headless test runs.
82
+ if "args" not in chat_session_kwargs or chat_session_kwargs["args"] is None:
83
+ from types import SimpleNamespace
84
+ chat_session_kwargs["args"] = SimpleNamespace(
85
+ profile="developer",
86
+ provider=self.provider,
87
+ model=self.model,
88
+ )
89
+
90
+ # Create the ChatSession instance **after** we monkey-patch methods that rely on
91
+ # prompt-toolkit so that no attempt is made to instantiate terminal UIs in
92
+ # a headless environment like CI.
93
+
94
+ # 1) Patch *ChatSession._create_prompt_session* to do nothing – the
95
+ # interactive session object is irrelevant for scripted runs.
96
+ from types import MethodType as _MT
97
+ if "_original_create_prompt_session" not in ChatSession.__dict__:
98
+ ChatSession._original_create_prompt_session = ChatSession._create_prompt_session # type: ignore[attr-defined]
99
+ ChatSession._create_prompt_session = _MT(lambda _self: None, ChatSession) # type: ignore[method-assign]
100
+
101
+ # Resolve provider instance now so that ChatSession uses a ready agent
102
+ provider_instance = ProviderRegistry().get_instance(self.provider)
103
+ if provider_instance is None:
104
+ raise RuntimeError(f"Provider '{self.provider}' is not available on this system.")
105
+ driver_config = LLMDriverConfig(model=self.model)
106
+ chat_session_kwargs.setdefault("provider_instance", provider_instance)
107
+ chat_session_kwargs.setdefault("llm_driver_config", driver_config)
108
+
109
+ self.chat_session = ChatSession(console=self.console, **chat_session_kwargs)
110
+
111
+
112
+ # Monkey-patch the *ChatSession._handle_input* method so that it pops
113
+ # from our in-memory queue instead of reading from stdin.
114
+ def _script_handle_input(this: ChatSession, _prompt_session_unused): # noqa: D401
115
+ if not self._input_queue:
116
+ # Signal normal shutdown
117
+ this._handle_exit()
118
+ return None
119
+ return self._input_queue.pop(0)
120
+
121
+ # Bind the method to the *chat_session* instance.
122
+ self.chat_session._handle_input = MethodType( # type: ignore[assignment]
123
+ _script_handle_input, self.chat_session
124
+ )
125
+
126
+ # ---------------------------------------------------------------------
127
+ # Public helpers
128
+ # ---------------------------------------------------------------------
129
+ def run(self) -> str:
130
+ """Execute the chat session and return the captured transcript."""
131
+ self.chat_session.run()
132
+ return self.console.export_text()
133
+
134
+ # ---------------------------------------------------------------------
135
+ # Helpers to introspect results
136
+ # ---------------------------------------------------------------------
137
+ def get_history(self):
138
+ """Return the structured conversation history produced by the LLM."""
139
+ try:
140
+ return self.chat_session.shell_state.conversation_history.get_history()
141
+ except Exception:
142
+ return []
143
+
144
+ def get_last_response(self) -> str | None:
145
+ """Return the *assistant* content of the last message, if any."""
146
+ history = self.get_history()
147
+ for message in reversed(history):
148
+ if message.get("role") == "assistant":
149
+ return message.get("content")
150
+ return None
151
+
152
+ # Convenience alias so tests can simply call *runner()*
153
+ __call__ = run
@@ -54,7 +54,7 @@ class ChatSession:
54
54
  args=None,
55
55
  verbose_tools=False,
56
56
  verbose_agent=False,
57
- exec_enabled=False,
57
+
58
58
  allowed_permissions=None,
59
59
  ):
60
60
 
@@ -76,12 +76,9 @@ class ChatSession:
76
76
  from janito.cli.chat_mode.session_profile_select import select_profile
77
77
 
78
78
  result = select_profile()
79
- if (
80
- isinstance(result, dict)
81
- and result.get("profile") is None
82
- and result.get("profile_system_prompt")
83
- ):
84
- profile_system_prompt = result["profile_system_prompt"]
79
+ if isinstance(result, dict):
80
+ profile = result.get("profile")
81
+ profile_system_prompt = result.get("profile_system_prompt")
85
82
  elif isinstance(result, str) and result.startswith("role:"):
86
83
  role = result[len("role:") :].strip()
87
84
  profile = "developer"
@@ -105,7 +102,7 @@ class ChatSession:
105
102
  role=role,
106
103
  verbose_tools=verbose_tools,
107
104
  verbose_agent=verbose_agent,
108
- exec_enabled=exec_enabled,
105
+
109
106
  allowed_permissions=allowed_permissions,
110
107
  profile=profile,
111
108
  profile_system_prompt=profile_system_prompt,
@@ -163,6 +160,14 @@ class ChatSession:
163
160
  f"[bold green]Janito Chat Mode v{__version__}[/bold green]"
164
161
  )
165
162
  self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
163
+ import os
164
+ cwd = os.getcwd()
165
+ home = os.path.expanduser('~')
166
+ if cwd.startswith(home):
167
+ cwd_display = '~' + cwd[len(home):]
168
+ else:
169
+ cwd_display = cwd
170
+ self.console.print(f"[green]Working Dir:[/green] {cwd_display}")
166
171
 
167
172
  # Inform user if no privileges are enabled
168
173
  from janito.cli.chat_mode.shell.commands._priv_check import user_has_any_privileges
@@ -185,40 +190,55 @@ class ChatSession:
185
190
  continue
186
191
  if self._handle_exit_conditions(cmd_input):
187
192
  break
188
- if cmd_input.startswith("/"):
189
- handle_command(cmd_input, shell_state=self.shell_state)
193
+ if self._handle_command_input(cmd_input):
190
194
  continue
191
195
  self.user_input_history.append(cmd_input)
192
- try:
193
- final_event = (
194
- self._prompt_handler.agent.last_event
195
- if hasattr(self._prompt_handler.agent, "last_event")
196
+ self._process_prompt(cmd_input)
197
+
198
+ def _handle_command_input(self, cmd_input):
199
+ if cmd_input.startswith("/"):
200
+ handle_command(cmd_input, shell_state=self.shell_state)
201
+ return True
202
+ if cmd_input.startswith("!"):
203
+ # Pass everything after ! to the bang handler
204
+ handle_command(f"! {cmd_input[1:]}", shell_state=self.shell_state)
205
+ return True
206
+ return False
207
+
208
+ def _process_prompt(self, cmd_input):
209
+ try:
210
+ import time
211
+ final_event = (
212
+ self._prompt_handler.agent.last_event
213
+ if hasattr(self._prompt_handler.agent, "last_event")
214
+ else None
215
+ )
216
+ start_time = time.time()
217
+ self._prompt_handler.run_prompt(cmd_input)
218
+ end_time = time.time()
219
+ elapsed = end_time - start_time
220
+ self.msg_count += 1
221
+ # After prompt, print the stat line using the shared core function
222
+ from janito.formatting_token import print_token_message_summary
223
+
224
+ usage = self.performance_collector.get_last_request_usage()
225
+ print_token_message_summary(self.console, self.msg_count, usage, elapsed=elapsed)
226
+ # Print exit reason if present in the final event
227
+ if final_event and hasattr(final_event, "metadata"):
228
+ exit_reason = (
229
+ final_event.metadata.get("exit_reason")
230
+ if hasattr(final_event, "metadata")
196
231
  else None
197
232
  )
198
- self._prompt_handler.run_prompt(cmd_input)
199
- self.msg_count += 1
200
- # After prompt, print the stat line using the shared core function
201
- from janito.formatting_token import print_token_message_summary
202
-
203
- usage = self.performance_collector.get_last_request_usage()
204
- print_token_message_summary(self.console, self.msg_count, usage)
205
- # Print exit reason if present in the final event
206
- if final_event and hasattr(final_event, "metadata"):
207
- exit_reason = (
208
- final_event.metadata.get("exit_reason")
209
- if hasattr(final_event, "metadata")
210
- else None
233
+ if exit_reason:
234
+ self.console.print(
235
+ f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
211
236
  )
212
- if exit_reason:
213
- self.console.print(
214
- f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
215
- )
216
-
217
- except Exception as exc:
218
- self.console.print(f"[red]Exception in agent: {exc}[/red]")
219
- import traceback
220
237
 
221
- self.console.print(traceback.format_exc())
238
+ except Exception as exc:
239
+ self.console.print(f"[red]Exception in agent: {exc}[/red]")
240
+ import traceback
241
+ self.console.print(traceback.format_exc())
222
242
 
223
243
  def _create_prompt_session(self):
224
244
  return PromptSession(
@@ -22,7 +22,7 @@ def select_profile():
22
22
  style=custom_style
23
23
  ).ask()
24
24
  if answer == "helpful assistant":
25
- return {"profile": None, "profile_system_prompt": "You are an helpful assistant"}
25
+ return {"profile": "assistant", "profile_system_prompt": None}
26
26
  if answer == "using role...":
27
27
  role_name = questionary.text("Enter the role name:").ask()
28
28
  return f"role:{role_name}"
@@ -2,7 +2,7 @@ from .base import ShellCmdHandler
2
2
  from .history_view import ViewShellHandler
3
3
  from .lang import LangShellHandler
4
4
  from .livelogs import LivelogsShellHandler
5
- from .prompt import PromptShellHandler, RoleShellHandler, ProfileShellHandler
5
+ from .prompt import PromptShellHandler, RoleShellHandler
6
6
  from .multi import MultiShellHandler
7
7
  from .model import ModelShellHandler
8
8
  from .role import RoleCommandShellHandler
@@ -12,6 +12,10 @@ from .help import HelpShellHandler
12
12
  from janito.cli.console import shared_console
13
13
 
14
14
  COMMAND_HANDLERS = {
15
+ # Bang handler for shell commands
16
+ "!": __import__(
17
+ "janito.cli.chat_mode.shell.commands.bang", fromlist=["BangShellHandler"]
18
+ ).BangShellHandler,
15
19
  "/execute": __import__(
16
20
  "janito.cli.chat_mode.shell.commands.execute", fromlist=["ExecuteShellHandler"]
17
21
  ).ExecuteShellHandler,
@@ -34,7 +38,7 @@ COMMAND_HANDLERS = {
34
38
  "/livelogs": LivelogsShellHandler,
35
39
  "/prompt": PromptShellHandler,
36
40
  "/role": RoleShellHandler,
37
- "/profile": ProfileShellHandler,
41
+
38
42
  "/history": HistoryShellHandler,
39
43
 
40
44
  "/tools": ToolsShellHandler,
@@ -0,0 +1,36 @@
1
+ from janito.cli.console import shared_console
2
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
3
+ from janito.platform_discovery import PlatformDiscovery
4
+ import subprocess
5
+ import sys
6
+
7
+ class BangShellHandler(ShellCmdHandler):
8
+ help_text = "!<cmd>: Run a shell command in the underlying shell (PowerShell or Bash). Usage: !ls -al or !Get-Process. Use ! with no command to launch an interactive shell."
9
+
10
+ def run(self):
11
+ if not self.shell_state:
12
+ shared_console.print("[red]Shell state unavailable.[/red]")
13
+ return
14
+ cmd = (self.after_cmd_line or "").strip()
15
+ if not cmd:
16
+ pd = PlatformDiscovery()
17
+ if pd.is_windows():
18
+ shared_console.print("[yellow]Launching interactive PowerShell. Type 'exit' to return.[/yellow]")
19
+ subprocess.run(["powershell.exe"], check=False)
20
+ else:
21
+ shared_console.print("[yellow]Launching interactive Bash shell. Type 'exit' to return.[/yellow]")
22
+ subprocess.run(["bash"], check=False)
23
+ return
24
+ pd = PlatformDiscovery()
25
+ if pd.is_windows():
26
+ shared_console.print(f"[cyan]Running in PowerShell:[/cyan] {cmd}")
27
+ completed = subprocess.run(["powershell.exe", "-Command", cmd], capture_output=True, text=True)
28
+ else:
29
+ shared_console.print(f"[cyan]Running in Bash:[/cyan] {cmd}")
30
+ completed = subprocess.run(cmd, shell=True, capture_output=True, text=True)
31
+ output = completed.stdout
32
+ error = completed.stderr
33
+ if output:
34
+ shared_console.print(output)
35
+ if error:
36
+ shared_console.print(f"[red]{error}[/red]")
@@ -5,31 +5,8 @@ from janito.cli.console import shared_console
5
5
 
6
6
 
7
7
  def handle_restart(shell_state=None):
8
- from janito.cli.chat_mode.shell.session.manager import (
9
- load_last_conversation,
10
- save_conversation,
11
- )
12
-
13
8
  reset_session_id()
14
- save_path = os.path.join(".janito", "last_conversation.json")
15
-
16
- # --- Append end-of-conversation message to old history if it exists and is non-trivial ---
17
- if os.path.exists(save_path):
18
- try:
19
- messages, prompts, usage = load_last_conversation(save_path)
20
- if messages and (
21
- len(messages) > 1
22
- or (len(messages) == 1 and messages[0].get("role") != "system")
23
- ):
24
- messages.append(
25
- {"role": "system", "content": "[Session ended by user]"}
26
- )
27
- # Save to permanent chat history (let save_conversation pick session file)
28
- save_conversation(messages, prompts, usage)
29
- except Exception as e:
30
- shared_console.print(
31
- f"[bold red]Failed to update previous conversation history:[/bold red] {e}"
32
- )
9
+ # Conversation history is no longer saved or loaded.
33
10
 
34
11
  # Clear the terminal screen
35
12
  shared_console.clear()
@@ -1,6 +1,6 @@
1
1
  from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
2
2
  from janito.cli.console import shared_console
3
-
3
+ import os
4
4
 
5
5
  class HelpShellHandler(ShellCmdHandler):
6
6
  help_text = "Show this help message"
@@ -54,11 +54,3 @@ class RoleShellHandler(ShellCmdHandler):
54
54
  )
55
55
 
56
56
 
57
- class ProfileShellHandler(ShellCmdHandler):
58
- help_text = (
59
- "Show the current and available Agent Profile (only 'base' is supported)"
60
- )
61
-
62
- def run(self):
63
- shared_console.print("[bold green]Current profile:[/bold green] base")
64
- shared_console.print("[bold yellow]Available profiles:[/bold yellow]\n- base")
@@ -12,7 +12,7 @@ class UserInputHistory:
12
12
  """
13
13
 
14
14
  def __init__(self, history_dir=None):
15
- self.history_dir = history_dir or os.path.join(".janito", "input_history")
15
+ self.history_dir = history_dir or os.path.join(os.path.expanduser("~"), ".janito", "input_history")
16
16
  os.makedirs(self.history_dir, exist_ok=True)
17
17
 
18
18
  def _get_today_file(self):
@@ -40,71 +40,3 @@ def set_role(role):
40
40
  rc.save()
41
41
 
42
42
 
43
- def load_last_summary(path=".janito/last_conversation.json"):
44
- if not os.path.exists(path):
45
- return None
46
- with open(path, "r", encoding="utf-8") as f:
47
- data = json.load(f)
48
- return data
49
-
50
-
51
- def load_last_conversation(path=".janito/last_conversation.json"):
52
- if not os.path.exists(path):
53
- return [], [], None
54
- with open(path, "r", encoding="utf-8") as f:
55
- data = json.load(f)
56
- messages = data.get("messages", [])
57
- prompts = data.get("prompts", [])
58
- usage = data.get("last_usage_info")
59
- return messages, prompts, usage
60
-
61
-
62
- def load_conversation_by_session_id(session_id):
63
- path = os.path.join(".janito", "chat_history", f"{session_id}.json")
64
- if not os.path.exists(path):
65
- raise FileNotFoundError(f"Session file not found: {path}")
66
- with open(path, "r", encoding="utf-8") as f:
67
- data = json.load(f)
68
- messages = data.get("messages", [])
69
- prompts = data.get("prompts", [])
70
- usage = data.get("last_usage_info")
71
- return messages, prompts, usage
72
-
73
-
74
- def save_conversation(messages, prompts, usage_info=None, path=None):
75
- # Do not save if only one message and it is a system message (noop session)
76
- if (
77
- isinstance(messages, list)
78
- and len(messages) == 1
79
- and messages[0].get("role") == "system"
80
- ):
81
- return
82
-
83
- if path is None:
84
- session_id = get_session_id()
85
- path = os.path.join(".janito", "chat_history", f"{session_id}.json")
86
- os.makedirs(os.path.dirname(path), exist_ok=True)
87
- data = {"messages": messages, "prompts": prompts, "last_usage_info": usage_info}
88
-
89
- def usage_serializer(obj):
90
- if hasattr(obj, "to_dict"):
91
- return obj.to_dict()
92
- if hasattr(obj, "__dict"):
93
- return obj.__dict__
94
- return str(obj)
95
-
96
- with open(path, "w", encoding="utf-8") as f:
97
- json.dump(data, f, indent=2, default=usage_serializer)
98
- f.write("\n")
99
-
100
-
101
- def last_conversation_exists(path=".janito/last_conversation.json"):
102
- if not os.path.exists(path):
103
- return False
104
- try:
105
- with open(path, "r", encoding="utf-8") as f:
106
- data = json.load(f)
107
- messages = data.get("messages", [])
108
- return bool(messages)
109
- except Exception:
110
- return False
janito/cli/core/runner.py CHANGED
@@ -96,7 +96,7 @@ def prepare_llm_driver_config(args, modifiers):
96
96
  return provider, llm_driver_config, agent_role
97
97
 
98
98
 
99
- def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False, exec_enabled=False):
99
+ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False, ):
100
100
  """
101
101
  Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
102
102
  """
@@ -108,7 +108,7 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
108
108
  from janito.tools.tool_base import ToolPermissions
109
109
  read = getattr(args, "read", False)
110
110
  write = getattr(args, "write", False)
111
- execute = exec_enabled
111
+ execute = getattr(args, "exec", False)
112
112
  from janito.tools.permissions import set_global_allowed_permissions
113
113
  from janito.tools.tool_base import ToolPermissions
114
114
  allowed_permissions = ToolPermissions(read=read, write=write, execute=execute)
@@ -145,7 +145,7 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
145
145
  handler = SingleShotPromptHandler(
146
146
  args, provider_instance, llm_driver_config,
147
147
  role=agent_role,
148
- exec_enabled=exec_enabled,
148
+
149
149
  allowed_permissions=allowed_permissions,
150
150
  )
151
151
  handler.handle()
@@ -162,7 +162,7 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
162
162
  args=args,
163
163
  verbose_tools=verbose_tools,
164
164
  verbose_agent=getattr(args, "verbose_agent", False),
165
- exec_enabled=exec_enabled,
165
+
166
166
  allowed_permissions=allowed_permissions,
167
167
  )
168
168
  session.run()
janito/cli/main_cli.py CHANGED
@@ -200,6 +200,17 @@ class JanitoCLI:
200
200
  self._define_args()
201
201
  self.args = self.parser.parse_args()
202
202
  self._set_all_arg_defaults()
203
+ # Support reading prompt from stdin if no user_prompt is given
204
+ import sys
205
+ if not sys.stdin.isatty():
206
+ stdin_input = sys.stdin.read().strip()
207
+ if stdin_input:
208
+ if self.args.user_prompt and len(self.args.user_prompt) > 0:
209
+ # Prefix the prompt argument to the stdin input
210
+ combined = ' '.join(self.args.user_prompt) + ' ' + stdin_input
211
+ self.args.user_prompt = [combined]
212
+ else:
213
+ self.args.user_prompt = [stdin_input]
203
214
  from janito.cli.rich_terminal_reporter import RichTerminalReporter
204
215
 
205
216
  self.rich_reporter = RichTerminalReporter(raw_mode=self.args.raw)
@@ -235,9 +246,6 @@ class JanitoCLI:
235
246
  if getattr(self.args, k, None) is not None
236
247
  }
237
248
 
238
- def exec_enabled(self):
239
- return getattr(self.args, "exec", False)
240
-
241
249
  def classify(self):
242
250
  if any(getattr(self.args, k, None) for k in SETTER_KEYS):
243
251
  return RunMode.SET
@@ -291,8 +299,7 @@ class JanitoCLI:
291
299
  llm_driver_config,
292
300
  agent_role,
293
301
  verbose_tools=self.args.verbose_tools,
294
- exec_enabled=self.exec_enabled(),
295
- )
302
+ )
296
303
  elif run_mode == RunMode.GET:
297
304
  handle_getter(self.args)
298
305
 
@@ -21,7 +21,7 @@ def setup_agent_and_prompt_handler(
21
21
  role: Optional[str] = None,
22
22
  verbose_tools: bool = False,
23
23
  verbose_agent: bool = False,
24
- exec_enabled: bool = False,
24
+
25
25
  allowed_permissions: Optional[list[str]] = None,
26
26
  profile: Optional[str] = None,
27
27
  profile_system_prompt: Optional[str] = None,
@@ -40,7 +40,7 @@ def setup_agent_and_prompt_handler(
40
40
  role=role,
41
41
  verbose_tools=verbose_tools,
42
42
  verbose_agent=verbose_agent,
43
- exec_enabled=exec_enabled,
43
+
44
44
  allowed_permissions=allowed_permissions,
45
45
  profile=profile,
46
46
  profile_system_prompt=profile_system_prompt,
@@ -10,6 +10,8 @@ from janito.event_bus.bus import event_bus
10
10
  from janito.llm import message_parts
11
11
 
12
12
 
13
+ import sys
14
+
13
15
  class RichTerminalReporter(EventHandlerBase):
14
16
  """
15
17
  Handles UI rendering for janito events using Rich.
@@ -63,8 +65,15 @@ class RichTerminalReporter(EventHandlerBase):
63
65
  self.console.print(Markdown(part.content))
64
66
  self.console.file.flush()
65
67
 
68
+ def delete_current_line(self):
69
+ """
70
+ Clears the entire current line in the terminal and returns the cursor to column 1.
71
+ """
72
+ sys.stdout.write('\033[2K\r')
73
+ sys.stdout.flush()
74
+
66
75
  def on_RequestFinished(self, event):
67
- self.console.print("") # Print end of line after waiting message
76
+ self.delete_current_line()
68
77
  self._waiting_printed = False
69
78
  response = getattr(event, "response", None)
70
79
  error = getattr(event, "error", None)
@@ -99,14 +108,14 @@ class RichTerminalReporter(EventHandlerBase):
99
108
  if not msg or not subtype:
100
109
  return
101
110
  if subtype == ReportSubtype.ACTION_INFO:
102
- if getattr(event, "action", None) in (
111
+ # Use orange for modification actions, cyan otherwise
112
+ modification_actions = (
103
113
  getattr(ReportAction, "UPDATE", None),
104
114
  getattr(ReportAction, "WRITE", None),
105
115
  getattr(ReportAction, "DELETE", None),
106
- ):
107
- self.console.print(f"[magenta]{msg}[/magenta]", end="")
108
- else:
109
- self.console.print(msg, end="")
116
+ )
117
+ style = "orange1" if getattr(event, "action", None) in modification_actions else "cyan"
118
+ self.console.print(Text(msg, style=style), end="")
110
119
  self.console.file.flush()
111
120
  elif subtype in (
112
121
  ReportSubtype.SUCCESS,
@@ -115,6 +124,12 @@ class RichTerminalReporter(EventHandlerBase):
115
124
  ):
116
125
  self.console.print(msg)
117
126
  self.console.file.flush()
127
+ elif subtype == ReportSubtype.STDOUT:
128
+ self.console.print(Text(msg, style="on dark_green"))
129
+ self.console.file.flush()
130
+ elif subtype == ReportSubtype.STDERR:
131
+ self.console.print(Text(msg, style="on red"))
132
+ self.console.file.flush()
118
133
  else:
119
134
  self.console.print(msg)
120
135
  self.console.file.flush()
@@ -10,13 +10,12 @@ from janito.cli.console import shared_console
10
10
 
11
11
 
12
12
  class PromptHandler:
13
- def __init__(self, args, provider_instance, llm_driver_config, role=None, exec_enabled=False, allowed_permissions=None):
13
+ def __init__(self, args, provider_instance, llm_driver_config, role=None, allowed_permissions=None):
14
14
  self.args = args
15
15
  self.provider_instance = provider_instance
16
16
  self.llm_driver_config = llm_driver_config
17
17
  self.role = role
18
- self.exec_enabled = exec_enabled
19
- # Instantiate agent together with prompt handler using the shared helper
18
+ # Instantiate agent together with prompt handler using the shared helper
20
19
  self.agent, self.generic_handler = setup_agent_and_prompt_handler(
21
20
  args=args,
22
21
  provider_instance=provider_instance,
@@ -24,7 +23,7 @@ class PromptHandler:
24
23
  role=role,
25
24
  verbose_tools=getattr(args, "verbose_tools", False),
26
25
  verbose_agent=getattr(args, "verbose_agent", False),
27
- exec_enabled=exec_enabled,
26
+
28
27
  allowed_permissions=allowed_permissions,
29
28
  profile=getattr(args, "profile", None),
30
29
  )
@@ -42,13 +41,18 @@ class PromptHandler:
42
41
  shared_console.print(
43
42
  "[yellow]Warning: Some characters in your input were not valid UTF-8 and have been replaced.[/yellow]"
44
43
  )
44
+ import time
45
45
  try:
46
+ start_time = time.time()
46
47
  self.generic_handler.handle_prompt(
47
48
  sanitized,
48
49
  args=self.args,
49
50
  print_header=True,
50
51
  raw=getattr(self.args, "raw", False),
51
52
  )
53
+ end_time = time.time()
54
+ elapsed = end_time - start_time
55
+ self._post_prompt_actions(elapsed=elapsed)
52
56
  if hasattr(self.args, "verbose_agent") and self.args.verbose_agent:
53
57
  print("[debug] handle_prompt() completed without exception.")
54
58
  except Exception as e:
@@ -56,14 +60,16 @@ class PromptHandler:
56
60
  f"[error] Exception occurred in handle_prompt: {type(e).__name__}: {e}"
57
61
  )
58
62
  traceback.print_exc()
59
- self._post_prompt_actions()
60
63
 
61
- def _post_prompt_actions(self):
64
+ def _post_prompt_actions(self, elapsed=None):
62
65
  # Align with chat mode: only print token usage summary
66
+ import sys
63
67
  from janito.formatting_token import print_token_message_summary
64
68
  from janito.perf_singleton import performance_collector
65
69
  usage = performance_collector.get_last_request_usage()
66
- print_token_message_summary(shared_console, msg_count=1, usage=usage)
70
+ # If running in stdin mode, do not print token usage
71
+ if sys.stdin.isatty():
72
+ print_token_message_summary(shared_console, msg_count=1, usage=usage, elapsed=elapsed)
67
73
  self._cleanup_driver_and_console()
68
74
 
69
75
 
@@ -8,13 +8,11 @@ from typing import Dict, Type
8
8
  # --- Import driver classes ---
9
9
  from janito.drivers.anthropic.driver import AnthropicModelDriver
10
10
  from janito.drivers.azure_openai.driver import AzureOpenAIModelDriver
11
- from janito.drivers.mistralai.driver import MistralAIModelDriver
12
11
  from janito.drivers.openai.driver import OpenAIModelDriver
13
12
 
14
13
  _DRIVER_REGISTRY: Dict[str, Type] = {
15
14
  "AnthropicModelDriver": AnthropicModelDriver,
16
15
  "AzureOpenAIModelDriver": AzureOpenAIModelDriver,
17
- "MistralAIModelDriver": MistralAIModelDriver,
18
16
  "OpenAIModelDriver": OpenAIModelDriver,
19
17
  }
20
18
 
@@ -25,9 +25,9 @@ def format_tokens(n, tag=None, use_rich=False):
25
25
  return val
26
26
 
27
27
 
28
- def format_token_message_summary(msg_count, usage, width=96, use_rich=False):
28
+ def format_token_message_summary(msg_count, usage, width=96, use_rich=False, elapsed=None):
29
29
  """
30
- Returns a string (rich or pt markup) summarizing message count and last token usage.
30
+ Returns a string (rich or pt markup) summarizing message count, last token usage, and elapsed time.
31
31
  """
32
32
  left = f" Messages: {'[' if use_rich else '<'}msg_count{']' if use_rich else '>'}{msg_count}{'[/msg_count]' if use_rich else '</msg_count>'}"
33
33
  tokens_part = ""
@@ -40,15 +40,16 @@ def format_token_message_summary(msg_count, usage, width=96, use_rich=False):
40
40
  f"Completion: {format_tokens(completion_tokens, 'tokens_out', use_rich)}, "
41
41
  f"Total: {format_tokens(total_tokens, 'tokens_total', use_rich)}"
42
42
  )
43
- return f"{left}{tokens_part}"
43
+ elapsed_part = f" | Elapsed: [cyan]{elapsed:.2f}s[/cyan]" if elapsed is not None else ""
44
+ return f"{left}{tokens_part}{elapsed_part}"
44
45
 
45
46
 
46
- def print_token_message_summary(console, msg_count=None, usage=None, width=96):
47
- """Prints the summary using rich markup, using defaults from perf_singleton if not given."""
47
+ def print_token_message_summary(console, msg_count=None, usage=None, width=96, elapsed=None):
48
+ """Prints the summary using rich markup, using defaults from perf_singleton if not given. Optionally includes elapsed time."""
48
49
  if usage is None:
49
50
  usage = performance_collector.get_last_request_usage()
50
51
  if msg_count is None:
51
52
  msg_count = performance_collector.get_total_turns() or 0
52
- line = format_token_message_summary(msg_count, usage, width, use_rich=True)
53
+ line = format_token_message_summary(msg_count, usage, width, use_rich=True, elapsed=elapsed)
53
54
  if line.strip():
54
55
  console.print(Rule(line))
@@ -130,7 +130,7 @@ class ProviderRegistry:
130
130
  "openai": "janito.providers.openai.model_info",
131
131
  "azure_openai": "janito.providers.azure_openai.model_info",
132
132
  "google": "janito.providers.google.model_info",
133
- "mistralai": "janito.providers.mistralai.model_info",
133
+
134
134
  "deepseek": "janito.providers.deepseek.model_info",
135
135
  }
136
136
  if provider_name in provider_to_specs:
@@ -1,8 +1,6 @@
1
1
  # Ensure all providers are registered by importing their modules
2
2
  import janito.providers.openai.provider
3
3
  import janito.providers.google.provider
4
- import janito.providers.mistralai.provider
5
- import janito.providers.google.provider
6
4
  import janito.providers.azure_openai.provider
7
5
  import janito.providers.anthropic.provider
8
6
  import janito.providers.deepseek.provider
@@ -8,9 +8,6 @@ STATIC_PROVIDER_METADATA = {
8
8
  "azure_openai": {
9
9
  "maintainer": "João Pinto <lamego.pinto@gmail.com>",
10
10
  },
11
- "mistralai": {
12
- "maintainer": "Needs maintainer",
13
- },
14
11
  "anthropic": {
15
12
  "maintainer": "Needs maintainer",
16
13
  },
@@ -96,7 +96,7 @@ class ValidateFileSyntaxTool(ToolBase):
96
96
  )
97
97
  result = validate_file_syntax(
98
98
  file_path,
99
- report_info=self.report_info,
99
+
100
100
  report_warning=self.report_warning,
101
101
  report_success=self.report_success,
102
102
  )
janito/tools/tool_base.py CHANGED
@@ -48,16 +48,6 @@ class ToolBase:
48
48
  )
49
49
  )
50
50
 
51
- def report_info(self, message: str, context: dict = None):
52
- self._event_bus.publish(
53
- ReportEvent(
54
- subtype=ReportSubtype.ACTION_INFO,
55
- message=message,
56
- action=None,
57
- tool=self.name,
58
- context=context,
59
- )
60
- )
61
51
 
62
52
  def report_error(self, message: str, context: dict = None):
63
53
  self._event_bus.publish(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: janito
3
- Version: 2.4.0
3
+ Version: 2.5.0
4
4
  Summary: A new Python package called janito.
5
5
  Author-email: João Pinto <lamego.pinto@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/janito-dev/janito
@@ -167,19 +167,6 @@ Janito has configuration options, like `--set api-key API_KEY` and `--set provid
167
167
 
168
168
  ### Advanced Options
169
169
 
170
- - **Enable Inline Web File Viewer for Clickable Links**
171
-
172
- By default, Janito can open referenced files in a browser-based viewer when you click on file links in supported terminals. To enable this feature for your session, use the `--web` flag:
173
-
174
- ```bash
175
- janito --web
176
- ```
177
-
178
- This starts the lightweight web file viewer () in the background, allowing you to inspect files referenced in responses directly in your browser. Combine with interactive mode or prompts as needed.
179
-
180
- > **Tip:** Use with the interactive shell for the best experience with clickable file links.
181
-
182
-
183
170
  - **Enable Execution Tools (Code/Shell Execution)**
184
171
 
185
172
  By default, **all tool privileges (read, write, execute)** are disabled for safety. This means Janito starts with no permissions to run tools that read, write, or execute code/shell commands unless you explicitly enable them.
@@ -232,7 +219,7 @@ janito -r -w -x "Run this code: print('Hello, world!')"
232
219
  ### Core CLI Options
233
220
  | Option | Description |
234
221
  |------------------------|-----------------------------------------------------------------------------|
235
- | `--web` | Enable the builtin lightweight web file viewer for clickable file links (). |
222
+
236
223
  | `--version` | Show program version |
237
224
  | `--list-tools` | List all registered tools |
238
225
  | `--list-providers` | List all supported LLM providers |
@@ -8,52 +8,55 @@ janito/dir_walk_utils.py,sha256=ON9EyVH7Aaik8WtCH5z8DQis9ycdoNVkjNvU16HH498,1193
8
8
  janito/driver_events.py,sha256=51ab7KW_W6fVZVeO0ez-HJFY4NbTI327ZlEmEsEkxQc,3405
9
9
  janito/exceptions.py,sha256=l4AepRdWwAuLp5fUygrBBgO9rpwgfV6JvY1afOdq2pw,913
10
10
  janito/formatting.py,sha256=SMvOmL6bst3KGcI7OLa5D4DE127fQYuHZS3oY8OPsn8,2031
11
- janito/formatting_token.py,sha256=J810eUoXhtM73fIAkgAcl_oN2WhdUs6A06lDX75mnmg,1965
11
+ janito/formatting_token.py,sha256=ECZ9CNcOfQeutNMTZZTQrKm17pTgNpMAGVsNr7_EEnE,2167
12
12
  janito/gitignore_utils.py,sha256=P3iF9fMWAomqULq2xsoqHtI9uNIFSPcagljrxZshmLw,4110
13
13
  janito/perf_singleton.py,sha256=g1h0Sdf4ydzegeEpJlMhQt4H0GQZ2hryXrdYOTL-b30,113
14
14
  janito/performance_collector.py,sha256=RYu4av16Trj3RljJZ8-2Gbn1KlGdJUosrcVFYtwviNI,6285
15
15
  janito/platform_discovery.py,sha256=JN3kC7hkxdvuj-AyrJTlbbDJjtNHke3fdlZDqGi_uz0,4621
16
16
  janito/provider_config.py,sha256=acn2FEgWsEIyi2AxZiuCLoP2rXDd-nXcP5VB4CZHaeE,3189
17
- janito/provider_registry.py,sha256=FjsrOXzuUFQZdJ6qK69Z365-iqIFeffLoObCGHQqv7A,7840
17
+ janito/provider_registry.py,sha256=THlyJLhAr0hTb4OuLHc7BcOjTYy0LG-THc-kZRk3PCI,7787
18
18
  janito/report_events.py,sha256=q4OR_jTZNfcqaQF_fzTjgqo6_VlUIxSGWfhpT4nJWcw,938
19
19
  janito/shell.bak.zip,sha256=hznHbmgfkAkjuQDJ3w73XPQh05yrtUZQxLmtGbanbYU,22
20
20
  janito/utils.py,sha256=eXSsMgM69YyzahgCNrJQLcEbB8ssLI1MQqaa20ONxbE,376
21
- janito/agent/setup_agent.py,sha256=7oKIE-ieKSimLARL8xHwAvrKWhvaoaQuZtouYPrCk6k,8632
21
+ janito/agent/setup_agent.py,sha256=CdhXRhnEJ6s3ZyIypBKVhyc9wJKzEKUw5Ph6a25sQAI,8568
22
+ janito/agent/templates/profiles/system_prompt_template_assistant.txt.j2,sha256=dTV9aF8ji2r9dzi-l4b9r95kHrbKmjvnRxk5cVpopN4,28
22
23
  janito/agent/templates/profiles/system_prompt_template_developer.txt.j2,sha256=gIXF3dPgGxQnVqRBnT8r2sUGu7F_Sl0F4YF-TfyOKgI,2586
23
24
  janito/cli/__init__.py,sha256=xaPDOrWphBbCR63Xpcx_yfpXSJIlCaaICc4j2qpWqrM,194
24
25
  janito/cli/config.py,sha256=t7sdM0I3RD_FZ2ni1xuGMFGzvCLMt3NwJKu3_WtxPUg,1068
25
26
  janito/cli/console.py,sha256=gJolqzWL7jEPLxeuH-CwBDRFpXt976KdZOEAB2tdBDs,64
26
27
  janito/cli/main.py,sha256=s5odou0txf8pzTf1ADk2yV7T5m8B6cejJ81e7iu776U,312
27
- janito/cli/main_cli.py,sha256=aZZjuqJbhDE0bxi1y4kfDOT5V8Z57TP8YqqdJGOlQ7k,11624
28
+ janito/cli/main_cli.py,sha256=t5AgysW_mfeLlrNhJpLhumUs65YCWzvN4gkJRmozlKU,12086
28
29
  janito/cli/prompt_core.py,sha256=IAa1X4fw4aPASFyOXGiFcpgiZXlVoFQM617F0mHMxsE,11587
29
30
  janito/cli/prompt_handler.py,sha256=SnPTlL64noeAMGlI08VBDD5IDD8jlVMIYA4-fS8zVLg,215
30
- janito/cli/prompt_setup.py,sha256=_2VaUtK67rk9QnvLGmdRJ31m244-Vf-WQazJtp9PzeE,1935
31
- janito/cli/rich_terminal_reporter.py,sha256=LCUGojAGlvs2SOHs7_qFz8AbAGJW5cyLQhte4OXHIR4,4981
31
+ janito/cli/prompt_setup.py,sha256=PoRXIWEoVJ5DQtOLO0JCz_8cVVWp7zhKXQtXJuRGiQ4,1882
32
+ janito/cli/rich_terminal_reporter.py,sha256=xoZ_oeeqAr1f6a20OvQx9hKfNuWUX6vOAoUIL3_anUA,5552
32
33
  janito/cli/utils.py,sha256=plCQiDKIf3V8mFhhX5H9-MF2W86i-xRdWf8Xi117Z0w,677
33
34
  janito/cli/verbose_output.py,sha256=UmB1byT1V6wZvMJDIPfqajhmNcMnnJ3tgYocje5w0x8,7620
34
35
  janito/cli/chat_mode/bindings.py,sha256=u8q8SekKyAFncoPI5mxeAQ2lI3loIEaUVyq2TqELv2c,1990
35
36
  janito/cli/chat_mode/chat_entry.py,sha256=HjflAjGOz4xyRbzocsEzrjcVepfQYz3d9fzyZDMBB34,477
36
37
  janito/cli/chat_mode/prompt_style.py,sha256=Yltxc9unsiWsJzfditE139iqL3S64d6G19LzrnqYvFg,825
37
- janito/cli/chat_mode/session.py,sha256=monPEAFbDeS_p_DM4ml_GQvz2JfipqNgU0T3MFJSGy0,11309
38
- janito/cli/chat_mode/session_profile_select.py,sha256=epKwAM_DlL_4LA940_zqmTy0BvIyheCdD_Zab-lRg9I,2913
38
+ janito/cli/chat_mode/script_runner.py,sha256=QwNIZWRPhlwsC4IOrh1rrZjTwMDeYGOByNZZVzg1tZk,6442
39
+ janito/cli/chat_mode/session.py,sha256=hwFilKshsZlR95ycX31clg4nD5DJiREmu9B-m02pbko,11941
40
+ janito/cli/chat_mode/session_profile_select.py,sha256=N_d1LMjXUS-ROQJaq0fTbPENxopXDuZwuLGCctg9Sd0,2894
39
41
  janito/cli/chat_mode/toolbar.py,sha256=QWIVAdm31vNKu0UO_-igxYwVwtko-KzjtxPtK3DYH5Y,4891
40
42
  janito/cli/chat_mode/shell/autocomplete.py,sha256=lE68MaVaodbA2VfUM0_YLqQVLBJAE_BJsd5cMtwuD-g,793
41
43
  janito/cli/chat_mode/shell/commands.bak.zip,sha256=I7GFjXg2ORT5NzFpicH1vQ3kchhduQsZinzqo0xO8wU,74238
42
- janito/cli/chat_mode/shell/input_history.py,sha256=mdcu8XNPp1ewVQMTEmqoAdgj1Lsig5cKkUfvFVxShYo,2537
44
+ janito/cli/chat_mode/shell/input_history.py,sha256=EbfsZWzEkbW3VpWldN6Z885HwJq7QtxOveWaAmTamdg,2562
43
45
  janito/cli/chat_mode/shell/session.bak.zip,sha256=m1GyO3Wy4G4D9sVgRO6ZDyC0VjclsmnEJsiQoer4LzI,5789
44
- janito/cli/chat_mode/shell/commands/__init__.py,sha256=Mi5srIBhIaLwjqKSb76bDTXiodtJqsjTNzptSm2Pt2Y,2278
46
+ janito/cli/chat_mode/shell/commands/__init__.py,sha256=T-t6JGDPTf7v6Ap4UT7spC0c0FbQ6YVXSVEesgbjycw,2390
45
47
  janito/cli/chat_mode/shell/commands/_priv_check.py,sha256=LfIa_IbJBIhKT17K2cACbfYEJprFUH-o4BPvNnGyPSE,204
48
+ janito/cli/chat_mode/shell/commands/bang.py,sha256=PE79ZDKb9l4cFGbHLdJbpBcKmJRvhyFQQcCrtofY0HQ,1746
46
49
  janito/cli/chat_mode/shell/commands/base.py,sha256=I6-SVOcRd7q4PpoutLdrbhbqeUpJic2oyPhOSMgMihA,288
47
50
  janito/cli/chat_mode/shell/commands/clear.py,sha256=wYEHGYcAohUoCJlbEhiXKfDbJvuzAVK4e9uirskIllw,422
48
- janito/cli/chat_mode/shell/commands/conversation_restart.py,sha256=klT_TtbsyJXOANAoc93_yg4ZxmHJjtdw5dH-ONrttPw,4710
51
+ janito/cli/chat_mode/shell/commands/conversation_restart.py,sha256=CDPYOZMWkgBlq-xMJEwOTXTpw_nNY9eBSfbqLtB1e00,3725
49
52
  janito/cli/chat_mode/shell/commands/execute.py,sha256=OS7RHl2JS-tFOA9-YAvWEYnb7HvAKOFOr7MHagV6imM,2190
50
- janito/cli/chat_mode/shell/commands/help.py,sha256=EaA9Dm8L6ilGMrgfqa0va0FaoOG8FIlX6sNhbgVKeik,938
53
+ janito/cli/chat_mode/shell/commands/help.py,sha256=MvjnTskb7_z0aTbPML11Py2XYqBvLymzwIZgwE4bMpI,947
51
54
  janito/cli/chat_mode/shell/commands/history_view.py,sha256=9dyxYpDHjT77LEIikjBQA03Ep3P2AmKXUwUnVsG0OQc,3584
52
55
  janito/cli/chat_mode/shell/commands/lang.py,sha256=uIelDs3gPYDZ9X9gw7iDMmiwefT7TiBo32420pq2tW8,837
53
56
  janito/cli/chat_mode/shell/commands/livelogs.py,sha256=uJI14qyubXEz8m0Cajd-vURPYxC__7p_CNCq6PVOHN0,2142
54
57
  janito/cli/chat_mode/shell/commands/model.py,sha256=2tORoA5vdkAknbS9mnMi03gNKcLEkgmIuHPUHDGWxYo,1390
55
58
  janito/cli/chat_mode/shell/commands/multi.py,sha256=HAAk0fAO3n8KFta3I4hT_scOAlz4SxWDyaNBUJBQ4nc,1985
56
- janito/cli/chat_mode/shell/commands/prompt.py,sha256=x9S3mOpplpR5aiy5b8LSIsZEEFGenQtPGK6HxYdwx1Y,2448
59
+ janito/cli/chat_mode/shell/commands/prompt.py,sha256=z59Nbx0ny51AqBOj3CtK6GdvIt7ZvgEnFHwlaAhPZTI,2104
57
60
  janito/cli/chat_mode/shell/commands/read.py,sha256=AFdkfFWasoUQ8icvHROVEExyCip-sGPLumoUXNkqIFY,1972
58
61
  janito/cli/chat_mode/shell/commands/role.py,sha256=7A2S2wzE6lcv1rg4iLGH8vVy-TnzRE0Tn_wPRhBHLpY,1474
59
62
  janito/cli/chat_mode/shell/commands/session.py,sha256=9wsw5U24-KJgTT70KAwnGuS8MVPyvpxCJfAt_Io76O0,1574
@@ -64,7 +67,7 @@ janito/cli/chat_mode/shell/commands/verbose.py,sha256=HDTe0NhdcjBuhh-eJSW8iLPDee
64
67
  janito/cli/chat_mode/shell/commands/write.py,sha256=kst0CBxR7UQurAjpx1junYwjm2bWsGVfSK80kJXAm54,1982
65
68
  janito/cli/chat_mode/shell/session/__init__.py,sha256=uTYE_QpZFEn7v9QE5o1LdulpCWa9vmk0OsefbBGWg_c,37
66
69
  janito/cli/chat_mode/shell/session/history.py,sha256=tYav6GgjAZkvWhlI_rfG6OArNqW6Wn2DTv39Hb20QYc,1262
67
- janito/cli/chat_mode/shell/session/manager.py,sha256=SL9BCdlCPdoo-5BPAIC1eaJuXv7hH4d5VGqMF6T7MEI,3333
70
+ janito/cli/chat_mode/shell/session/manager.py,sha256=m6cQe-9SeIqBnnWVEGtZiBtCpStqIwqRzP09XPhJrdM,1005
68
71
  janito/cli/cli_commands/list_models.py,sha256=VN7_DG6aTxaHPrc6_H-OftRXRT1urhf5ze_qJ_SO35U,1116
69
72
  janito/cli/cli_commands/list_providers.py,sha256=AMAVdoS7KN7WA3gaKhZZdfio_zvknu21OLDc6CTFZ34,173
70
73
  janito/cli/cli_commands/list_tools.py,sha256=b-OG-lVV4B99bBc05qOrac3qoK8qDJJWGGLHAxsRwvo,4060
@@ -76,13 +79,13 @@ janito/cli/cli_commands/show_system_prompt.py,sha256=fbFWKWiIuI-UmYy39oHSZE3LBty
76
79
  janito/cli/core/__init__.py,sha256=YH95fhgY9yBX8RgqX9dSrEkl4exjV0T4rbmJ6xUpG-Y,196
77
80
  janito/cli/core/event_logger.py,sha256=1X6lR0Ax7AgF8HlPWFoY5Ystuu7Bh4ooTo78vXzeGB0,2008
78
81
  janito/cli/core/getters.py,sha256=Znw6aF6QUHGu6UWqQHQYu7LvNPPIjOO4SD4yyYaIGnw,1467
79
- janito/cli/core/runner.py,sha256=4n2T_9viKqP5uMe5maYKmYXHs88L8hqvvNsZjGBR21E,7198
82
+ janito/cli/core/runner.py,sha256=SOrwRpiOC81ja_ZiN1RelaXNhquvMuu6YIOyT_iLtwg,7144
80
83
  janito/cli/core/setters.py,sha256=S3PxWPh0s7DAhbNyNRspbjtbd5EdAR-JNRe6X4jjIjE,7438
81
84
  janito/cli/core/unsetters.py,sha256=FEw9gCt0vRvoCt0kRSNfVB2tzi_TqppJIx2nHPP59-k,2012
82
85
  janito/cli/single_shot_mode/__init__.py,sha256=Ct99pKe9tINzVW6oedZJfzfZQKWpXz-weSSCn0hrwHY,115
83
- janito/cli/single_shot_mode/handler.py,sha256=z8sL3CMRbncXLjdaPUYLq7dsV3t0nyh1mm4kXQf5Mdg,3475
86
+ janito/cli/single_shot_mode/handler.py,sha256=RtmkJVvF1j8FS7_HSlnuldUj2BzTf63rwGQ0KKhe4dU,3704
84
87
  janito/drivers/dashscope.bak.zip,sha256=9Pv4Xyciju8jO1lEMFVgYXexoZkxmDO3Ig6vw3ODfL8,4936
85
- janito/drivers/driver_registry.py,sha256=c_nezPfjPHaAZjCZhU80JN_YRCKYBJhomQNYZCu-Ug4,1007
88
+ janito/drivers/driver_registry.py,sha256=5ywB2CoNLsKB5D9ODVGVTCThbtskoUH_BvuRlHkK5Ew,890
86
89
  janito/drivers/openai_responses.bak.zip,sha256=E43eDCHGa2tCtdjzj_pMnWDdnsOZzj8BJTR5tJp8wcM,13352
87
90
  janito/drivers/anthropic/driver.py,sha256=4yLaf2T0g2zr-MSwXOx32s7ETut9FOl0uXyJGYiJzZU,3937
88
91
  janito/drivers/azure_openai/driver.py,sha256=zQc9xH-RD409okDCfTRwb1QXXb9WzR2bsBfRyrZ5HYc,3936
@@ -108,9 +111,9 @@ janito/llm/driver_input.py,sha256=Zq7IO4KdQPUraeIo6XoOaRy1IdQAyYY15RQw4JU30uA,38
108
111
  janito/llm/message_parts.py,sha256=QY_0kDjaxdoErDgKPRPv1dNkkYJuXIBmHWNLiOEKAH4,1365
109
112
  janito/llm/model.py,sha256=42hjcffZDTuzjAJoVhDcDqwIXm6rUmmi5UwTOYopf5w,1131
110
113
  janito/llm/provider.py,sha256=lfIJnh06F0kf8--Pg_W7ALhkbIzn7N4iItQ93pntyuM,7978
111
- janito/providers/__init__.py,sha256=Q9zTiZlDuAsdI6y4tAcqLlZ6LCKyRaOsoQ2iBAGq0O4,367
114
+ janito/providers/__init__.py,sha256=AY_mYBUuPP85TTIrx0-lMwbf8-biTLaCo_mZQBy0sck,282
112
115
  janito/providers/dashscope.bak.zip,sha256=BwXxRmZreEivvRtmqbr5BR62IFVlNjAf4y6DrF2BVJo,5998
113
- janito/providers/provider_static_info.py,sha256=Lwbcb-AOEmo9v5Ma4SqM51uSXGwWYFewMJSDl1rOd8M,568
116
+ janito/providers/provider_static_info.py,sha256=CaidrKP062WrYAej27wIbSPK426t2iuufIUTNd6Sjug,497
114
117
  janito/providers/registry.py,sha256=Ygwv9eVrTXOKhv0EKxSWQXO5WMHvajWE2Q_Lc3p7dKo,730
115
118
  janito/providers/anthropic/model_info.py,sha256=saofXNs73WhlAhm58AcIkSem7C8FMUgHP19BvkoLV5Y,641
116
119
  janito/providers/anthropic/provider.py,sha256=JW7PSGf7RNQWDMpf55DnnfP1oWU3d98koaz4AHjWtrQ,2509
@@ -135,7 +138,7 @@ janito/tools/inspect_registry.py,sha256=Jo7PrMPRKLuR-j_mBAk9PBcTzeJf1eQrS1ChGofg
135
138
  janito/tools/outline_file.bak.zip,sha256=EeI2cBXCwTdWVgJDNiroxKeYlkjwo6NLKeXz3J-2iZI,15607
136
139
  janito/tools/permissions.py,sha256=8lsfT7L6pyuvjZAgIXX5WrZZYSjZXPWUBpW7LXDBJ6M,1496
137
140
  janito/tools/permissions_parse.py,sha256=OY_Uojjg_QCp6UsfVk5iHhrKRbeFgzfm8UUIoYDe18I,382
138
- janito/tools/tool_base.py,sha256=v5xUQqI9SzkwPrjAjbFgXIxSAHLC8eZOBIAaQMJBsqI,3962
141
+ janito/tools/tool_base.py,sha256=-yzl7Kki8eNlyyU-Z83ReXR-iJ0RkHpD6uksLYneyoE,3629
139
142
  janito/tools/tool_events.py,sha256=czRtC2TYakAySBZvfHS_Q6_NY_7_krxzAzAL1ggRFWA,1527
140
143
  janito/tools/tool_run_exception.py,sha256=43yWgTaGBGEtRteo6FvTrane6fEVGo9FU1uOdjMRWJE,525
141
144
  janito/tools/tool_use_tracker.py,sha256=koXi1h-si8IpRFUdMaj6h6buxeYsuEDC4geP_f2xPms,2805
@@ -177,7 +180,7 @@ janito/tools/adapters/local/search_text/match_lines.py,sha256=2l0r8_1l5gnmu9vJSd
177
180
  janito/tools/adapters/local/search_text/pattern_utils.py,sha256=Cytwl7M9tNY-IsAmvoMgvlQMPswbCHTVrX8aZQ6IBJc,2374
178
181
  janito/tools/adapters/local/search_text/traverse_directory.py,sha256=TrsAlFXcG7WdtZS6pg3_6vlL3h-afps5u7kkBDhA65c,4064
179
182
  janito/tools/adapters/local/validate_file_syntax/__init__.py,sha256=P53RHmas4BbHL90cMxH9m-RpMCJI8JquoJb0rpkPVVk,29
180
- janito/tools/adapters/local/validate_file_syntax/core.py,sha256=dOIKVY43rvY_TdPqBHKsOyig64DpjH-Fb9btYvGvRJs,3398
183
+ janito/tools/adapters/local/validate_file_syntax/core.py,sha256=Gqrvx0hPFnuzg0kQbLT-Z6ftF84Tkqq7o2c4CJDU4M8,3369
181
184
  janito/tools/adapters/local/validate_file_syntax/css_validator.py,sha256=2yUMNxVIQy3AhuiahyZZbci0azMHkSWlGBbYIxJNJ-U,1361
182
185
  janito/tools/adapters/local/validate_file_syntax/html_validator.py,sha256=sCIGBx-b-xz-vbz6pQM0rYYuzrt93_9ApC5zQ9Rwadk,3064
183
186
  janito/tools/adapters/local/validate_file_syntax/js_validator.py,sha256=Km-wUrG0YZJ7kzxxyVPN_vXqOWIdfD12GkhQHPRVrC8,1008
@@ -187,9 +190,9 @@ janito/tools/adapters/local/validate_file_syntax/ps1_validator.py,sha256=cP1jsMh
187
190
  janito/tools/adapters/local/validate_file_syntax/python_validator.py,sha256=lHzjlA4g9nCF9hXkGx3izWF0b0vJH3yV7Pu3buLyBbI,140
188
191
  janito/tools/adapters/local/validate_file_syntax/xml_validator.py,sha256=3CK7BEGO7gKI3bpeTtCFe0kJ5aKDZVh3Kh67bGIhcuc,294
189
192
  janito/tools/adapters/local/validate_file_syntax/yaml_validator.py,sha256=XLmOp7Ef6pLd97ICVnF3PxNKL1Yo5tLZsasvxPY478Y,165
190
- janito-2.4.0.dist-info/licenses/LICENSE,sha256=GSAKapQH5ZIGWlpQTA7v5YrfECyaxaohUb1vJX-qepw,1090
191
- janito-2.4.0.dist-info/METADATA,sha256=QlUOwMhvDFyWpbzS1n3lk_CQoE32Bf2q82_hzUgKgsw,17058
192
- janito-2.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
193
- janito-2.4.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
194
- janito-2.4.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
195
- janito-2.4.0.dist-info/RECORD,,
193
+ janito-2.5.0.dist-info/licenses/LICENSE,sha256=GSAKapQH5ZIGWlpQTA7v5YrfECyaxaohUb1vJX-qepw,1090
194
+ janito-2.5.0.dist-info/METADATA,sha256=WqfY2ffIWvjuk6WAdM70c_dZYUcQCXjNgm6VChozTeE,16364
195
+ janito-2.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
196
+ janito-2.5.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
197
+ janito-2.5.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
198
+ janito-2.5.0.dist-info/RECORD,,
File without changes