janito 1.7.0__py3-none-any.whl → 1.8.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 (115) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/config.py +1 -1
  3. janito/agent/config_defaults.py +2 -2
  4. janito/agent/conversation.py +70 -27
  5. janito/agent/conversation_api.py +104 -4
  6. janito/agent/conversation_exceptions.py +6 -0
  7. janito/agent/conversation_tool_calls.py +17 -3
  8. janito/agent/event.py +24 -0
  9. janito/agent/event_dispatcher.py +24 -0
  10. janito/agent/event_handler_protocol.py +5 -0
  11. janito/agent/event_system.py +15 -0
  12. janito/agent/message_handler.py +4 -1
  13. janito/agent/message_handler_protocol.py +5 -0
  14. janito/agent/openai_client.py +5 -8
  15. janito/agent/openai_schema_generator.py +23 -4
  16. janito/agent/profile_manager.py +15 -83
  17. janito/agent/queued_message_handler.py +22 -3
  18. janito/agent/rich_message_handler.py +66 -72
  19. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +14 -0
  20. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +13 -0
  21. janito/agent/test_handler_protocols.py +47 -0
  22. janito/agent/tests/__init__.py +1 -0
  23. janito/agent/tool_base.py +1 -1
  24. janito/agent/tool_executor.py +109 -0
  25. janito/agent/tool_registry.py +3 -75
  26. janito/agent/tool_use_tracker.py +46 -0
  27. janito/agent/tools/__init__.py +8 -9
  28. janito/agent/tools/ask_user.py +19 -11
  29. janito/agent/tools/create_directory.py +43 -28
  30. janito/agent/tools/create_file.py +60 -29
  31. janito/agent/tools/dir_walk_utils.py +16 -0
  32. janito/agent/tools/fetch_url.py +10 -11
  33. janito/agent/tools/find_files.py +49 -32
  34. janito/agent/tools/get_lines.py +54 -18
  35. janito/agent/tools/memory.py +32 -52
  36. janito/agent/tools/move_file.py +72 -23
  37. janito/agent/tools/outline_file/__init__.py +85 -0
  38. janito/agent/tools/outline_file/formatting.py +20 -0
  39. janito/agent/tools/outline_file/markdown_outline.py +14 -0
  40. janito/agent/tools/outline_file/python_outline.py +71 -0
  41. janito/agent/tools/present_choices.py +62 -0
  42. janito/agent/tools/present_choices_test.py +18 -0
  43. janito/agent/tools/remove_directory.py +31 -26
  44. janito/agent/tools/remove_file.py +31 -13
  45. janito/agent/tools/replace_text_in_file.py +135 -36
  46. janito/agent/tools/run_bash_command.py +47 -50
  47. janito/agent/tools/run_powershell_command.py +52 -36
  48. janito/agent/tools/run_python_command.py +49 -29
  49. janito/agent/tools/search_outline.py +17 -0
  50. janito/agent/tools/search_text.py +208 -0
  51. janito/agent/tools/tools_utils.py +47 -4
  52. janito/agent/tools/utils.py +14 -15
  53. janito/agent/tools/validate_file_syntax.py +163 -0
  54. janito/cli/arg_parser.py +36 -4
  55. janito/cli/logging_setup.py +7 -2
  56. janito/cli/main.py +96 -2
  57. janito/cli/runner/_termweb_log_utils.py +17 -0
  58. janito/cli/runner/cli_main.py +119 -77
  59. janito/cli/runner/config.py +2 -2
  60. janito/cli/termweb_starter.py +73 -0
  61. janito/cli_chat_shell/chat_loop.py +42 -7
  62. janito/cli_chat_shell/chat_state.py +1 -1
  63. janito/cli_chat_shell/chat_ui.py +0 -1
  64. janito/cli_chat_shell/commands/__init__.py +15 -6
  65. janito/cli_chat_shell/commands/{history_reset.py → history_start.py} +13 -5
  66. janito/cli_chat_shell/commands/lang.py +16 -0
  67. janito/cli_chat_shell/commands/prompt.py +42 -0
  68. janito/cli_chat_shell/commands/session_control.py +36 -1
  69. janito/cli_chat_shell/commands/termweb_log.py +86 -0
  70. janito/cli_chat_shell/commands/utility.py +5 -2
  71. janito/cli_chat_shell/commands/verbose.py +29 -0
  72. janito/cli_chat_shell/session_manager.py +9 -1
  73. janito/cli_chat_shell/shell_command_completer.py +20 -0
  74. janito/cli_chat_shell/ui.py +110 -99
  75. janito/i18n/__init__.py +35 -0
  76. janito/i18n/messages.py +23 -0
  77. janito/i18n/pt.py +46 -0
  78. janito/rich_utils.py +43 -43
  79. janito/termweb/app.py +95 -0
  80. janito/termweb/static/editor.html +238 -0
  81. janito/termweb/static/editor.html.bak +238 -0
  82. janito/termweb/static/explorer.html.bak +59 -0
  83. janito/termweb/static/favicon.ico +0 -0
  84. janito/termweb/static/favicon.ico.bak +0 -0
  85. janito/termweb/static/index.html +55 -0
  86. janito/termweb/static/index.html.bak +55 -0
  87. janito/termweb/static/index.html.bak.bak +175 -0
  88. janito/termweb/static/landing.html.bak +36 -0
  89. janito/termweb/static/termicon.svg +1 -0
  90. janito/termweb/static/termweb.css +235 -0
  91. janito/termweb/static/termweb.css.bak +286 -0
  92. janito/termweb/static/termweb.js +187 -0
  93. janito/termweb/static/termweb.js.bak +187 -0
  94. janito/termweb/static/termweb.js.bak.bak +157 -0
  95. janito/termweb/static/termweb_quickopen.js +135 -0
  96. janito/termweb/static/termweb_quickopen.js.bak +125 -0
  97. janito/web/app.py +4 -4
  98. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/METADATA +58 -25
  99. janito-1.8.0.dist-info/RECORD +127 -0
  100. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/WHEEL +1 -1
  101. janito/agent/templates/profiles/system_prompt_template_base.toml +0 -76
  102. janito/agent/templates/profiles/system_prompt_template_default.toml +0 -3
  103. janito/agent/templates/profiles/system_prompt_template_technical.toml +0 -13
  104. janito/agent/tests/test_prompt_toml.py +0 -61
  105. janito/agent/tool_registry_core.py +0 -2
  106. janito/agent/tools/get_file_outline.py +0 -146
  107. janito/agent/tools/py_compile_file.py +0 -40
  108. janito/agent/tools/replace_file.py +0 -51
  109. janito/agent/tools/search_files.py +0 -65
  110. janito/cli/runner/scan.py +0 -57
  111. janito/cli_chat_shell/commands/system.py +0 -73
  112. janito-1.7.0.dist-info/RECORD +0 -89
  113. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/entry_points.txt +0 -0
  114. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/licenses/LICENSE +0 -0
  115. {janito-1.7.0.dist-info → janito-1.8.0.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,35 @@
1
1
  from janito.agent.rich_message_handler import RichMessageHandler
2
- from .chat_state import load_chat_state
2
+ from .chat_state import load_chat_state, save_chat_state
3
3
  from .chat_ui import setup_prompt_session, print_welcome_message
4
4
  from .commands import handle_command
5
5
  from janito.agent.conversation_exceptions import EmptyResponseError, ProviderError
6
6
 
7
+ # Track the active prompt session for cleanup
8
+ active_prompt_session = None
7
9
 
8
- def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
10
+
11
+ def start_chat_shell(
12
+ profile_manager,
13
+ continue_session=False,
14
+ max_rounds=50,
15
+ termweb_stdout_path=None,
16
+ termweb_stderr_path=None,
17
+ ):
18
+ import janito.i18n as i18n
19
+ from janito.agent.runtime_config import runtime_config
20
+
21
+ i18n.set_locale(runtime_config.get("lang", "en"))
22
+ global active_prompt_session
9
23
  agent = profile_manager.agent
10
24
  message_handler = RichMessageHandler()
11
25
  console = message_handler.console
12
26
 
13
27
  # Load state
14
28
  state = load_chat_state(continue_session)
29
+ if termweb_stdout_path:
30
+ state["termweb_stdout_path"] = termweb_stdout_path
31
+ if termweb_stderr_path:
32
+ state["termweb_stderr_path"] = termweb_stderr_path
15
33
  messages = state["messages"]
16
34
  mem_history = state["mem_history"]
17
35
  last_usage_info_ref = {"value": state["last_usage_info"]}
@@ -22,7 +40,10 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
22
40
 
23
41
  if (
24
42
  profile_manager.system_prompt_template
25
- and not runtime_config.get("vanilla_mode", False)
43
+ and (
44
+ not runtime_config.get("vanilla_mode", False)
45
+ or runtime_config.get("system_prompt_template")
46
+ )
26
47
  and not any(m.get("role") == "system" for m in messages)
27
48
  ):
28
49
  messages.insert(0, {"role": "system", "content": agent.system_prompt_template})
@@ -32,10 +53,19 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
32
53
  session = setup_prompt_session(
33
54
  messages, last_usage_info_ref, last_elapsed, mem_history, profile_manager, agent
34
55
  )
56
+ active_prompt_session = session
57
+
58
+ inject_message = state.get("inject_message")
59
+ if "inject_message" in state:
60
+ del state["inject_message"]
35
61
 
36
62
  while True:
37
63
  try:
38
- if state.get("paste_mode"):
64
+ if inject_message is not None:
65
+ user_input = inject_message
66
+ inject_message = None
67
+ was_paste_mode = False
68
+ elif state.get("paste_mode"):
39
69
  console.print("")
40
70
  user_input = session.prompt("Multiline> ", multiline=True)
41
71
  was_paste_mode = True
@@ -44,7 +74,7 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
44
74
  from prompt_toolkit.formatted_text import HTML
45
75
 
46
76
  user_input = session.prompt(
47
- HTML("<prompt>💬 </prompt>"), multiline=False
77
+ HTML("<inputline>💬 </inputline>"), multiline=False
48
78
  )
49
79
  was_paste_mode = False
50
80
  except EOFError:
@@ -55,7 +85,10 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
55
85
  try:
56
86
  confirm = (
57
87
  session.prompt(
58
- HTML("<prompt>Do you really want to exit? (y/n): </prompt>")
88
+ # Use <inputline> for full-line blue background, <prompt> for icon only
89
+ HTML(
90
+ "<inputline>Do you really want to exit? (y/n): </inputline>"
91
+ )
59
92
  )
60
93
  .strip()
61
94
  .lower()
@@ -99,6 +132,8 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
99
132
 
100
133
  start_time = time.time()
101
134
 
135
+ # No need to propagate verbose; ToolExecutor and others fetch from runtime_config
136
+
102
137
  try:
103
138
  response = profile_manager.agent.chat(
104
139
  messages,
@@ -125,4 +160,4 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
125
160
  last_usage_info_ref["value"] = usage
126
161
 
127
162
  # Save conversation and input history
128
- # save_chat_state(messages, mem_history, last_usage_info)
163
+ save_chat_state(messages, mem_history, last_usage_info_ref["value"])
@@ -9,7 +9,7 @@ from prompt_toolkit.history import InMemoryHistory
9
9
 
10
10
  def load_chat_state(continue_session: bool):
11
11
  messages = []
12
- last_usage_info = None
12
+ last_usage_info = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
13
13
  last_elapsed = None
14
14
  history_list = load_input_history()
15
15
  mem_history = InMemoryHistory()
@@ -32,7 +32,6 @@ def setup_prompt_session(
32
32
  )
33
33
  else (runtime_config.get("role") or effective_config.get("role"))
34
34
  ),
35
- style_ref=lambda: getattr(profile_manager, "interaction_style", "default"),
36
35
  ),
37
36
  mem_history,
38
37
  )
@@ -1,14 +1,19 @@
1
1
  from .session import handle_continue, handle_history
2
- from .system import handle_system, handle_role, handle_style
2
+ from .prompt import handle_prompt, handle_role
3
3
  from .session_control import handle_exit, handle_restart
4
4
  from .utility import handle_help, handle_clear, handle_multi
5
+ from .termweb_log import handle_termweb_log_tail, handle_termweb_status
5
6
  from .sum import handle_sum
6
7
  from .config import handle_reload
7
- from .history_reset import handle_reset
8
+ from .history_start import handle_start
8
9
  from ..config_shell import handle_config_shell
10
+ from .verbose import handle_verbose
11
+ from .lang import handle_lang
9
12
  from janito.agent.runtime_config import runtime_config
10
13
 
11
14
  COMMAND_HANDLERS = {
15
+ "/termweb-logs": handle_termweb_log_tail,
16
+ "/termweb-status": handle_termweb_status,
12
17
  "/history": handle_history,
13
18
  "/continue": handle_continue,
14
19
  "/exit": handle_exit,
@@ -16,20 +21,23 @@ COMMAND_HANDLERS = {
16
21
  "/restart": handle_restart,
17
22
  "/help": handle_help,
18
23
  "/multi": handle_multi,
19
- "/system": handle_system,
24
+ "/prompt": handle_prompt,
25
+ "/verbose": handle_verbose,
20
26
  }
21
27
 
22
28
  if not runtime_config.get("vanilla_mode", False):
23
29
  COMMAND_HANDLERS["/role"] = handle_role
24
30
 
31
+
32
+ COMMAND_HANDLERS["/lang"] = handle_lang
33
+
25
34
  COMMAND_HANDLERS.update(
26
35
  {
27
36
  "/sum": handle_sum,
28
37
  "/clear": handle_clear,
29
- "/reset": handle_reset,
38
+ "/start": handle_start,
30
39
  "/config": handle_config_shell,
31
40
  "/reload": handle_reload,
32
- "/style": handle_style,
33
41
  }
34
42
  )
35
43
 
@@ -40,7 +48,8 @@ def handle_command(command, console, **kwargs):
40
48
  args = parts[1:]
41
49
  handler = COMMAND_HANDLERS.get(cmd)
42
50
  if handler:
43
- return handler(console, *args, **kwargs)
51
+ # Pass args as a keyword argument for handlers that expect it
52
+ return handler(console, args=args, **kwargs)
44
53
  console.print(
45
54
  f"[bold red]Invalid command: {cmd}. Type /help for a list of commands.[/bold red]"
46
55
  )
@@ -2,14 +2,22 @@ from prompt_toolkit.history import InMemoryHistory
2
2
  import os
3
3
 
4
4
 
5
- def handle_reset(console, state, **kwargs):
5
+ def handle_start(console, state, **kwargs):
6
+
6
7
  save_path = os.path.join(".janito", "last_conversation.json")
7
8
 
9
+ # Clear the terminal screen
10
+ os.system("cls" if os.name == "nt" else "clear")
11
+
8
12
  # Clear in-memory conversation and prompt history
9
13
  state["messages"].clear()
10
14
  state["history_list"].clear()
11
15
  state["mem_history"] = InMemoryHistory()
12
- state["last_usage_info"] = None
16
+ state["last_usage_info"] = {
17
+ "prompt_tokens": 0,
18
+ "completion_tokens": 0,
19
+ "total_tokens": 0,
20
+ }
13
21
  state["last_elapsed"] = None
14
22
 
15
23
  # Delete saved conversation file if exists
@@ -23,7 +31,7 @@ def handle_reset(console, state, **kwargs):
23
31
  console.print(
24
32
  f"[bold red]Failed to delete saved conversation:[/bold red] {e}"
25
33
  )
26
- else:
27
- console.print("[bold yellow]No saved conversation to delete.[/bold yellow]")
28
34
 
29
- console.print("[bold green]Conversation history has been reset.[/bold green]")
35
+ console.print(
36
+ "[bold green]Conversation history has been started (context reset).[/bold green]"
37
+ )
@@ -0,0 +1,16 @@
1
+ from janito.agent.runtime_config import runtime_config
2
+ import janito.i18n as i18n
3
+
4
+
5
+ def handle_lang(console, args=None, **kwargs):
6
+ if not args or len(args) == 0:
7
+ console.print(
8
+ "[bold yellow]Uso: /lang [código_idioma] (ex: pt, en, es)[/bold yellow]"
9
+ )
10
+ return
11
+ lang_code = args[0]
12
+ runtime_config.set("lang", lang_code)
13
+ i18n.set_locale(lang_code)
14
+ console.print(
15
+ f"[bold green]Idioma alterado para:[/bold green] [cyan]{lang_code}[/cyan]"
16
+ )
@@ -0,0 +1,42 @@
1
+ from janito.agent.runtime_config import runtime_config
2
+
3
+
4
+ def handle_prompt(console, **kwargs):
5
+ profile_manager = kwargs.get("profile_manager")
6
+ prompt = profile_manager.system_prompt_template if profile_manager else None
7
+ if not prompt and profile_manager:
8
+ prompt = profile_manager.system_prompt_template
9
+ console.print(f"[bold magenta]System Prompt:[/bold magenta]\n{prompt}")
10
+
11
+
12
+ def handle_role(console, *args, **kwargs):
13
+ state = kwargs.get("state")
14
+ profile_manager = kwargs.get("profile_manager")
15
+ if not args:
16
+ console.print("[bold red]Usage: /role <new role description>[/bold red]")
17
+ return
18
+ new_role = " ".join(args)
19
+ if profile_manager:
20
+ profile_manager.set_role(new_role)
21
+ # Update system message in conversation
22
+ found = False
23
+ for msg in state["messages"]:
24
+ if msg.get("role") == "system":
25
+ msg["content"] = (
26
+ profile_manager.system_prompt_template if profile_manager else new_role
27
+ )
28
+ found = True
29
+ break
30
+ if not found:
31
+ state["messages"].insert(0, {"role": "system", "content": new_role})
32
+ # Also store the raw role string
33
+ if profile_manager:
34
+ setattr(profile_manager, "role_name", new_role)
35
+ runtime_config.set("role", new_role)
36
+ console.print(f"[bold green]System role updated to:[/bold green] {new_role}")
37
+
38
+
39
+ def handle_profile(console, *args, **kwargs):
40
+ """/profile - Show the current and available Agent Profile (only 'base' is supported)"""
41
+ console.print("[bold green]Current profile:[/bold green] base")
42
+ console.print("[bold yellow]Available profiles:[/bold yellow]\n- base")
@@ -1,5 +1,40 @@
1
1
  import os
2
2
  import sys
3
+ import subprocess
4
+
5
+
6
+ def restart_cli():
7
+ # Clean up prompt_toolkit session if active
8
+ try:
9
+ from janito.cli_chat_shell import chat_loop
10
+
11
+ session = getattr(chat_loop, "active_prompt_session", None)
12
+ if session is not None and hasattr(session, "app"):
13
+ session.app.exit()
14
+ except Exception:
15
+ pass # Ignore cleanup errors
16
+
17
+ if os.name == "nt":
18
+ if (
19
+ "powershell" in os.environ.get("SHELL", "").lower()
20
+ or "pwsh" in sys.executable.lower()
21
+ ):
22
+ args = [
23
+ "powershell",
24
+ "-Command",
25
+ "Start-Process",
26
+ sys.executable,
27
+ "-ArgumentList",
28
+ "'-m','janito"
29
+ + ("','" + "','".join(sys.argv[1:]) if sys.argv[1:] else "")
30
+ + "'",
31
+ ]
32
+ subprocess.Popen(args)
33
+ else:
34
+ subprocess.Popen([sys.executable, "-m", "janito"] + sys.argv[1:])
35
+ sys.exit(0)
36
+ else:
37
+ os.execv(sys.executable, [sys.executable, "-m", "janito"] + sys.argv[1:])
3
38
 
4
39
 
5
40
  def handle_exit(console, **kwargs):
@@ -9,4 +44,4 @@ def handle_exit(console, **kwargs):
9
44
 
10
45
  def handle_restart(console, **kwargs):
11
46
  console.print("[bold yellow]Restarting CLI...[/bold yellow]")
12
- os.execv(sys.executable, [sys.executable, "-m", "janito"] + sys.argv[1:])
47
+ restart_cli()
@@ -0,0 +1,86 @@
1
+ import http.client
2
+ from rich.console import Console
3
+ from janito.agent.runtime_config import runtime_config
4
+
5
+
6
+ def is_termweb_running(port):
7
+ """Check if termweb is running by making an HTTP request to the root endpoint."""
8
+ try:
9
+ conn = http.client.HTTPConnection("localhost", port, timeout=0.5)
10
+ conn.request("GET", "/")
11
+ resp = conn.getresponse()
12
+ return resp.status == 200
13
+ except Exception:
14
+ return False
15
+
16
+
17
+ def handle_termweb_log_tail(console: Console, *args, state=None, **kwargs):
18
+ lines = 20
19
+ if args and args[0].isdigit():
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
23
+ if not stdout_path and not stderr_path:
24
+ console.print(
25
+ "[yellow][termweb] No termweb log files found for this session.[/yellow]"
26
+ )
27
+ return
28
+ if stdout_path:
29
+ try:
30
+ with open(stdout_path, encoding="utf-8") as f:
31
+ stdout_lines = f.readlines()[-lines:]
32
+ if stdout_lines:
33
+ console.print(
34
+ f"[yellow][termweb][stdout] Tail of {stdout_path}:\n"
35
+ + "".join(stdout_lines)
36
+ )
37
+ except Exception:
38
+ pass
39
+ if stderr_path:
40
+ try:
41
+ with open(stderr_path, encoding="utf-8") as f:
42
+ stderr_lines = f.readlines()[-lines:]
43
+ if stderr_lines:
44
+ console.print(
45
+ f"[red][termweb][stderr] Tail of {stderr_path}:\n"
46
+ + "".join(stderr_lines)
47
+ )
48
+ except Exception:
49
+ pass
50
+ if (not stdout_path or not stdout_lines) and (not stderr_path or not stderr_lines):
51
+ console.print("[termweb] No output or errors captured in logs.")
52
+
53
+
54
+ def handle_termweb_status(console: Console, *args, state=None, **kwargs):
55
+ if state is None:
56
+ console.print(
57
+ "[red]No shell state available. Cannot determine termweb status.[/red]"
58
+ )
59
+ return
60
+ port = state.get("termweb_port")
61
+ port_source = "state"
62
+ if not port:
63
+ port = runtime_config.get("termweb_port")
64
+ 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
+ running = False
69
+ if port:
70
+ running = is_termweb_running(port)
71
+ console.print("[bold cyan]TermWeb Server Status:[/bold cyan]")
72
+ console.print(f" Running: {'[green]Yes[/green]' if running else '[red]No[/red]'}")
73
+ if pid:
74
+ console.print(f" PID: {pid}")
75
+ if port:
76
+ console.print(f" Port: {port} (from {port_source})")
77
+ url = f"http://localhost:{port}/"
78
+ console.print(f" URL: [underline blue]{url}[/underline blue]")
79
+ else:
80
+ console.print(
81
+ " [yellow]No port configured in state or runtime_config.[/yellow]"
82
+ )
83
+ if stdout_path:
84
+ console.print(f" Stdout log: {stdout_path}")
85
+ if stderr_path:
86
+ console.print(f" Stderr log: {stderr_path}")
@@ -6,12 +6,15 @@ def handle_help(console, **kwargs):
6
6
  /restart - Restart the CLI
7
7
  /help - Show this help message
8
8
  /continue - Restore last saved conversation
9
- /reset - Reset conversation history
10
- /system - Show the system prompt
9
+ /start - Reset conversation history
10
+ /prompt - Show the system prompt
11
11
  /role - Change the system role
12
12
  /clear - Clear the terminal screen
13
13
  /multi - Provide multiline input as next message
14
14
  /config - Show or set configuration (see: /config show, /config set local|global key=value)
15
+ /termweb-logs - Show the last lines of the latest termweb logs
16
+ /termweb-status - Show status information about the running termweb server
17
+ /verbose [on|off] - Show or set verbose mode for this session
15
18
  """
16
19
  )
17
20
 
@@ -0,0 +1,29 @@
1
+ from janito.agent.runtime_config import runtime_config
2
+
3
+
4
+ def handle_verbose(console, state, **kwargs):
5
+ """
6
+ /verbose [on|off]
7
+ Shows or sets verbose mode for the current shell session.
8
+ """
9
+ args = kwargs.get("args", [])
10
+ verbose = runtime_config.get("verbose", False)
11
+ if not args:
12
+ status = "ON" if verbose else "OFF"
13
+ console.print(
14
+ f"[bold green]/verbose:[/bold green] Verbose mode is currently [bold]{status}[/bold]."
15
+ )
16
+ return
17
+ arg = args[0].lower()
18
+ if arg == "on":
19
+ runtime_config["verbose"] = True
20
+ console.print(
21
+ "[bold green]/verbose:[/bold green] Verbose mode is now [bold]ON[/bold]."
22
+ )
23
+ elif arg == "off":
24
+ runtime_config["verbose"] = False
25
+ console.print(
26
+ "[bold green]/verbose:[/bold green] Verbose mode is now [bold]OFF[/bold]."
27
+ )
28
+ else:
29
+ console.print("[bold red]Usage:[/bold red] /verbose [on|off]")
@@ -27,8 +27,16 @@ def save_conversation(
27
27
  ):
28
28
  os.makedirs(os.path.dirname(path), exist_ok=True)
29
29
  data = {"messages": messages, "prompts": prompts, "last_usage_info": usage_info}
30
+
31
+ def usage_serializer(obj):
32
+ if hasattr(obj, "to_dict"):
33
+ return obj.to_dict()
34
+ if hasattr(obj, "__dict__"):
35
+ return obj.__dict__
36
+ return str(obj)
37
+
30
38
  with open(path, "w", encoding="utf-8") as f:
31
- json.dump(data, f, indent=2)
39
+ json.dump(data, f, indent=2, default=usage_serializer)
32
40
 
33
41
 
34
42
  def load_input_history():
@@ -0,0 +1,20 @@
1
+ from prompt_toolkit.completion import Completer, Completion
2
+
3
+
4
+ class ShellCommandCompleter(Completer):
5
+ def __init__(self):
6
+ # Import here to avoid circular import at module level
7
+ from janito.cli_chat_shell.commands import COMMAND_HANDLERS
8
+
9
+ # Only commands starting with '/'
10
+ self.commands = sorted(
11
+ [cmd for cmd in COMMAND_HANDLERS.keys() if cmd.startswith("/")]
12
+ )
13
+
14
+ def get_completions(self, document, complete_event):
15
+ text = document.text_before_cursor
16
+ if text.startswith("/"):
17
+ prefix = text[1:]
18
+ for cmd in self.commands:
19
+ if cmd[1:].startswith(prefix):
20
+ yield Completion(cmd, start_position=-(len(prefix) + 1))