janito 1.8.0__py3-none-any.whl → 1.9.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 (119) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/config_defaults.py +23 -0
  3. janito/agent/config_utils.py +0 -9
  4. janito/agent/conversation.py +31 -9
  5. janito/agent/conversation_api.py +32 -2
  6. janito/agent/conversation_history.py +53 -0
  7. janito/agent/conversation_tool_calls.py +11 -8
  8. janito/agent/openai_client.py +11 -3
  9. janito/agent/openai_schema_generator.py +9 -6
  10. janito/agent/providers.py +77 -0
  11. janito/agent/rich_message_handler.py +1 -1
  12. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +8 -8
  13. janito/agent/tool_executor.py +18 -10
  14. janito/agent/tool_use_tracker.py +16 -0
  15. janito/agent/tools/__init__.py +7 -9
  16. janito/agent/tools/create_directory.py +7 -6
  17. janito/agent/tools/create_file.py +29 -54
  18. janito/agent/tools/delete_text_in_file.py +97 -0
  19. janito/agent/tools/fetch_url.py +11 -3
  20. janito/agent/tools/find_files.py +37 -25
  21. janito/agent/tools/get_file_outline/__init__.py +1 -0
  22. janito/agent/tools/{outline_file/__init__.py → get_file_outline/core.py} +12 -15
  23. janito/agent/tools/get_file_outline/python_outline.py +134 -0
  24. janito/agent/tools/{search_outline.py → get_file_outline/search_outline.py} +9 -0
  25. janito/agent/tools/get_lines.py +15 -11
  26. janito/agent/tools/move_file.py +10 -11
  27. janito/agent/tools/remove_directory.py +2 -2
  28. janito/agent/tools/remove_file.py +11 -13
  29. janito/agent/tools/replace_file.py +62 -0
  30. janito/agent/tools/replace_text_in_file.py +3 -3
  31. janito/agent/tools/run_bash_command.py +3 -7
  32. janito/agent/tools/run_powershell_command.py +39 -28
  33. janito/agent/tools/run_python_command.py +3 -5
  34. janito/agent/tools/search_text.py +10 -14
  35. janito/agent/tools/validate_file_syntax/__init__.py +1 -0
  36. janito/agent/tools/validate_file_syntax/core.py +92 -0
  37. janito/agent/tools/validate_file_syntax/css_validator.py +35 -0
  38. janito/agent/tools/validate_file_syntax/html_validator.py +77 -0
  39. janito/agent/tools/validate_file_syntax/js_validator.py +27 -0
  40. janito/agent/tools/validate_file_syntax/json_validator.py +6 -0
  41. janito/agent/tools/validate_file_syntax/markdown_validator.py +66 -0
  42. janito/agent/tools/validate_file_syntax/ps1_validator.py +32 -0
  43. janito/agent/tools/validate_file_syntax/python_validator.py +5 -0
  44. janito/agent/tools/validate_file_syntax/xml_validator.py +11 -0
  45. janito/agent/tools/validate_file_syntax/yaml_validator.py +6 -0
  46. janito/agent/tools_utils/__init__.py +1 -0
  47. janito/agent/tools_utils/dir_walk_utils.py +23 -0
  48. janito/agent/{tools/outline_file → tools_utils}/formatting.py +5 -2
  49. janito/agent/{tools → tools_utils}/gitignore_utils.py +0 -3
  50. janito/agent/tools_utils/utils.py +30 -0
  51. janito/cli/_livereload_log_utils.py +13 -0
  52. janito/cli/arg_parser.py +45 -3
  53. janito/cli/{runner/cli_main.py → cli_main.py} +120 -20
  54. janito/cli/livereload_starter.py +60 -0
  55. janito/cli/main.py +110 -21
  56. janito/cli/one_shot.py +66 -0
  57. janito/cli/termweb_starter.py +2 -2
  58. janito/livereload/app.py +25 -0
  59. janito/rich_utils.py +0 -22
  60. janito/{cli_chat_shell → shell}/commands/__init__.py +18 -11
  61. janito/{cli_chat_shell → shell}/commands/config.py +4 -4
  62. janito/shell/commands/conversation_restart.py +72 -0
  63. janito/shell/commands/edit.py +21 -0
  64. janito/shell/commands/history_view.py +18 -0
  65. janito/shell/commands/livelogs.py +40 -0
  66. janito/{cli_chat_shell → shell}/commands/prompt.py +10 -6
  67. janito/shell/commands/session.py +32 -0
  68. janito/{cli_chat_shell → shell}/commands/session_control.py +2 -7
  69. janito/{cli_chat_shell → shell}/commands/sum.py +6 -6
  70. janito/{cli_chat_shell → shell}/commands/termweb_log.py +10 -10
  71. janito/shell/commands/tools.py +23 -0
  72. janito/{cli_chat_shell → shell}/commands/utility.py +5 -4
  73. janito/{cli_chat_shell → shell}/commands/verbose.py +1 -1
  74. janito/shell/commands.py +40 -0
  75. janito/shell/main.py +321 -0
  76. janito/{cli_chat_shell/shell_command_completer.py → shell/prompt/completer.py} +1 -1
  77. janito/{cli_chat_shell/chat_ui.py → shell/prompt/session_setup.py} +19 -5
  78. janito/{cli_chat_shell/session_manager.py → shell/session/manager.py} +53 -3
  79. janito/{cli_chat_shell/ui.py → shell/ui/interactive.py} +23 -15
  80. janito/termweb/app.py +3 -3
  81. janito/termweb/static/editor.css +146 -0
  82. janito/termweb/static/editor.css.bak +27 -0
  83. janito/termweb/static/editor.html +15 -213
  84. janito/termweb/static/editor.html.bak +16 -215
  85. janito/termweb/static/editor.js +209 -0
  86. janito/termweb/static/editor.js.bak +227 -0
  87. janito/termweb/static/index.html +2 -3
  88. janito/termweb/static/index.html.bak +2 -3
  89. janito/termweb/static/termweb.css.bak +33 -84
  90. janito/termweb/static/termweb.js +15 -34
  91. janito/termweb/static/termweb.js.bak +18 -36
  92. {janito-1.8.0.dist-info → janito-1.9.0.dist-info}/METADATA +6 -3
  93. janito-1.9.0.dist-info/RECORD +151 -0
  94. {janito-1.8.0.dist-info → janito-1.9.0.dist-info}/WHEEL +1 -1
  95. janito/agent/tools/dir_walk_utils.py +0 -16
  96. janito/agent/tools/memory.py +0 -48
  97. janito/agent/tools/outline_file/python_outline.py +0 -71
  98. janito/agent/tools/present_choices_test.py +0 -18
  99. janito/agent/tools/rich_live.py +0 -44
  100. janito/agent/tools/tools_utils.py +0 -56
  101. janito/agent/tools/utils.py +0 -33
  102. janito/agent/tools/validate_file_syntax.py +0 -163
  103. janito/cli_chat_shell/chat_loop.py +0 -163
  104. janito/cli_chat_shell/chat_state.py +0 -38
  105. janito/cli_chat_shell/commands/history_start.py +0 -37
  106. janito/cli_chat_shell/commands/session.py +0 -48
  107. janito-1.8.0.dist-info/RECORD +0 -127
  108. /janito/agent/tools/{outline_file → get_file_outline}/markdown_outline.py +0 -0
  109. /janito/cli/{runner/_termweb_log_utils.py → _termweb_log_utils.py} +0 -0
  110. /janito/cli/{runner/config.py → config_runner.py} +0 -0
  111. /janito/cli/{runner/formatting.py → formatting_runner.py} +0 -0
  112. /janito/{cli/runner → shell}/__init__.py +0 -0
  113. /janito/{cli_chat_shell → shell}/commands/lang.py +0 -0
  114. /janito/{cli_chat_shell → shell/prompt}/load_prompt.py +0 -0
  115. /janito/{cli_chat_shell/config_shell.py → shell/session/config.py} +0 -0
  116. /janito/{cli_chat_shell/__init__.py → shell/session/history.py} +0 -0
  117. {janito-1.8.0.dist-info → janito-1.9.0.dist-info}/entry_points.txt +0 -0
  118. {janito-1.8.0.dist-info → janito-1.9.0.dist-info}/licenses/LICENSE +0 -0
  119. {janito-1.8.0.dist-info → janito-1.9.0.dist-info}/top_level.txt +0 -0
janito/cli/main.py CHANGED
@@ -3,8 +3,9 @@
3
3
  from janito.cli.arg_parser import create_parser
4
4
  from janito.cli.config_commands import handle_config_commands
5
5
  from janito.cli.logging_setup import setup_verbose_logging
6
- from janito.cli.runner.cli_main import run_cli
6
+ from janito.cli.cli_main import run_cli
7
7
  from janito.agent.runtime_config import unified_config
8
+ from janito.cli.livereload_starter import start_livereload
8
9
 
9
10
  # Ensure all tools are registered at startup
10
11
  import janito.agent.tools # noqa: F401
@@ -25,6 +26,77 @@ def main():
25
26
  parser = create_parser()
26
27
  args = parser.parse_args()
27
28
 
29
+ # Handle --set-provider-config <name> <key> <value>
30
+ if getattr(args, "set_provider_config", None) is not None:
31
+ import os
32
+ import json
33
+
34
+ name, key, value = args.set_provider_config
35
+ config_dir = os.path.expanduser("~/.janito")
36
+ os.makedirs(config_dir, exist_ok=True)
37
+ providers_path = os.path.join(config_dir, "providers.json")
38
+
39
+ # Load or initialize providers config
40
+ if os.path.exists(providers_path):
41
+ with open(providers_path, "r", encoding="utf-8") as f:
42
+ try:
43
+ providers = json.load(f)
44
+ except Exception:
45
+ providers = {}
46
+ else:
47
+ providers = {}
48
+
49
+ if name not in providers or not isinstance(providers[name], dict):
50
+ providers[name] = {}
51
+ providers[name][key] = value
52
+
53
+ with open(providers_path, "w", encoding="utf-8") as f:
54
+ json.dump(providers, f, indent=2)
55
+
56
+ print(f"Set {key} for provider '{name}' in {providers_path}.")
57
+ sys.exit(0)
58
+
59
+ # Handle --list [n] before anything else
60
+ if getattr(args, "list", None) is not None:
61
+ import os
62
+ import glob
63
+
64
+ n = args.list if args.list is not None else 10
65
+ history_dir = os.path.join(os.path.expanduser(".janito"), "chat_history")
66
+ if not os.path.exists(history_dir):
67
+ print("No session history found.")
68
+ sys.exit(0)
69
+ files = glob.glob(os.path.join(history_dir, "*.json"))
70
+ files = sorted(files, key=os.path.getmtime, reverse=True)
71
+ print(f"Last {n} sessions:")
72
+ for f in files[:n]:
73
+ session_id = os.path.splitext(os.path.basename(f))[0]
74
+ print(session_id)
75
+ sys.exit(0)
76
+
77
+ # Handle --view <id> to print conversation history
78
+ if getattr(args, "view", None) is not None:
79
+ import os
80
+ import json
81
+
82
+ history_dir = os.path.join(os.path.expanduser(".janito"), "chat_history")
83
+ session_file = os.path.join(history_dir, f"{args.view}.json")
84
+ if not os.path.exists(session_file):
85
+ print(f"Session '{args.view}' not found.")
86
+ sys.exit(1)
87
+ with open(session_file, "r", encoding="utf-8") as f:
88
+ try:
89
+ messages = json.load(f)
90
+ except Exception as e:
91
+ print(f"Failed to load session: {e}")
92
+ sys.exit(1)
93
+ print(f"Conversation history for session '{args.view}':\n")
94
+ for i, msg in enumerate(messages, 1):
95
+ role = msg.get("role", "?")
96
+ content = msg.get("content", "")
97
+ print(f"[{i}] {role}: {content}\n")
98
+ sys.exit(0)
99
+
28
100
  # Seleção de idioma: prioridade --lang > config.json > padrão
29
101
  lang = getattr(args, "lang", None) or unified_config.get("lang", None) or "en"
30
102
  runtime_config.set("lang", lang)
@@ -72,37 +144,31 @@ def main():
72
144
  sys.exit(0)
73
145
 
74
146
  if getattr(args, "info", False):
75
- # (mantém bloco info)
76
-
77
- print("Janito - Agente CLI de automação")
78
- print(f"Modelo: {unified_config.get('model')}")
79
- print(f"Temperatura: {unified_config.get('temperature')}")
80
- print(f"Max tokens: {unified_config.get('max_tokens')}")
81
- # System prompt real via AgentProfileManager
82
- # Prioridade: --system-file > --system > AgentProfileManager
147
+ # Compact, colored, single-line info output using rich
148
+ from janito import __version__
149
+ from rich.console import Console
150
+ from rich.text import Text
83
151
  from janito.agent.runtime_config import runtime_config
84
152
 
153
+ model = unified_config.get("model")
154
+ temperature = unified_config.get("temperature")
155
+ max_tokens = unified_config.get("max_tokens")
85
156
  system_prompt_val = None
86
- origem = None
87
157
  if getattr(args, "system_file", None):
88
158
  try:
89
159
  with open(args.system_file, "r", encoding="utf-8") as f:
90
160
  system_prompt_val = f.read().strip()
91
161
  runtime_config.set("system_prompt_template", system_prompt_val)
92
- origem = "--system-file"
93
162
  except Exception as e:
94
- print(f"System prompt: (error reading system-file: {e})")
163
+ system_prompt_val = f"(error reading system-file: {e})"
95
164
  elif getattr(args, "system", None):
96
165
  system_prompt_val = args.system
97
166
  runtime_config.set("system_prompt_template", system_prompt_val)
98
- origem = "--system"
99
167
  else:
100
168
  system_prompt_val = runtime_config.get("system_prompt_template")
101
- if system_prompt_val:
102
- origem = "runtime_config"
103
- if system_prompt_val:
104
- print(f"System prompt ({origem or 'runtime_config'}): {system_prompt_val}")
105
- else:
169
+ # if system_prompt_val:
170
+ # origem = "runtime_config"
171
+ if not system_prompt_val:
106
172
  try:
107
173
  from janito.agent.profile_manager import AgentProfileManager
108
174
  from janito.agent.config import get_api_key
@@ -119,10 +185,22 @@ def main():
119
185
  system_prompt_val = profile_manager.get_system_prompt(
120
186
  role, interaction_mode, profile
121
187
  )
122
- print(f"System prompt (profile_manager): {system_prompt_val}")
123
188
  except Exception as e:
124
- print(f"System prompt: (error obtaining from profile_manager: {e})")
125
- sys.exit(0)
189
+ system_prompt_val = f"(error: {e})"
190
+
191
+ console = Console()
192
+ info_text = Text()
193
+ info_text.append(f"Janito v{__version__}", style="bold cyan")
194
+ info_text.append(" | model: ", style="white")
195
+ info_text.append(str(model), style="green")
196
+ info_text.append(" | temp: ", style="white")
197
+ info_text.append(str(temperature), style="yellow")
198
+ info_text.append(" | max_tokens: ", style="white")
199
+ info_text.append(str(max_tokens), style="magenta")
200
+ info_text.append(" | system: ", style="white")
201
+ info_text.append(str(system_prompt_val), style="bold blue")
202
+ console.print(info_text, style="dim")
203
+ # Previously: sys.exit(0) would exit after showing info. Now, program continues after displaying info.
126
204
 
127
205
  # ... resto do main ...
128
206
  handle_config_commands(args)
@@ -131,5 +209,16 @@ def main():
131
209
  import subprocess # Only needed if launching web
132
210
 
133
211
  subprocess.run([sys.executable, "-m", "janito.web"])
212
+ elif getattr(args, "live", False):
213
+ port = 35729 # Default livereload port
214
+ livereload_proc, started, livereload_stdout_path, livereload_stderr_path = (
215
+ start_livereload(port)
216
+ )
217
+ try:
218
+ run_cli(args)
219
+ finally:
220
+ if livereload_proc:
221
+ livereload_proc.terminate()
222
+ livereload_proc.wait()
134
223
  else:
135
224
  run_cli(args)
janito/cli/one_shot.py ADDED
@@ -0,0 +1,66 @@
1
+ from janito.agent.conversation_exceptions import (
2
+ MaxRoundsExceededError,
3
+ ProviderError,
4
+ EmptyResponseError,
5
+ )
6
+
7
+
8
+ def run_oneshot_mode(args, profile_manager, runtime_config):
9
+ prompt = getattr(args, "input_arg", None)
10
+ from rich.console import Console
11
+ from janito.agent.rich_message_handler import RichMessageHandler
12
+
13
+ console = Console()
14
+ message_handler = RichMessageHandler()
15
+ messages = []
16
+ system_prompt_override = runtime_config.get("system_prompt_template")
17
+ if system_prompt_override:
18
+ if not runtime_config.get("vanilla_mode", False) or getattr(
19
+ args, "system", None
20
+ ):
21
+ messages.append({"role": "system", "content": system_prompt_override})
22
+ elif profile_manager.system_prompt_template and not runtime_config.get(
23
+ "vanilla_mode", False
24
+ ):
25
+ messages.append(
26
+ {"role": "system", "content": profile_manager.system_prompt_template}
27
+ )
28
+ messages.append({"role": "user", "content": prompt})
29
+ import time
30
+
31
+ info_start_time = None
32
+ if getattr(args, "info", False):
33
+ info_start_time = time.time()
34
+ try:
35
+ max_rounds = 100
36
+ from janito.agent.conversation_history import ConversationHistory
37
+
38
+ result = profile_manager.agent.chat(
39
+ ConversationHistory(messages),
40
+ message_handler=message_handler,
41
+ spinner=True,
42
+ max_rounds=max_rounds,
43
+ stream=getattr(args, "stream", False),
44
+ )
45
+ if (
46
+ getattr(args, "info", False)
47
+ and info_start_time is not None
48
+ and result is not None
49
+ ):
50
+ usage_info = result.get("usage")
51
+ total_tokens = usage_info.get("total_tokens") if usage_info else None
52
+ prompt_tokens = usage_info.get("prompt_tokens") if usage_info else None
53
+ completion_tokens = (
54
+ usage_info.get("completion_tokens") if usage_info else None
55
+ )
56
+ elapsed = time.time() - info_start_time
57
+ console.print(
58
+ 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]",
59
+ style="dim",
60
+ )
61
+ except MaxRoundsExceededError:
62
+ console.print("[red]Max conversation rounds exceeded.[/red]")
63
+ except ProviderError as e:
64
+ console.print(f"[red]Provider error:[/red] {e}")
65
+ except EmptyResponseError as e:
66
+ console.print(f"[red]Error:[/red] {e}")
@@ -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
@@ -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,23 +2,13 @@
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
8
6
 
9
7
 
10
- def print_markdown(console: Console, message: str):
11
- console.print(Markdown(message))
12
-
13
-
14
8
  def print_info(console: Console, message: str):
15
9
  console.print(message, style="cyan", end="")
16
10
 
17
11
 
18
- def print_success(console: Console, message: str):
19
- console.print(message, style="bold green", end="\n")
20
-
21
-
22
12
  def print_error(console: Console, message: str):
23
13
  console.print(message, style="bold red", end="\n")
24
14
 
@@ -29,15 +19,3 @@ def print_warning(console: Console, message: str):
29
19
 
30
20
  def print_magenta(console: Console, message: str):
31
21
  console.print(message, style="magenta", end="\n")
32
-
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
- )
@@ -1,27 +1,34 @@
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
8
+ from .livelogs import handle_livelogs
6
9
  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
10
+ from .edit import handle_edit
11
+
12
+ from .history_view import handle_view
13
+ from janito.shell.session.config import handle_config_shell
10
14
  from .verbose import handle_verbose
11
15
  from .lang import handle_lang
12
16
  from janito.agent.runtime_config import runtime_config
13
17
 
14
18
  COMMAND_HANDLERS = {
15
19
  "/termweb-logs": handle_termweb_log_tail,
20
+ "/livelogs": handle_livelogs,
16
21
  "/termweb-status": handle_termweb_status,
22
+ "/edit": handle_edit,
17
23
  "/history": handle_history,
18
- "/continue": handle_continue,
19
24
  "/exit": handle_exit,
20
25
  "exit": handle_exit,
21
26
  "/restart": handle_restart,
27
+ "/start": handle_restart,
22
28
  "/help": handle_help,
23
29
  "/multi": handle_multi,
24
30
  "/prompt": handle_prompt,
31
+ "/tools": handle_tools,
25
32
  "/verbose": handle_verbose,
26
33
  }
27
34
 
@@ -35,21 +42,21 @@ COMMAND_HANDLERS.update(
35
42
  {
36
43
  "/sum": handle_sum,
37
44
  "/clear": handle_clear,
38
- "/start": handle_start,
45
+ "/restart": handle_restart,
39
46
  "/config": handle_config_shell,
40
- "/reload": handle_reload,
47
+ "/view": handle_view,
41
48
  }
42
49
  )
43
50
 
44
51
 
45
- def handle_command(command, console, **kwargs):
52
+ def handle_command(command, console, shell_state=None):
46
53
  parts = command.strip().split()
47
54
  cmd = parts[0]
48
55
  args = parts[1:]
49
56
  handler = COMMAND_HANDLERS.get(cmd)
50
57
  if handler:
51
- # Pass args as a keyword argument for handlers that expect it
52
- return handler(console, args=args, **kwargs)
58
+ # Pass shell_state and args as keyword arguments for handlers that expect them
59
+ return handler(console, args=args, shell_state=shell_state)
53
60
  console.print(
54
61
  f"[bold red]Invalid command: {cmd}. Type /help for a list of commands.[/bold red]"
55
62
  )
@@ -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,72 @@
1
+ import os
2
+
3
+
4
+ from janito.shell.session.manager import reset_session_id
5
+
6
+
7
+ def handle_restart(console, shell_state=None, **kwargs):
8
+ from janito.shell.session.manager import load_last_conversation, save_conversation
9
+
10
+ reset_session_id()
11
+ save_path = os.path.join(".janito", "last_conversation.json")
12
+
13
+ # --- Append end-of-conversation message to old history if it exists and is non-trivial ---
14
+ if os.path.exists(save_path):
15
+ try:
16
+ messages, prompts, usage = load_last_conversation(save_path)
17
+ if messages and (
18
+ len(messages) > 1
19
+ or (len(messages) == 1 and messages[0].get("role") != "system")
20
+ ):
21
+ messages.append(
22
+ {"role": "system", "content": "[Session ended by user]"}
23
+ )
24
+ # Save to permanent chat history (let save_conversation pick session file)
25
+ save_conversation(messages, prompts, usage)
26
+ except Exception as e:
27
+ console.print(
28
+ f"[bold red]Failed to update previous conversation history:[/bold red] {e}"
29
+ )
30
+
31
+ # Clear the terminal screen
32
+ console.clear()
33
+
34
+ # Reset conversation history using its clear method
35
+ shell_state.conversation_history.clear()
36
+
37
+ # Reset tool use tracker
38
+ try:
39
+ from janito.agent.tool_use_tracker import ToolUseTracker
40
+
41
+ ToolUseTracker.instance().clear_history()
42
+ except Exception as e:
43
+ console.print(
44
+ f"[bold yellow]Warning: Failed to reset tool use tracker:[/bold yellow] {e}"
45
+ )
46
+ # Set system prompt from agent template if available
47
+ if (
48
+ hasattr(shell_state, "profile_manager")
49
+ and shell_state.profile_manager
50
+ and hasattr(shell_state.profile_manager, "agent")
51
+ and shell_state.profile_manager.agent
52
+ and getattr(shell_state.profile_manager.agent, "system_prompt_template", None)
53
+ and not any(
54
+ m.get("role") == "system"
55
+ for m in shell_state.conversation_history.get_messages()
56
+ )
57
+ ):
58
+ shell_state.conversation_history.set_system_message(
59
+ shell_state.profile_manager.agent.system_prompt_template
60
+ )
61
+
62
+ # Reset token usage info in-place so all references (including status bar) are updated
63
+ for k in ("prompt_tokens", "completion_tokens", "total_tokens"):
64
+ if k in shell_state.last_usage_info:
65
+ shell_state.last_usage_info[k] = 0
66
+ else:
67
+ shell_state.last_usage_info[k] = 0
68
+ shell_state.last_elapsed = None
69
+
70
+ console.print(
71
+ "[bold green]Conversation history has been started (context reset).[/bold green]"
72
+ )
@@ -0,0 +1,21 @@
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)
@@ -0,0 +1,18 @@
1
+ def handle_view(console, args=None, shell_state=None, **kwargs):
2
+ """
3
+ Prints the current LLM conversation history in a readable format.
4
+ """
5
+ messages = shell_state.conversation_history.get_messages()
6
+ if not messages:
7
+ console.print("[yellow]Conversation history is empty.[/yellow]")
8
+ return
9
+ for i, msg in enumerate(messages, 1):
10
+ role = msg.get("role", "?")
11
+ content = msg.get("content", "")
12
+ tool_calls = msg.get("tool_calls")
13
+ tool_call_id = msg.get("tool_call_id")
14
+ console.print(f"[bold]{i}. {role}:[/bold] {content}")
15
+ if tool_calls:
16
+ console.print(f" [cyan]tool_calls:[/cyan] {tool_calls}")
17
+ if tool_call_id:
18
+ console.print(f" [magenta]tool_call_id:[/magenta] {tool_call_id}")
@@ -0,0 +1,40 @@
1
+ def handle_livelogs(console, args=None, shell_state=None, **kwargs):
2
+ """
3
+ /livelogs [N] - Show the last N lines of the livereload server logs (default: 20)
4
+ """
5
+ lines = 20
6
+ if args and len(args) > 0 and str(args[0]).isdigit():
7
+ lines = int(args[0])
8
+ stdout_path = shell_state.termweb_stdout_path if shell_state else None
9
+ stderr_path = shell_state.livereload_stderr_path if shell_state else None
10
+ if not stdout_path and not stderr_path:
11
+ console.print(
12
+ "[yellow][livereload] No livereload log files found for this session.[/yellow]"
13
+ )
14
+ return
15
+ stdout_lines = []
16
+ stderr_lines = []
17
+ if stdout_path:
18
+ try:
19
+ with open(stdout_path, encoding="utf-8") as f:
20
+ stdout_lines = f.readlines()[-lines:]
21
+ if stdout_lines:
22
+ console.print(
23
+ f"[yellow][livereload][stdout] Tail of {stdout_path}:\n"
24
+ + "".join(stdout_lines)
25
+ )
26
+ except Exception as e:
27
+ console.print(f"[red][livereload][stdout] Error: {e}[/red]")
28
+ if stderr_path:
29
+ try:
30
+ with open(stderr_path, encoding="utf-8") as f:
31
+ stderr_lines = f.readlines()[-lines:]
32
+ if stderr_lines:
33
+ console.print(
34
+ f"[red][livereload][stderr] Tail of {stderr_path}:\n"
35
+ + "".join(stderr_lines)
36
+ )
37
+ except Exception as e:
38
+ console.print(f"[red][livereload][stderr] Error: {e}[/red]")
39
+ if (not stdout_path or not stdout_lines) and (not stderr_path or not stderr_lines):
40
+ console.print("[livereload] No output or errors captured in logs.")
@@ -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,12 @@ 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
+ def handle_role(console, args=None, shell_state=None, **kwargs):
13
+ profile_manager = (
14
+ shell_state.profile_manager
15
+ if shell_state and hasattr(shell_state, "profile_manager")
16
+ else kwargs.get("profile_manager")
17
+ )
15
18
  if not args:
16
19
  console.print("[bold red]Usage: /role <new role description>[/bold red]")
17
20
  return
@@ -20,7 +23,7 @@ def handle_role(console, *args, **kwargs):
20
23
  profile_manager.set_role(new_role)
21
24
  # Update system message in conversation
22
25
  found = False
23
- for msg in state["messages"]:
26
+ for msg in shell_state.conversation_history.get_messages():
24
27
  if msg.get("role") == "system":
25
28
  msg["content"] = (
26
29
  profile_manager.system_prompt_template if profile_manager else new_role
@@ -28,7 +31,8 @@ def handle_role(console, *args, **kwargs):
28
31
  found = True
29
32
  break
30
33
  if not found:
31
- state["messages"].insert(0, {"role": "system", "content": new_role})
34
+ if shell_state and hasattr(shell_state, "conversation_history"):
35
+ shell_state.conversation_history.set_system_message(new_role)
32
36
  # Also store the raw role string
33
37
  if profile_manager:
34
38
  setattr(profile_manager, "role_name", new_role)
@@ -0,0 +1,32 @@
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}")
@@ -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:
@@ -40,8 +40,3 @@ def restart_cli():
40
40
  def handle_exit(console, **kwargs):
41
41
  console.print("[bold red]Exiting chat mode.[/bold red]")
42
42
  sys.exit(0)
43
-
44
-
45
- def handle_restart(console, **kwargs):
46
- console.print("[bold yellow]Restarting CLI...[/bold yellow]")
47
- restart_cli()