janito 1.8.1__py3-none-any.whl → 1.10.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 (142) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/api_exceptions.py +4 -0
  3. janito/agent/config.py +1 -1
  4. janito/agent/config_defaults.py +2 -3
  5. janito/agent/config_utils.py +0 -9
  6. janito/agent/conversation.py +177 -114
  7. janito/agent/conversation_api.py +179 -159
  8. janito/agent/conversation_tool_calls.py +11 -8
  9. janito/agent/llm_conversation_history.py +70 -0
  10. janito/agent/openai_client.py +44 -21
  11. janito/agent/openai_schema_generator.py +164 -128
  12. janito/agent/platform_discovery.py +134 -77
  13. janito/agent/profile_manager.py +5 -5
  14. janito/agent/rich_message_handler.py +80 -31
  15. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +9 -8
  16. janito/agent/test_openai_schema_generator.py +93 -0
  17. janito/agent/tool_base.py +7 -2
  18. janito/agent/tool_executor.py +63 -50
  19. janito/agent/tool_registry.py +5 -2
  20. janito/agent/tool_use_tracker.py +42 -5
  21. janito/agent/tools/__init__.py +13 -12
  22. janito/agent/tools/create_directory.py +9 -6
  23. janito/agent/tools/create_file.py +35 -54
  24. janito/agent/tools/delete_text_in_file.py +97 -0
  25. janito/agent/tools/fetch_url.py +50 -5
  26. janito/agent/tools/find_files.py +40 -26
  27. janito/agent/tools/get_file_outline/__init__.py +1 -0
  28. janito/agent/tools/{outline_file/__init__.py → get_file_outline/core.py} +14 -18
  29. janito/agent/tools/get_file_outline/python_outline.py +134 -0
  30. janito/agent/tools/{search_outline.py → get_file_outline/search_outline.py} +11 -0
  31. janito/agent/tools/get_lines.py +21 -12
  32. janito/agent/tools/move_file.py +13 -12
  33. janito/agent/tools/present_choices.py +3 -1
  34. janito/agent/tools/python_command_runner.py +150 -0
  35. janito/agent/tools/python_file_runner.py +148 -0
  36. janito/agent/tools/python_stdin_runner.py +154 -0
  37. janito/agent/tools/remove_directory.py +4 -2
  38. janito/agent/tools/remove_file.py +15 -13
  39. janito/agent/tools/replace_file.py +72 -0
  40. janito/agent/tools/replace_text_in_file.py +7 -5
  41. janito/agent/tools/run_bash_command.py +29 -72
  42. janito/agent/tools/run_powershell_command.py +142 -102
  43. janito/agent/tools/search_text.py +177 -131
  44. janito/agent/tools/validate_file_syntax/__init__.py +1 -0
  45. janito/agent/tools/validate_file_syntax/core.py +94 -0
  46. janito/agent/tools/validate_file_syntax/css_validator.py +35 -0
  47. janito/agent/tools/validate_file_syntax/html_validator.py +77 -0
  48. janito/agent/tools/validate_file_syntax/js_validator.py +27 -0
  49. janito/agent/tools/validate_file_syntax/json_validator.py +6 -0
  50. janito/agent/tools/validate_file_syntax/markdown_validator.py +66 -0
  51. janito/agent/tools/validate_file_syntax/ps1_validator.py +32 -0
  52. janito/agent/tools/validate_file_syntax/python_validator.py +5 -0
  53. janito/agent/tools/validate_file_syntax/xml_validator.py +11 -0
  54. janito/agent/tools/validate_file_syntax/yaml_validator.py +6 -0
  55. janito/agent/tools_utils/__init__.py +1 -0
  56. janito/agent/tools_utils/action_type.py +7 -0
  57. janito/agent/tools_utils/dir_walk_utils.py +24 -0
  58. janito/agent/tools_utils/formatting.py +49 -0
  59. janito/agent/tools_utils/gitignore_utils.py +69 -0
  60. janito/agent/tools_utils/test_gitignore_utils.py +46 -0
  61. janito/agent/tools_utils/utils.py +30 -0
  62. janito/cli/_livereload_log_utils.py +13 -0
  63. janito/cli/_print_config.py +63 -61
  64. janito/cli/arg_parser.py +57 -14
  65. janito/cli/cli_main.py +270 -0
  66. janito/cli/livereload_starter.py +60 -0
  67. janito/cli/main.py +166 -99
  68. janito/cli/one_shot.py +80 -0
  69. janito/cli/termweb_starter.py +2 -2
  70. janito/i18n/__init__.py +1 -1
  71. janito/livereload/app.py +25 -0
  72. janito/rich_utils.py +41 -25
  73. janito/{cli_chat_shell → shell}/commands/__init__.py +19 -14
  74. janito/{cli_chat_shell → shell}/commands/config.py +4 -4
  75. janito/shell/commands/conversation_restart.py +74 -0
  76. janito/shell/commands/edit.py +24 -0
  77. janito/shell/commands/history_view.py +18 -0
  78. janito/{cli_chat_shell → shell}/commands/lang.py +3 -0
  79. janito/shell/commands/livelogs.py +42 -0
  80. janito/{cli_chat_shell → shell}/commands/prompt.py +16 -6
  81. janito/shell/commands/session.py +35 -0
  82. janito/{cli_chat_shell → shell}/commands/session_control.py +3 -5
  83. janito/{cli_chat_shell → shell}/commands/termweb_log.py +18 -10
  84. janito/shell/commands/tools.py +26 -0
  85. janito/shell/commands/track.py +36 -0
  86. janito/shell/commands/utility.py +28 -0
  87. janito/{cli_chat_shell → shell}/commands/verbose.py +4 -5
  88. janito/shell/commands.py +40 -0
  89. janito/shell/input_history.py +62 -0
  90. janito/shell/main.py +257 -0
  91. janito/{cli_chat_shell/shell_command_completer.py → shell/prompt/completer.py} +1 -1
  92. janito/{cli_chat_shell/chat_ui.py → shell/prompt/session_setup.py} +19 -5
  93. janito/shell/session/manager.py +101 -0
  94. janito/{cli_chat_shell/ui.py → shell/ui/interactive.py} +23 -17
  95. janito/termweb/app.py +3 -3
  96. janito/termweb/static/editor.css +142 -0
  97. janito/termweb/static/editor.css.bak +27 -0
  98. janito/termweb/static/editor.html +15 -213
  99. janito/termweb/static/editor.html.bak +16 -215
  100. janito/termweb/static/editor.js +209 -0
  101. janito/termweb/static/editor.js.bak +227 -0
  102. janito/termweb/static/index.html +2 -3
  103. janito/termweb/static/index.html.bak +2 -3
  104. janito/termweb/static/termweb.css.bak +33 -84
  105. janito/termweb/static/termweb.js +15 -34
  106. janito/termweb/static/termweb.js.bak +18 -36
  107. janito/tests/test_rich_utils.py +44 -0
  108. janito/web/app.py +0 -75
  109. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/METADATA +62 -42
  110. janito-1.10.0.dist-info/RECORD +158 -0
  111. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/WHEEL +1 -1
  112. janito/agent/tools/dir_walk_utils.py +0 -16
  113. janito/agent/tools/gitignore_utils.py +0 -46
  114. janito/agent/tools/memory.py +0 -48
  115. janito/agent/tools/outline_file/formatting.py +0 -20
  116. janito/agent/tools/outline_file/python_outline.py +0 -71
  117. janito/agent/tools/present_choices_test.py +0 -18
  118. janito/agent/tools/rich_live.py +0 -44
  119. janito/agent/tools/run_python_command.py +0 -163
  120. janito/agent/tools/tools_utils.py +0 -56
  121. janito/agent/tools/utils.py +0 -33
  122. janito/agent/tools/validate_file_syntax.py +0 -163
  123. janito/cli/runner/cli_main.py +0 -180
  124. janito/cli_chat_shell/chat_loop.py +0 -163
  125. janito/cli_chat_shell/chat_state.py +0 -38
  126. janito/cli_chat_shell/commands/history_start.py +0 -37
  127. janito/cli_chat_shell/commands/session.py +0 -48
  128. janito/cli_chat_shell/commands/sum.py +0 -49
  129. janito/cli_chat_shell/commands/utility.py +0 -32
  130. janito/cli_chat_shell/session_manager.py +0 -72
  131. janito-1.8.1.dist-info/RECORD +0 -127
  132. /janito/agent/tools/{outline_file → get_file_outline}/markdown_outline.py +0 -0
  133. /janito/cli/{runner/_termweb_log_utils.py → _termweb_log_utils.py} +0 -0
  134. /janito/cli/{runner/config.py → config_runner.py} +0 -0
  135. /janito/cli/{runner/formatting.py → formatting_runner.py} +0 -0
  136. /janito/{cli/runner → shell}/__init__.py +0 -0
  137. /janito/{cli_chat_shell → shell/prompt}/load_prompt.py +0 -0
  138. /janito/{cli_chat_shell/config_shell.py → shell/session/config.py} +0 -0
  139. /janito/{cli_chat_shell/__init__.py → shell/session/history.py} +0 -0
  140. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/entry_points.txt +0 -0
  141. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/licenses/LICENSE +0 -0
  142. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/top_level.txt +0 -0
janito/cli/one_shot.py ADDED
@@ -0,0 +1,80 @@
1
+ from janito.agent.conversation_exceptions import (
2
+ MaxRoundsExceededError,
3
+ ProviderError,
4
+ EmptyResponseError,
5
+ )
6
+ from janito.agent.api_exceptions import ApiError
7
+ from janito.agent.llm_conversation_history import LLMConversationHistory
8
+
9
+
10
+ def prepare_messages(args, profile_manager, runtime_config):
11
+ prompt = getattr(args, "input_arg", None)
12
+ messages = []
13
+ system_prompt_override = runtime_config.get("system_prompt_template")
14
+ if system_prompt_override:
15
+ if not runtime_config.get("vanilla_mode", False) or getattr(
16
+ args, "system", None
17
+ ):
18
+ messages.append({"role": "system", "content": system_prompt_override})
19
+ elif profile_manager.system_prompt_template and not runtime_config.get(
20
+ "vanilla_mode", False
21
+ ):
22
+ messages.append(
23
+ {"role": "system", "content": profile_manager.system_prompt_template}
24
+ )
25
+ messages.append({"role": "user", "content": prompt})
26
+ return messages
27
+
28
+
29
+ def print_usage_info(args, info_start_time, result, console):
30
+ if (
31
+ getattr(args, "info", False)
32
+ and info_start_time is not None
33
+ and result is not None
34
+ ):
35
+ usage_info = result.get("usage")
36
+ total_tokens = usage_info.get("total_tokens") if usage_info else None
37
+ prompt_tokens = usage_info.get("prompt_tokens") if usage_info else None
38
+ completion_tokens = usage_info.get("completion_tokens") if usage_info else None
39
+ elapsed = time.time() - info_start_time
40
+ console.print(
41
+ f"[bold green]Total tokens:[/] [yellow]{total_tokens}[/yellow] [bold green]| Input:[/] [cyan]{prompt_tokens}[/cyan] [bold green]| Output:[/] [magenta]{completion_tokens}[/magenta] [bold green]| Elapsed:[/] [yellow]{elapsed:.2f}s[/yellow]",
42
+ style="dim",
43
+ )
44
+
45
+
46
+ def run_oneshot_mode(args, profile_manager, runtime_config):
47
+ from rich.console import Console
48
+ from janito.agent.rich_message_handler import RichMessageHandler
49
+ import time
50
+
51
+ console = Console()
52
+ message_handler = RichMessageHandler()
53
+ messages = prepare_messages(args, profile_manager, runtime_config)
54
+ info_start_time = None
55
+ if getattr(args, "info", False):
56
+ info_start_time = time.time()
57
+ try:
58
+ max_rounds = 100
59
+ result = profile_manager.agent.chat(
60
+ LLMConversationHistory(messages),
61
+ message_handler=message_handler,
62
+ spinner=True,
63
+ max_rounds=max_rounds,
64
+ )
65
+ print_usage_info(args, info_start_time, result, console)
66
+ except MaxRoundsExceededError:
67
+ console.print("[red]Max conversation rounds exceeded.[/red]")
68
+ except ProviderError as e:
69
+ console.print(f"[red]Provider error:[/red] {e}")
70
+ except EmptyResponseError as e:
71
+ console.print(f"[red]Error:[/red] {e}")
72
+ except ApiError as e:
73
+ if "maximum context length" in str(e):
74
+ console.print(
75
+ f"[red]Error:[/red] {e}\n[bold yellow]Tip:[/] Try using [green]--max-tokens[/green] with a lower value."
76
+ )
77
+ else:
78
+ console.print(f"[red]API error:[/red] {e}")
79
+ except Exception:
80
+ raise
@@ -5,7 +5,7 @@ import time
5
5
  import http.client
6
6
  import os
7
7
  from rich.console import Console
8
- from janito.cli.runner._termweb_log_utils import print_termweb_logs
8
+ from janito.cli._termweb_log_utils import print_termweb_logs
9
9
  from janito.i18n import tr
10
10
 
11
11
 
@@ -69,5 +69,5 @@ def start_termweb(selected_port):
69
69
  console.print(
70
70
  f"[red]Failed to start TermWeb on port {selected_port}. Check logs for details.[/red]"
71
71
  )
72
- print_termweb_logs(termweb_stdout.name, termweb_stderr.name)
72
+ print_termweb_logs(termweb_stdout.name, termweb_stderr.name, console)
73
73
  return None, False, termweb_stdout.name, termweb_stderr.name
janito/i18n/__init__.py CHANGED
@@ -23,7 +23,7 @@ def set_locale(locale):
23
23
 
24
24
  def tr(msg, **kwargs):
25
25
  """Translate message to current locale, usando hash SHA-1 da mensagem como chave."""
26
- msg_hash = hashlib.sha1(msg.encode("utf-8")).hexdigest()
26
+ msg_hash = hashlib.sha1(msg.encode("utf-8", errors="surrogatepass")).hexdigest()
27
27
  template = _translations.get(msg_hash, msg)
28
28
  try:
29
29
  return template.format(**kwargs)
@@ -0,0 +1,25 @@
1
+ import sys
2
+ import os
3
+ from livereload import Server
4
+
5
+
6
+ def main():
7
+ port = 35729 # Default livereload port
8
+ if "--port" in sys.argv:
9
+ idx = sys.argv.index("--port")
10
+ if idx + 1 < len(sys.argv):
11
+ try:
12
+ port = int(sys.argv[idx + 1])
13
+ except ValueError:
14
+ pass
15
+ watch_dir = os.path.abspath(os.getcwd())
16
+ server = Server()
17
+ server.watch(watch_dir, delay=1)
18
+ print(
19
+ f"Starting livereload server on http://localhost:{port}, watching {watch_dir}"
20
+ )
21
+ server.serve(root=watch_dir, port=port, open_url_delay=None)
22
+
23
+
24
+ if __name__ == "__main__":
25
+ main()
janito/rich_utils.py CHANGED
@@ -2,42 +2,58 @@
2
2
  Utilities for working with the Rich library.
3
3
  """
4
4
 
5
- from rich.markdown import Markdown
6
- from rich.text import Text
7
5
  from rich.console import Console
6
+ from typing import Optional
8
7
 
9
8
 
10
- def print_markdown(console: Console, message: str):
11
- console.print(Markdown(message))
9
+ class RichPrinter:
10
+ """
11
+ Utility class for printing styled messages using the Rich library.
12
12
 
13
+ Args:
14
+ console (Optional[Console]): An optional Rich Console instance. If not provided, a default Console will be created.
13
15
 
14
- def print_info(console: Console, message: str):
15
- console.print(message, style="cyan", end="")
16
+ Methods:
17
+ print_info(message: str)
18
+ Print an informational message in cyan (no newline at end).
16
19
 
20
+ print_error(message: str)
21
+ Print an error message in bold red.
17
22
 
18
- def print_success(console: Console, message: str):
19
- console.print(message, style="bold green", end="\n")
23
+ print_warning(message: str)
24
+ Print a warning message in bold yellow.
20
25
 
26
+ print_magenta(message: str)
27
+ Print a message in magenta.
28
+ """
21
29
 
22
- def print_error(console: Console, message: str):
23
- console.print(message, style="bold red", end="\n")
30
+ def __init__(self, console: Optional[Console] = None):
31
+ self.console = console or Console()
24
32
 
33
+ def print_info(self, message: str):
34
+ self.console.print(message, style="cyan", end="")
25
35
 
26
- def print_warning(console: Console, message: str):
27
- console.print(message, style="bold yellow", end="\n")
36
+ def print_error(self, message: str):
37
+ self.console.print(message, style="bold red", end="\n")
28
38
 
39
+ def print_warning(self, message: str):
40
+ self.console.print(message, style="bold yellow", end="\n")
29
41
 
30
- def print_magenta(console: Console, message: str):
31
- console.print(message, style="magenta", end="\n")
42
+ def print_magenta(self, message: str):
43
+ self.console.print(message, style="magenta", end="\n")
32
44
 
33
-
34
- def print_stdout(console: Console, message: str):
35
- console.print(
36
- Text(message, style="on #003300", no_wrap=True, overflow=None), end=""
37
- )
38
-
39
-
40
- def print_stderr(console: Console, message: str):
41
- console.print(
42
- Text(message, style="on #330000", no_wrap=True, overflow=None), end=""
43
- )
45
+ def print_colored_message(self, message: str, color_index: int = 0):
46
+ """
47
+ Print a message with a cycling background color for verbose-messages.
48
+ """
49
+ bg_colors = [
50
+ "on blue",
51
+ "on green",
52
+ "on magenta",
53
+ "on cyan",
54
+ "on yellow",
55
+ "on red",
56
+ "on bright_black",
57
+ ]
58
+ style = f"bold white {bg_colors[color_index % len(bg_colors)]}"
59
+ self.console.print(message, style=style, end="\n")
@@ -1,55 +1,60 @@
1
- from .session import handle_continue, handle_history
1
+ from .session import handle_history
2
2
  from .prompt import handle_prompt, handle_role
3
- from .session_control import handle_exit, handle_restart
3
+ from .session_control import handle_exit
4
+ from .conversation_restart import handle_restart
4
5
  from .utility import handle_help, handle_clear, handle_multi
6
+ from .tools import handle_tools
5
7
  from .termweb_log import handle_termweb_log_tail, handle_termweb_status
6
- from .sum import handle_sum
7
- from .config import handle_reload
8
- from .history_start import handle_start
9
- from ..config_shell import handle_config_shell
8
+ from .livelogs import handle_livelogs
9
+ from .edit import handle_edit
10
+ from .history_view import handle_view
11
+ from janito.shell.session.config import handle_config_shell
10
12
  from .verbose import handle_verbose
11
13
  from .lang import handle_lang
12
14
  from janito.agent.runtime_config import runtime_config
15
+ from .track import handle_track
13
16
 
14
17
  COMMAND_HANDLERS = {
15
18
  "/termweb-logs": handle_termweb_log_tail,
19
+ "/livelogs": handle_livelogs,
16
20
  "/termweb-status": handle_termweb_status,
21
+ "/edit": handle_edit,
17
22
  "/history": handle_history,
18
- "/continue": handle_continue,
19
23
  "/exit": handle_exit,
20
24
  "exit": handle_exit,
21
25
  "/restart": handle_restart,
26
+ "/start": handle_restart,
22
27
  "/help": handle_help,
23
28
  "/multi": handle_multi,
24
29
  "/prompt": handle_prompt,
30
+ "/tools": handle_tools,
25
31
  "/verbose": handle_verbose,
26
32
  }
27
33
 
28
34
  if not runtime_config.get("vanilla_mode", False):
29
35
  COMMAND_HANDLERS["/role"] = handle_role
30
36
 
31
-
32
37
  COMMAND_HANDLERS["/lang"] = handle_lang
38
+ COMMAND_HANDLERS["/track"] = handle_track
33
39
 
34
40
  COMMAND_HANDLERS.update(
35
41
  {
36
- "/sum": handle_sum,
37
42
  "/clear": handle_clear,
38
- "/start": handle_start,
43
+ "/restart": handle_restart,
39
44
  "/config": handle_config_shell,
40
- "/reload": handle_reload,
45
+ "/view": handle_view,
41
46
  }
42
47
  )
43
48
 
44
49
 
45
- def handle_command(command, console, **kwargs):
50
+ def handle_command(command, console, shell_state=None):
46
51
  parts = command.strip().split()
47
52
  cmd = parts[0]
48
53
  args = parts[1:]
49
54
  handler = COMMAND_HANDLERS.get(cmd)
50
55
  if handler:
51
- # Pass args as a keyword argument for handlers that expect it
52
- return handler(console, args=args, **kwargs)
56
+ # Pass shell_state and args as keyword arguments for handlers that expect them
57
+ return handler(console, args=args, shell_state=shell_state)
53
58
  console.print(
54
59
  f"[bold red]Invalid command: {cmd}. Type /help for a list of commands.[/bold red]"
55
60
  )
@@ -1,5 +1,5 @@
1
1
  def handle_reload(console, *args, **kwargs):
2
- from ..load_prompt import load_prompt
2
+ from janito.shell.prompt.load_prompt import load_prompt
3
3
 
4
4
  agent = kwargs.get("agent")
5
5
  state = kwargs.get("state")
@@ -9,9 +9,9 @@ def handle_reload(console, *args, **kwargs):
9
9
  if hasattr(agent, "system_prompt_template"):
10
10
  agent.system_prompt_template = prompt_text
11
11
  # Update the first system message in the conversation if present
12
- messages = state.get("messages") if state else None
13
- if messages:
14
- for msg in messages:
12
+ history = state.get("history") if state else None
13
+ if history:
14
+ for msg in history:
15
15
  if msg.get("role") == "system":
16
16
  msg["content"] = prompt_text
17
17
  break
@@ -0,0 +1,74 @@
1
+ import os
2
+
3
+ from janito.shell.session.manager import reset_session_id
4
+
5
+
6
+ def handle_restart(console, shell_state=None, **kwargs):
7
+ from janito.shell.session.manager import load_last_conversation, save_conversation
8
+
9
+ reset_session_id()
10
+ save_path = os.path.join(".janito", "last_conversation.json")
11
+
12
+ # --- Append end-of-conversation message to old history if it exists and is non-trivial ---
13
+ if os.path.exists(save_path):
14
+ try:
15
+ messages, prompts, usage = load_last_conversation(save_path)
16
+ if messages and (
17
+ len(messages) > 1
18
+ or (len(messages) == 1 and messages[0].get("role") != "system")
19
+ ):
20
+ messages.append(
21
+ {"role": "system", "content": "[Session ended by user]"}
22
+ )
23
+ # Save to permanent chat history (let save_conversation pick session file)
24
+ save_conversation(messages, prompts, usage)
25
+ except Exception as e:
26
+ console.print(
27
+ f"[bold red]Failed to update previous conversation history:[/bold red] {e}"
28
+ )
29
+
30
+ # Clear the terminal screen
31
+ console.clear()
32
+
33
+ # Reset conversation history using its clear method
34
+ shell_state.conversation_history.clear()
35
+
36
+ # Reset tool use tracker
37
+ try:
38
+ from janito.agent.tool_use_tracker import ToolUseTracker
39
+
40
+ ToolUseTracker.instance().clear_history()
41
+ except Exception as e:
42
+ console.print(
43
+ f"[bold yellow]Warning: Failed to reset tool use tracker:[/bold yellow] {e}"
44
+ )
45
+ # Set system prompt from agent template if available
46
+ if (
47
+ hasattr(shell_state, "profile_manager")
48
+ and shell_state.profile_manager
49
+ and hasattr(shell_state.profile_manager, "agent")
50
+ and shell_state.profile_manager.agent
51
+ and getattr(shell_state.profile_manager.agent, "system_prompt_template", None)
52
+ and not any(
53
+ m.get("role") == "system"
54
+ for m in shell_state.conversation_history.get_messages()
55
+ )
56
+ ):
57
+ shell_state.conversation_history.set_system_message(
58
+ shell_state.profile_manager.agent.system_prompt_template
59
+ )
60
+
61
+ # Reset token usage info in-place so all references (including status bar) are updated
62
+ for k in ("prompt_tokens", "completion_tokens", "total_tokens"):
63
+ if k in shell_state.last_usage_info:
64
+ shell_state.last_usage_info[k] = 0
65
+ else:
66
+ shell_state.last_usage_info[k] = 0
67
+ shell_state.last_elapsed = None
68
+
69
+ console.print(
70
+ "[bold green]Conversation history has been started (context reset).[/bold green]"
71
+ )
72
+
73
+
74
+ handle_restart.help_text = "Start a new conversation (reset context)"
@@ -0,0 +1,24 @@
1
+ import os
2
+ import webbrowser
3
+ from janito.agent.runtime_config import runtime_config
4
+
5
+
6
+ def handle_edit(console, args=None, shell_state=None, **kwargs):
7
+ if not args or len(args) < 1:
8
+ console.print("[red]Usage: /edit <filename>[/red]")
9
+ return
10
+ filename = args[0]
11
+ if not os.path.isfile(filename):
12
+ console.print(f"[red]File not found:[/red] {filename}")
13
+ return
14
+ port = getattr(shell_state, "termweb_port", None) or runtime_config.get(
15
+ "termweb_port", 8080
16
+ )
17
+ url = f"http://localhost:{port}/?path={filename}"
18
+ console.print(
19
+ f"[green]Opening in browser:[/green] [underline blue]{url}[/underline blue]"
20
+ )
21
+ webbrowser.open(url)
22
+
23
+
24
+ handle_edit.help_text = "Open a file in the browser-based editor"
@@ -0,0 +1,18 @@
1
+ def handle_view(console, args=None, shell_state=None, **kwargs):
2
+ messages = shell_state.conversation_history.get_messages()
3
+ if not messages:
4
+ console.print("[yellow]Conversation history is empty.[/yellow]")
5
+ return
6
+ for i, msg in enumerate(messages, 1):
7
+ role = msg.get("role", "?")
8
+ content = msg.get("content", "")
9
+ tool_calls = msg.get("tool_calls")
10
+ tool_call_id = msg.get("tool_call_id")
11
+ console.print(f"[bold]{i}. {role}:[/bold] {content}")
12
+ if tool_calls:
13
+ console.print(f" [cyan]tool_calls:[/cyan] {tool_calls}")
14
+ if tool_call_id:
15
+ console.print(f" [magenta]tool_call_id:[/magenta] {tool_call_id}")
16
+
17
+
18
+ handle_view.help_text = "Print the current LLM conversation history"
@@ -14,3 +14,6 @@ def handle_lang(console, args=None, **kwargs):
14
14
  console.print(
15
15
  f"[bold green]Idioma alterado para:[/bold green] [cyan]{lang_code}[/cyan]"
16
16
  )
17
+
18
+
19
+ handle_lang.help_text = "Change the interface language (e.g., /lang en)"
@@ -0,0 +1,42 @@
1
+ def handle_livelogs(console, args=None, shell_state=None, **kwargs):
2
+ lines = 20
3
+ if args and len(args) > 0 and str(args[0]).isdigit():
4
+ lines = int(args[0])
5
+ stdout_path = shell_state.termweb_stdout_path if shell_state else None
6
+ stderr_path = shell_state.livereload_stderr_path if shell_state else None
7
+ if not stdout_path and not stderr_path:
8
+ console.print(
9
+ "[yellow][livereload] No livereload log files found for this session.[/yellow]"
10
+ )
11
+ return
12
+ stdout_lines = []
13
+ stderr_lines = []
14
+ if stdout_path:
15
+ try:
16
+ with open(stdout_path, encoding="utf-8") as f:
17
+ stdout_lines = f.readlines()[-lines:]
18
+ if stdout_lines:
19
+ console.print(
20
+ f"[yellow][livereload][stdout] Tail of {stdout_path}:\n"
21
+ + "".join(stdout_lines)
22
+ )
23
+ except Exception as e:
24
+ console.print(f"[red][livereload][stdout] Error: {e}[/red]")
25
+ if stderr_path:
26
+ try:
27
+ with open(stderr_path, encoding="utf-8") as f:
28
+ stderr_lines = f.readlines()[-lines:]
29
+ if stderr_lines:
30
+ console.print(
31
+ f"[red][livereload][stderr] Tail of {stderr_path}:\n"
32
+ + "".join(stderr_lines)
33
+ )
34
+ except Exception as e:
35
+ console.print(f"[red][livereload][stderr] Error: {e}[/red]")
36
+ if (not stdout_path or not stdout_lines) and (not stderr_path or not stderr_lines):
37
+ console.print("[livereload] No output or errors captured in logs.")
38
+
39
+
40
+ handle_livelogs.help_text = (
41
+ "Show live updates from the server log file (default: server.log)"
42
+ )
@@ -1,7 +1,7 @@
1
1
  from janito.agent.runtime_config import runtime_config
2
2
 
3
3
 
4
- def handle_prompt(console, **kwargs):
4
+ def handle_prompt(console, shell_state=None, **kwargs):
5
5
  profile_manager = kwargs.get("profile_manager")
6
6
  prompt = profile_manager.system_prompt_template if profile_manager else None
7
7
  if not prompt and profile_manager:
@@ -9,9 +9,15 @@ def handle_prompt(console, **kwargs):
9
9
  console.print(f"[bold magenta]System Prompt:[/bold magenta]\n{prompt}")
10
10
 
11
11
 
12
- def handle_role(console, *args, **kwargs):
13
- state = kwargs.get("state")
14
- profile_manager = kwargs.get("profile_manager")
12
+ handle_prompt.help_text = "Show the system prompt"
13
+
14
+
15
+ def handle_role(console, args=None, shell_state=None, **kwargs):
16
+ profile_manager = (
17
+ shell_state.profile_manager
18
+ if shell_state and hasattr(shell_state, "profile_manager")
19
+ else kwargs.get("profile_manager")
20
+ )
15
21
  if not args:
16
22
  console.print("[bold red]Usage: /role <new role description>[/bold red]")
17
23
  return
@@ -20,7 +26,7 @@ def handle_role(console, *args, **kwargs):
20
26
  profile_manager.set_role(new_role)
21
27
  # Update system message in conversation
22
28
  found = False
23
- for msg in state["messages"]:
29
+ for msg in shell_state.conversation_history.get_messages():
24
30
  if msg.get("role") == "system":
25
31
  msg["content"] = (
26
32
  profile_manager.system_prompt_template if profile_manager else new_role
@@ -28,7 +34,8 @@ def handle_role(console, *args, **kwargs):
28
34
  found = True
29
35
  break
30
36
  if not found:
31
- state["messages"].insert(0, {"role": "system", "content": new_role})
37
+ if shell_state and hasattr(shell_state, "conversation_history"):
38
+ shell_state.conversation_history.set_system_message(new_role)
32
39
  # Also store the raw role string
33
40
  if profile_manager:
34
41
  setattr(profile_manager, "role_name", new_role)
@@ -36,6 +43,9 @@ def handle_role(console, *args, **kwargs):
36
43
  console.print(f"[bold green]System role updated to:[/bold green] {new_role}")
37
44
 
38
45
 
46
+ handle_role.help_text = "Change the system role"
47
+
48
+
39
49
  def handle_profile(console, *args, **kwargs):
40
50
  """/profile - Show the current and available Agent Profile (only 'base' is supported)"""
41
51
  console.print("[bold green]Current profile:[/bold green] base")
@@ -0,0 +1,35 @@
1
+ def handle_history(console, shell_state=None, *args, **kwargs):
2
+ if shell_state and hasattr(shell_state, "mem_history"):
3
+ input_history = list(shell_state.mem_history.get_strings())
4
+ else:
5
+ input_history = []
6
+ if not args:
7
+ # Default: last 5 inputs
8
+ start = max(0, len(input_history) - 5)
9
+ end = len(input_history)
10
+ elif len(args) == 1:
11
+ count = int(args[0])
12
+ start = max(0, len(input_history) - count)
13
+ end = len(input_history)
14
+ elif len(args) >= 2:
15
+ start = int(args[0])
16
+ end = int(args[1]) + 1 # inclusive
17
+ else:
18
+ start = 0
19
+ end = len(input_history)
20
+
21
+ console.print(
22
+ f"[bold cyan]Showing input history {start} to {end - 1} (total {len(input_history)}):[/bold cyan]"
23
+ )
24
+ for idx, line in enumerate(input_history[start:end], start=start):
25
+ console.print(f"{idx}: {line}")
26
+ if isinstance(line, dict):
27
+ role = line.get("role", "unknown")
28
+ content = line.get("content", "")
29
+ else:
30
+ role = "user"
31
+ content = line
32
+ console.print(f"[bold]{idx} [{role}]:[/bold] {content}")
33
+
34
+
35
+ handle_history.help_text = "Show input history for this session"
@@ -6,9 +6,9 @@ import subprocess
6
6
  def restart_cli():
7
7
  # Clean up prompt_toolkit session if active
8
8
  try:
9
- from janito.cli_chat_shell import chat_loop
9
+ from janito.shell import main
10
10
 
11
- session = getattr(chat_loop, "active_prompt_session", None)
11
+ session = getattr(main, "active_prompt_session", None)
12
12
  if session is not None and hasattr(session, "app"):
13
13
  session.app.exit()
14
14
  except Exception:
@@ -42,6 +42,4 @@ def handle_exit(console, **kwargs):
42
42
  sys.exit(0)
43
43
 
44
44
 
45
- def handle_restart(console, **kwargs):
46
- console.print("[bold yellow]Restarting CLI...[/bold yellow]")
47
- restart_cli()
45
+ handle_exit.help_text = "Exit chat mode"
@@ -14,12 +14,12 @@ def is_termweb_running(port):
14
14
  return False
15
15
 
16
16
 
17
- def handle_termweb_log_tail(console: Console, *args, state=None, **kwargs):
17
+ def handle_termweb_log_tail(console: Console, *args, shell_state=None, **kwargs):
18
18
  lines = 20
19
19
  if args and args[0].isdigit():
20
20
  lines = int(args[0])
21
- stdout_path = state.get("termweb_stdout_path") if state else None
22
- stderr_path = state.get("termweb_stderr_path") if state else None
21
+ stdout_path = shell_state.termweb_stdout_path if shell_state else None
22
+ stderr_path = shell_state.termweb_stderr_path if shell_state else None
23
23
  if not stdout_path and not stderr_path:
24
24
  console.print(
25
25
  "[yellow][termweb] No termweb log files found for this session.[/yellow]"
@@ -51,20 +51,23 @@ def handle_termweb_log_tail(console: Console, *args, state=None, **kwargs):
51
51
  console.print("[termweb] No output or errors captured in logs.")
52
52
 
53
53
 
54
- def handle_termweb_status(console: Console, *args, state=None, **kwargs):
55
- if state is None:
54
+ handle_termweb_log_tail.help_text = "Show the last lines of the latest termweb logs"
55
+
56
+
57
+ def handle_termweb_status(console: Console, *args, shell_state=None, **kwargs):
58
+ if shell_state is None:
56
59
  console.print(
57
60
  "[red]No shell state available. Cannot determine termweb status.[/red]"
58
61
  )
59
62
  return
60
- port = state.get("termweb_port")
61
- port_source = "state"
63
+ port = getattr(shell_state, "termweb_port", None)
64
+ port_source = "shell_state"
62
65
  if not port:
63
66
  port = runtime_config.get("termweb_port")
64
67
  port_source = "runtime_config"
65
- pid = state.get("termweb_pid")
66
- stdout_path = state.get("termweb_stdout_path")
67
- stderr_path = state.get("termweb_stderr_path")
68
+ pid = getattr(shell_state, "termweb_pid", None)
69
+ stdout_path = getattr(shell_state, "termweb_stdout_path", None)
70
+ stderr_path = getattr(shell_state, "termweb_stderr_path", None)
68
71
  running = False
69
72
  if port:
70
73
  running = is_termweb_running(port)
@@ -84,3 +87,8 @@ def handle_termweb_status(console: Console, *args, state=None, **kwargs):
84
87
  console.print(f" Stdout log: {stdout_path}")
85
88
  if stderr_path:
86
89
  console.print(f" Stderr log: {stderr_path}")
90
+
91
+
92
+ handle_termweb_status.help_text = (
93
+ "Show status information about the running termweb server"
94
+ )