janito 1.5.2__py3-none-any.whl → 1.6.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 (85) hide show
  1. janito/__init__.py +1 -1
  2. janito/__main__.py +0 -1
  3. janito/agent/config.py +11 -10
  4. janito/agent/config_defaults.py +3 -2
  5. janito/agent/conversation.py +93 -119
  6. janito/agent/conversation_api.py +98 -0
  7. janito/agent/conversation_exceptions.py +12 -0
  8. janito/agent/conversation_tool_calls.py +22 -0
  9. janito/agent/conversation_ui.py +17 -0
  10. janito/agent/message_handler.py +8 -9
  11. janito/agent/{agent.py → openai_client.py} +48 -16
  12. janito/agent/openai_schema_generator.py +53 -37
  13. janito/agent/profile_manager.py +172 -0
  14. janito/agent/queued_message_handler.py +13 -14
  15. janito/agent/rich_live.py +32 -0
  16. janito/agent/rich_message_handler.py +64 -0
  17. janito/agent/runtime_config.py +6 -1
  18. janito/agent/{tools/tool_base.py → tool_base.py} +15 -8
  19. janito/agent/tool_registry.py +118 -132
  20. janito/agent/tools/__init__.py +41 -2
  21. janito/agent/tools/ask_user.py +43 -33
  22. janito/agent/tools/create_directory.py +18 -16
  23. janito/agent/tools/create_file.py +31 -36
  24. janito/agent/tools/fetch_url.py +23 -19
  25. janito/agent/tools/find_files.py +40 -36
  26. janito/agent/tools/get_file_outline.py +100 -22
  27. janito/agent/tools/get_lines.py +40 -32
  28. janito/agent/tools/gitignore_utils.py +9 -6
  29. janito/agent/tools/move_file.py +22 -13
  30. janito/agent/tools/py_compile_file.py +40 -0
  31. janito/agent/tools/remove_directory.py +34 -24
  32. janito/agent/tools/remove_file.py +22 -20
  33. janito/agent/tools/replace_file.py +51 -0
  34. janito/agent/tools/replace_text_in_file.py +69 -42
  35. janito/agent/tools/rich_live.py +9 -2
  36. janito/agent/tools/run_bash_command.py +155 -107
  37. janito/agent/tools/run_python_command.py +139 -0
  38. janito/agent/tools/search_files.py +51 -34
  39. janito/agent/tools/tools_utils.py +4 -2
  40. janito/agent/tools/utils.py +6 -2
  41. janito/cli/_print_config.py +42 -16
  42. janito/cli/_utils.py +1 -0
  43. janito/cli/arg_parser.py +182 -29
  44. janito/cli/config_commands.py +54 -22
  45. janito/cli/logging_setup.py +9 -3
  46. janito/cli/main.py +11 -10
  47. janito/cli/runner/__init__.py +2 -0
  48. janito/cli/runner/cli_main.py +148 -0
  49. janito/cli/runner/config.py +33 -0
  50. janito/cli/runner/formatting.py +12 -0
  51. janito/cli/runner/scan.py +44 -0
  52. janito/cli_chat_shell/__init__.py +0 -1
  53. janito/cli_chat_shell/chat_loop.py +71 -92
  54. janito/cli_chat_shell/chat_state.py +38 -0
  55. janito/cli_chat_shell/chat_ui.py +43 -0
  56. janito/cli_chat_shell/commands/__init__.py +45 -0
  57. janito/cli_chat_shell/commands/config.py +22 -0
  58. janito/cli_chat_shell/commands/history_reset.py +29 -0
  59. janito/cli_chat_shell/commands/session.py +48 -0
  60. janito/cli_chat_shell/commands/session_control.py +12 -0
  61. janito/cli_chat_shell/commands/system.py +73 -0
  62. janito/cli_chat_shell/commands/utility.py +29 -0
  63. janito/cli_chat_shell/config_shell.py +39 -10
  64. janito/cli_chat_shell/load_prompt.py +5 -2
  65. janito/cli_chat_shell/session_manager.py +24 -27
  66. janito/cli_chat_shell/ui.py +75 -40
  67. janito/rich_utils.py +15 -2
  68. janito/web/__main__.py +10 -2
  69. janito/web/app.py +88 -52
  70. {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/METADATA +76 -11
  71. janito-1.6.0.dist-info/RECORD +81 -0
  72. {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/WHEEL +1 -1
  73. janito/agent/rich_tool_handler.py +0 -43
  74. janito/agent/templates/system_instructions.j2 +0 -38
  75. janito/agent/tool_auto_imports.py +0 -5
  76. janito/agent/tools/append_text_to_file.py +0 -41
  77. janito/agent/tools/py_compile.py +0 -39
  78. janito/agent/tools/python_exec.py +0 -83
  79. janito/cli/runner.py +0 -137
  80. janito/cli_chat_shell/commands.py +0 -204
  81. janito/render_prompt.py +0 -13
  82. janito-1.5.2.dist-info/RECORD +0 -66
  83. {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/entry_points.txt +0 -0
  84. {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/licenses/LICENSE +0 -0
  85. {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,22 @@
1
+ def handle_reload(console, *args, **kwargs):
2
+ from ..load_prompt import load_prompt
3
+
4
+ agent = kwargs.get("agent")
5
+ state = kwargs.get("state")
6
+ filename = args[0] if args else None
7
+ try:
8
+ prompt_text = load_prompt(filename)
9
+ if hasattr(agent, "system_prompt_template"):
10
+ agent.system_prompt_template = prompt_text
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:
15
+ if msg.get("role") == "system":
16
+ msg["content"] = prompt_text
17
+ break
18
+ console.print(
19
+ f"[bold green]System prompt reloaded from {'default file' if not filename else filename}![/bold green]"
20
+ )
21
+ except Exception as e:
22
+ console.print(f"[bold red]Failed to reload system prompt:[/bold red] {e}")
@@ -0,0 +1,29 @@
1
+ from prompt_toolkit.history import InMemoryHistory
2
+ import os
3
+
4
+
5
+ def handle_reset(console, state, **kwargs):
6
+ save_path = os.path.join(".janito", "last_conversation.json")
7
+
8
+ # Clear in-memory conversation and prompt history
9
+ state["messages"].clear()
10
+ state["history_list"].clear()
11
+ state["mem_history"] = InMemoryHistory()
12
+ state["last_usage_info"] = None
13
+ state["last_elapsed"] = None
14
+
15
+ # Delete saved conversation file if exists
16
+ if os.path.exists(save_path):
17
+ try:
18
+ os.remove(save_path)
19
+ console.print(
20
+ "[bold yellow]Deleted saved conversation history.[/bold yellow]"
21
+ )
22
+ except Exception as e:
23
+ console.print(
24
+ f"[bold red]Failed to delete saved conversation:[/bold red] {e}"
25
+ )
26
+ else:
27
+ console.print("[bold yellow]No saved conversation to delete.[/bold yellow]")
28
+
29
+ console.print("[bold green]Conversation history has been reset.[/bold green]")
@@ -0,0 +1,48 @@
1
+ from prompt_toolkit.history import InMemoryHistory
2
+ import os
3
+ import json
4
+
5
+
6
+ def handle_continue(console, state, **kwargs):
7
+ save_path = os.path.join(".janito", "last_conversation.json")
8
+ if not os.path.exists(save_path):
9
+ console.print("[bold red]No saved conversation found.[/bold red]")
10
+ return
11
+
12
+ with open(save_path, "r", encoding="utf-8") as f:
13
+ data = json.load(f)
14
+ state["messages"].clear()
15
+ state["messages"].extend(data.get("messages", []))
16
+ state["history_list"].clear()
17
+ state["history_list"].extend(data.get("prompts", []))
18
+ state["mem_history"] = InMemoryHistory()
19
+ for item in state["history_list"]:
20
+ state["mem_history"].append_string(item)
21
+ state["last_usage_info"] = data.get("last_usage_info")
22
+ console.print("[bold green]Conversation restored from last session.[/bold green]")
23
+
24
+
25
+ def handle_history(console, state, *args, **kwargs):
26
+ messages = state.get("messages", [])
27
+ if not args:
28
+ # Default: last 5 messages
29
+ start = max(0, len(messages) - 5)
30
+ end = len(messages)
31
+ elif len(args) == 1:
32
+ count = int(args[0])
33
+ start = max(0, len(messages) - count)
34
+ end = len(messages)
35
+ elif len(args) >= 2:
36
+ start = int(args[0])
37
+ end = int(args[1]) + 1 # inclusive
38
+ else:
39
+ start = 0
40
+ end = len(messages)
41
+
42
+ console.print(
43
+ f"[bold cyan]Showing messages {start} to {end - 1} (total {len(messages)}):[/bold cyan]"
44
+ )
45
+ for idx, msg in enumerate(messages[start:end], start=start):
46
+ role = msg.get("role", "unknown")
47
+ content = msg.get("content", "")
48
+ console.print(f"[bold]{idx} [{role}]:[/bold] {content}")
@@ -0,0 +1,12 @@
1
+ import os
2
+ import sys
3
+
4
+
5
+ def handle_exit(console, **kwargs):
6
+ console.print("[bold red]Exiting chat mode.[/bold red]")
7
+ sys.exit(0)
8
+
9
+
10
+ def handle_restart(console, **kwargs):
11
+ console.print("[bold yellow]Restarting CLI...[/bold yellow]")
12
+ os.execv(sys.executable, [sys.executable, "-m", "janito"] + sys.argv[1:])
@@ -0,0 +1,73 @@
1
+ from janito.agent.runtime_config import runtime_config
2
+
3
+
4
+ def handle_system(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.render_prompt()
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_style(console, *args, **kwargs):
40
+ """/style <new_style> - Change the interaction style (e.g., default, technical)"""
41
+ state = kwargs.get("state")
42
+ profile_manager = kwargs.get("profile_manager")
43
+ if not args:
44
+ current = getattr(profile_manager, "interaction_style", "default")
45
+ console.print(f"[bold green]Current style:[/bold green] {current}")
46
+ return
47
+ new_style = args[0]
48
+ if profile_manager:
49
+ profile_manager.set_interaction_style(new_style)
50
+ # Update system message in conversation
51
+ found = False
52
+ for msg in state["messages"]:
53
+ if msg.get("role") == "system":
54
+ msg["content"] = (
55
+ profile_manager.system_prompt_template
56
+ if profile_manager
57
+ else msg["content"]
58
+ )
59
+ found = True
60
+ break
61
+ if not found:
62
+ state["messages"].insert(
63
+ 0,
64
+ {
65
+ "role": "system",
66
+ "content": (
67
+ profile_manager.system_prompt_template
68
+ if profile_manager
69
+ else new_style
70
+ ),
71
+ },
72
+ )
73
+ console.print(f"[bold green]Interaction style updated to:[/bold green] {new_style}")
@@ -0,0 +1,29 @@
1
+ def handle_help(console, **kwargs):
2
+ console.print(
3
+ """
4
+ [bold green]Available commands:[/bold green]
5
+ /exit, exit - Exit chat mode
6
+ /restart - Restart the CLI
7
+ /help - Show this help message
8
+ /continue - Restore last saved conversation
9
+ /reset - Reset conversation history
10
+ /system - Show the system prompt
11
+ /role - Change the system role
12
+ /clear - Clear the terminal screen
13
+ /multi - Provide multiline input as next message
14
+ /config - Show or set configuration (see: /config show, /config set local|global key=value)
15
+ """
16
+ )
17
+
18
+
19
+ def handle_clear(console, **kwargs):
20
+ import os
21
+
22
+ os.system("cls" if os.name == "nt" else "clear")
23
+
24
+
25
+ def handle_multi(console, state, **kwargs):
26
+ console.print(
27
+ "[bold yellow]Multiline mode activated. Provide or write your text and press Esc + Enter to submit.[/bold yellow]"
28
+ )
29
+ state["paste_mode"] = True
@@ -2,6 +2,7 @@ from janito.agent.config import local_config, global_config, CONFIG_OPTIONS
2
2
  from janito.agent.config_defaults import CONFIG_DEFAULTS
3
3
  from janito.agent.runtime_config import unified_config, runtime_config
4
4
 
5
+
5
6
  def handle_config_shell(console, *args, **kwargs):
6
7
  """
7
8
  /config show
@@ -11,13 +12,22 @@ def handle_config_shell(console, *args, **kwargs):
11
12
  /config reset global
12
13
  """
13
14
  if not args or args[0] not in ("show", "set", "reset"):
14
- console.print("[bold red]Usage:[/bold red] /config show | /config set local|global key=value | /config reset local|global")
15
+ console.print(
16
+ "[bold red]Usage:[/bold red] /config show | /config set local|global key=value | /config reset local|global"
17
+ )
15
18
  return
16
19
 
17
20
  if args[0] == "show":
18
21
  # Show config, unified with CLI
19
22
  from janito.cli._print_config import print_full_config
20
- print_full_config(local_config, global_config, unified_config, CONFIG_DEFAULTS, console=console)
23
+
24
+ print_full_config(
25
+ local_config,
26
+ global_config,
27
+ unified_config,
28
+ CONFIG_DEFAULTS,
29
+ console=console,
30
+ )
21
31
  return
22
32
 
23
33
  if args[0] == "reset":
@@ -26,27 +36,38 @@ def handle_config_shell(console, *args, **kwargs):
26
36
  return
27
37
  import os
28
38
  from pathlib import Path
39
+
29
40
  scope = args[1]
30
41
  if scope == "local":
31
- local_path = Path('.janito/config.json')
42
+ local_path = Path(".janito/config.json")
32
43
  if local_path.exists():
33
44
  os.remove(local_path)
34
45
  console.print(f"[green]Removed local config file:[/green] {local_path}")
35
46
  else:
36
- console.print(f"[yellow]Local config file does not exist:[/yellow] {local_path}")
47
+ console.print(
48
+ f"[yellow]Local config file does not exist:[/yellow] {local_path}"
49
+ )
37
50
  elif scope == "global":
38
- global_path = Path.home() / '.janito/config.json'
51
+ global_path = Path.home() / ".janito/config.json"
39
52
  if global_path.exists():
40
53
  os.remove(global_path)
41
- console.print(f"[green]Removed global config file:[/green] {global_path}")
54
+ console.print(
55
+ f"[green]Removed global config file:[/green] {global_path}"
56
+ )
42
57
  else:
43
- console.print(f"[yellow]Global config file does not exist:[/yellow] {global_path}")
44
- console.print("[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]")
58
+ console.print(
59
+ f"[yellow]Global config file does not exist:[/yellow] {global_path}"
60
+ )
61
+ console.print(
62
+ "[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
63
+ )
45
64
  return
46
65
 
47
66
  if args[0] == "set":
48
67
  if len(args) < 3 or args[1] not in ("local", "global"):
49
- console.print("[bold red]Usage:[/bold red] /config set local|global key=value")
68
+ console.print(
69
+ "[bold red]Usage:[/bold red] /config set local|global key=value"
70
+ )
50
71
  return
51
72
  scope = args[1]
52
73
  try:
@@ -56,7 +77,9 @@ def handle_config_shell(console, *args, **kwargs):
56
77
  return
57
78
  key = key.strip()
58
79
  if key not in CONFIG_OPTIONS and not key.startswith("template."):
59
- console.print(f"[bold red]Invalid config key: '{key}'. Supported keys are: {', '.join(CONFIG_OPTIONS.keys())}")
80
+ console.print(
81
+ f"[bold red]Invalid config key: '{key}'. Supported keys are: {', '.join(CONFIG_OPTIONS.keys())}"
82
+ )
60
83
  return
61
84
  val = val.strip()
62
85
  if scope == "local":
@@ -64,9 +87,15 @@ def handle_config_shell(console, *args, **kwargs):
64
87
  local_config.save()
65
88
  runtime_config.set(key, val)
66
89
  console.print(f"[green]Local config updated:[/green] {key} = {val}")
90
+ console.print(
91
+ "[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
92
+ )
67
93
  elif scope == "global":
68
94
  global_config.set(key, val)
69
95
  global_config.save()
70
96
  runtime_config.set(key, val)
71
97
  console.print(f"[green]Global config updated:[/green] {key} = {val}")
98
+ console.print(
99
+ "[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
100
+ )
72
101
  return
@@ -1,5 +1,6 @@
1
1
  import os
2
2
 
3
+
3
4
  def load_prompt(filename=None):
4
5
  """
5
6
  Load the system prompt from a file. If filename is None, use the default prompt file.
@@ -7,9 +8,11 @@ def load_prompt(filename=None):
7
8
  """
8
9
  if filename is None:
9
10
  # Default prompt file path (can be customized)
10
- filename = os.path.join(os.path.dirname(__file__), '../agent/templates/system_instructions.j2')
11
+ filename = os.path.join(
12
+ os.path.dirname(__file__), "../agent/templates/system_prompt_template.j2"
13
+ )
11
14
  filename = os.path.abspath(filename)
12
15
  if not os.path.exists(filename):
13
16
  raise FileNotFoundError(f"Prompt file not found: {filename}")
14
- with open(filename, 'r', encoding='utf-8') as f:
17
+ with open(filename, "r", encoding="utf-8") as f:
15
18
  return f.read()
@@ -3,65 +3,62 @@ import json
3
3
  from datetime import datetime
4
4
 
5
5
 
6
- def load_last_summary(path='.janito/last_conversation.json'):
6
+ def load_last_summary(path=".janito/last_conversation.json"):
7
7
  if not os.path.exists(path):
8
8
  return None
9
- with open(path, 'r', encoding='utf-8') as f:
9
+ with open(path, "r", encoding="utf-8") as f:
10
10
  data = json.load(f)
11
11
  return data
12
12
 
13
13
 
14
-
15
- def load_last_conversation(path='.janito/last_conversation.json'):
14
+ def load_last_conversation(path=".janito/last_conversation.json"):
16
15
  if not os.path.exists(path):
17
16
  return [], [], None
18
- with open(path, 'r', encoding='utf-8') as f:
17
+ with open(path, "r", encoding="utf-8") as f:
19
18
  data = json.load(f)
20
- messages = data.get('messages', [])
21
- prompts = data.get('prompts', [])
22
- usage = data.get('last_usage_info')
19
+ messages = data.get("messages", [])
20
+ prompts = data.get("prompts", [])
21
+ usage = data.get("last_usage_info")
23
22
  return messages, prompts, usage
24
23
 
25
24
 
26
-
27
- def save_conversation(messages, prompts, usage_info=None, path='.janito/last_conversation.json'):
25
+ def save_conversation(
26
+ messages, prompts, usage_info=None, path=".janito/last_conversation.json"
27
+ ):
28
28
  os.makedirs(os.path.dirname(path), exist_ok=True)
29
- data = {
30
- 'messages': messages,
31
- 'prompts': prompts,
32
- 'last_usage_info': usage_info
33
- }
34
- with open(path, 'w', encoding='utf-8') as f:
29
+ data = {"messages": messages, "prompts": prompts, "last_usage_info": usage_info}
30
+ with open(path, "w", encoding="utf-8") as f:
35
31
  json.dump(data, f, indent=2)
36
32
 
37
33
 
38
34
  def load_input_history():
39
- history_dir = os.path.join('.janito', 'input_history')
35
+ history_dir = os.path.join(".janito", "input_history")
40
36
  os.makedirs(history_dir, exist_ok=True)
41
- today_str = datetime.now().strftime('%y%m%d')
42
- history_file = os.path.join(history_dir, f'{today_str}.json')
37
+ today_str = datetime.now().strftime("%y%m%d")
38
+ history_file = os.path.join(history_dir, f"{today_str}.json")
43
39
  try:
44
- with open(history_file, 'r', encoding='utf-8') as f:
40
+ with open(history_file, "r", encoding="utf-8") as f:
45
41
  return json.load(f)
46
42
  except (FileNotFoundError, json.JSONDecodeError):
47
43
  return []
48
44
 
49
45
 
50
46
  def save_input_history(history_list):
51
- history_dir = os.path.join('.janito', 'input_history')
47
+ history_dir = os.path.join(".janito", "input_history")
52
48
  os.makedirs(history_dir, exist_ok=True)
53
- today_str = datetime.now().strftime('%y%m%d')
54
- history_file = os.path.join(history_dir, f'{today_str}.json')
55
- with open(history_file, 'w', encoding='utf-8') as f:
49
+ today_str = datetime.now().strftime("%y%m%d")
50
+ history_file = os.path.join(history_dir, f"{today_str}.json")
51
+ with open(history_file, "w", encoding="utf-8") as f:
56
52
  json.dump(history_list, f, indent=2)
57
53
 
58
- def last_conversation_exists(path='.janito/last_conversation.json'):
54
+
55
+ def last_conversation_exists(path=".janito/last_conversation.json"):
59
56
  if not os.path.exists(path):
60
57
  return False
61
58
  try:
62
- with open(path, 'r', encoding='utf-8') as f:
59
+ with open(path, "r", encoding="utf-8") as f:
63
60
  data = json.load(f)
64
- messages = data.get('messages', [])
61
+ messages = data.get("messages", [])
65
62
  return bool(messages)
66
63
  except Exception:
67
64
  return False
@@ -9,39 +9,58 @@ from .session_manager import last_conversation_exists
9
9
  def print_summary(console, data, continue_session):
10
10
  if not data:
11
11
  return
12
- msgs = data.get('messages', [])
13
- last_user = next((m['content'] for m in reversed(msgs) if m.get('role') == 'user'), None)
14
- last_assistant = next((m['content'] for m in reversed(msgs) if m.get('role') == 'assistant'), None)
15
- usage = data.get('last_usage_info', {})
16
- console.print('[bold cyan]Last saved conversation:[/bold cyan]')
12
+ msgs = data.get("messages", [])
13
+ last_user = next(
14
+ (m["content"] for m in reversed(msgs) if m.get("role") == "user"), None
15
+ )
16
+ last_assistant = next(
17
+ (m["content"] for m in reversed(msgs) if m.get("role") == "assistant"), None
18
+ )
19
+ usage = data.get("last_usage_info", {})
20
+ console.print("[bold cyan]Last saved conversation:[/bold cyan]")
17
21
  console.print(f"Messages: {len(msgs)}")
18
22
  if last_user:
19
- console.print(f"Last user: [italic]{last_user[:100]}{'...' if len(last_user)>100 else ''}[/italic]")
23
+ console.print(
24
+ f"Last user: [italic]{last_user[:100]}{'...' if len(last_user)>100 else ''}[/italic]"
25
+ )
20
26
  if last_assistant:
21
- console.print(f"Last assistant: [italic]{last_assistant[:100]}{'...' if len(last_assistant)>100 else ''}[/italic]")
27
+ console.print(
28
+ f"Last assistant: [italic]{last_assistant[:100]}{'...' if len(last_assistant)>100 else ''}[/italic]"
29
+ )
22
30
  if usage:
23
- ptok = usage.get('prompt_tokens')
24
- ctok = usage.get('completion_tokens')
31
+ ptok = usage.get("prompt_tokens")
32
+ ctok = usage.get("completion_tokens")
25
33
  tot = (ptok or 0) + (ctok or 0)
26
34
  console.print(f"Tokens - Prompt: {ptok}, Completion: {ctok}, Total: {tot}")
27
35
  # Only print /continue suggestion if a last conversation exists
28
36
  if not continue_session and last_conversation_exists():
29
- console.print("[bold yellow]Type /continue to restore the last saved conversation.[/bold yellow]")
37
+ console.print(
38
+ "[bold yellow]Type /continue to restore the last saved conversation.[/bold yellow]"
39
+ )
30
40
 
31
41
 
32
42
  def print_welcome(console, version=None, continued=False):
33
43
  version_str = f" (v{version})" if version else ""
34
- vanilla_mode = runtime_config.get('vanilla_mode', False)
44
+ vanilla_mode = runtime_config.get("vanilla_mode", False)
35
45
  if vanilla_mode:
36
- console.print(f"[bold magenta]Welcome to Janito{version_str} in [white on magenta]VANILLA MODE[/white on magenta]! Tools, system prompt, and temperature are disabled unless overridden.[/bold magenta]")
46
+ console.print(
47
+ f"[bold magenta]Welcome to Janito{version_str} in [white on magenta]VANILLA MODE[/white on magenta]! Tools, system prompt, and temperature are disabled unless overridden.[/bold magenta]\n[cyan]Quick action: Press F12 to continue. Double-check the suggested action first. 😊[/cyan]"
48
+ )
37
49
  else:
38
- console.print(f"[bold green]Welcome to Janito{version_str}! Entering chat mode. Type /exit to exit.[/bold green]")
50
+ console.print(
51
+ f"[bold green]Welcome to Janito{version_str}! Entering chat mode. Type /exit to exit.[/bold green]\n[cyan]Quick action: Press F12 to continue. Double-check the suggested action first. 😊[/cyan]"
52
+ )
39
53
  # Only print /continue suggestion if a last conversation exists
40
- if not continued and last_conversation_exists():
41
- console.print("[yellow]To resume your previous conversation, type /continue at any time.[/yellow]")
42
54
 
43
55
 
44
- def get_toolbar_func(messages_ref, last_usage_info_ref, last_elapsed_ref, model_name=None, role_ref=None):
56
+ def get_toolbar_func(
57
+ messages_ref,
58
+ last_usage_info_ref,
59
+ last_elapsed_ref,
60
+ model_name=None,
61
+ role_ref=None,
62
+ style_ref=None,
63
+ ):
45
64
  def format_tokens(n):
46
65
  if n is None:
47
66
  return "?"
@@ -52,12 +71,12 @@ def get_toolbar_func(messages_ref, last_usage_info_ref, last_elapsed_ref, model_
52
71
  return str(n)
53
72
 
54
73
  def get_toolbar():
55
- left = f' Messages: <msg_count>{len(messages_ref())}</msg_count>'
74
+ left = f" Messages: <msg_count>{len(messages_ref())}</msg_count>"
56
75
  usage = last_usage_info_ref()
57
76
  last_elapsed = last_elapsed_ref()
58
77
  if usage:
59
- prompt_tokens = usage.get('prompt_tokens')
60
- completion_tokens = usage.get('completion_tokens')
78
+ prompt_tokens = usage.get("prompt_tokens")
79
+ completion_tokens = usage.get("completion_tokens")
61
80
  total_tokens = (prompt_tokens or 0) + (completion_tokens or 0)
62
81
  speed = None
63
82
  if last_elapsed and last_elapsed > 0:
@@ -71,26 +90,34 @@ def get_toolbar_func(messages_ref, last_usage_info_ref, last_elapsed_ref, model_
71
90
  left += f", speed=<speed>{speed:.1f}</speed> tokens/sec"
72
91
 
73
92
  from prompt_toolkit.application import get_app
93
+
74
94
  width = get_app().output.get_size().columns
75
95
  model_part = f" Model: <model>{model_name}</model>" if model_name else ""
76
96
  role_part = ""
77
- vanilla_mode = runtime_config.get('vanilla_mode', False)
97
+ vanilla_mode = runtime_config.get("vanilla_mode", False)
78
98
  if role_ref and not vanilla_mode:
79
99
  role = role_ref()
80
100
  if role:
81
101
  role_part = f"Role: <b>{role}</b>"
102
+ style_part = ""
103
+ if style_ref:
104
+ style = style_ref()
105
+ if style:
106
+ style_part = f"Style: <b>{style}</b>"
82
107
  first_line_parts = []
83
108
  if model_part:
84
109
  first_line_parts.append(model_part)
85
110
  if role_part:
86
111
  first_line_parts.append(role_part)
112
+ if style_part:
113
+ first_line_parts.append(style_part)
87
114
  first_line = " | ".join(first_line_parts)
88
- help_part = "<b>/help</b> for help | <b>F12</b>: Go ahead"
115
+ help_part = "<b>/help</b> for help | <b>F12</b>: proceed"
89
116
  total_len = len(left) + len(help_part) + 3 # separators and spaces
90
117
  if first_line:
91
118
  total_len += len(first_line) + 3
92
119
  if total_len < width:
93
- padding = ' ' * (width - total_len)
120
+ padding = " " * (width - total_len)
94
121
  second_line = f"{left}{padding} | {help_part}"
95
122
  else:
96
123
  second_line = f"{left} | {help_part}"
@@ -99,39 +126,47 @@ def get_toolbar_func(messages_ref, last_usage_info_ref, last_elapsed_ref, model_
99
126
  else:
100
127
  toolbar_text = second_line
101
128
  return HTML(toolbar_text)
129
+
102
130
  return get_toolbar
103
131
 
132
+
104
133
  def get_prompt_session(get_toolbar_func, mem_history):
105
134
  from prompt_toolkit.key_binding import KeyBindings
106
- style = Style.from_dict({
107
- 'bottom-toolbar': 'bg:#333333 #ffffff',
108
- 'b': 'bold',
109
- 'prompt': 'bold bg:#000080 #ffffff',
110
- 'model': 'bold bg:#005f5f #ffffff', # distinct background/foreground
111
- 'msg_count': 'bg:#333333 #ffff00 bold',
112
- 'tokens_in': 'ansicyan bold',
113
- 'tokens_out': 'ansigreen bold',
114
- 'tokens_total': 'ansiyellow bold',
115
- 'speed': 'ansimagenta bold',
116
- 'right': 'bg:#005f5f #ffffff',
117
- 'input': 'bg:#000080 #ffffff',
118
- '': 'bg:#000080 #ffffff',
119
- })
135
+
136
+ style = Style.from_dict(
137
+ {
138
+ "bottom-toolbar": "bg:#333333 #ffffff",
139
+ "b": "bold",
140
+ "prompt": "bold bg:#000080 #ffffff",
141
+ "model": "bold bg:#005f5f #ffffff", # distinct background/foreground
142
+ "msg_count": "bg:#333333 #ffff00 bold",
143
+ "tokens_in": "ansicyan bold",
144
+ "tokens_out": "ansigreen bold",
145
+ "tokens_total": "ansiyellow bold",
146
+ "speed": "ansimagenta bold",
147
+ "right": "bg:#005f5f #ffffff",
148
+ "input": "bg:#000080 #ffffff",
149
+ "": "bg:#000080 #ffffff",
150
+ }
151
+ )
120
152
  kb = KeyBindings()
121
- @kb.add('f12')
153
+
154
+ @kb.add("f12")
122
155
  def _(event):
123
- """When F12 is pressed, send 'Go ahead' as input immediately."""
156
+ """When F12 is pressed, send 'proceed' as input immediately."""
124
157
  buf = event.app.current_buffer
125
- buf.text = 'Go ahead'
158
+ buf.text = "proceed"
126
159
  buf.validate_and_handle()
160
+
127
161
  session = PromptSession(
128
162
  multiline=False,
129
163
  key_bindings=kb,
130
164
  editing_mode=EditingMode.EMACS,
131
165
  bottom_toolbar=get_toolbar_func,
132
166
  style=style,
133
- history=mem_history
167
+ history=mem_history,
134
168
  )
135
169
  return session
136
170
 
171
+
137
172
  # ... rest of the file remains unchanged ...