janito 1.9.0__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 (81) 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 -26
  5. janito/agent/conversation.py +163 -122
  6. janito/agent/conversation_api.py +149 -159
  7. janito/agent/{conversation_history.py → llm_conversation_history.py} +18 -1
  8. janito/agent/openai_client.py +38 -23
  9. janito/agent/openai_schema_generator.py +162 -129
  10. janito/agent/platform_discovery.py +134 -77
  11. janito/agent/profile_manager.py +5 -5
  12. janito/agent/rich_message_handler.py +80 -31
  13. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +5 -4
  14. janito/agent/test_openai_schema_generator.py +93 -0
  15. janito/agent/tool_base.py +7 -2
  16. janito/agent/tool_executor.py +54 -49
  17. janito/agent/tool_registry.py +5 -2
  18. janito/agent/tool_use_tracker.py +26 -5
  19. janito/agent/tools/__init__.py +6 -3
  20. janito/agent/tools/create_directory.py +3 -1
  21. janito/agent/tools/create_file.py +7 -1
  22. janito/agent/tools/fetch_url.py +40 -3
  23. janito/agent/tools/find_files.py +3 -1
  24. janito/agent/tools/get_file_outline/core.py +6 -7
  25. janito/agent/tools/get_file_outline/search_outline.py +3 -1
  26. janito/agent/tools/get_lines.py +7 -2
  27. janito/agent/tools/move_file.py +3 -1
  28. janito/agent/tools/present_choices.py +3 -1
  29. janito/agent/tools/python_command_runner.py +150 -0
  30. janito/agent/tools/python_file_runner.py +148 -0
  31. janito/agent/tools/python_stdin_runner.py +154 -0
  32. janito/agent/tools/remove_directory.py +3 -1
  33. janito/agent/tools/remove_file.py +5 -1
  34. janito/agent/tools/replace_file.py +12 -2
  35. janito/agent/tools/replace_text_in_file.py +4 -2
  36. janito/agent/tools/run_bash_command.py +30 -69
  37. janito/agent/tools/run_powershell_command.py +134 -105
  38. janito/agent/tools/search_text.py +172 -122
  39. janito/agent/tools/validate_file_syntax/core.py +3 -1
  40. janito/agent/tools_utils/action_type.py +7 -0
  41. janito/agent/tools_utils/dir_walk_utils.py +3 -2
  42. janito/agent/tools_utils/formatting.py +47 -21
  43. janito/agent/tools_utils/gitignore_utils.py +66 -40
  44. janito/agent/tools_utils/test_gitignore_utils.py +46 -0
  45. janito/cli/_print_config.py +63 -61
  46. janito/cli/arg_parser.py +13 -12
  47. janito/cli/cli_main.py +137 -147
  48. janito/cli/main.py +152 -174
  49. janito/cli/one_shot.py +40 -26
  50. janito/i18n/__init__.py +1 -1
  51. janito/rich_utils.py +46 -8
  52. janito/shell/commands/__init__.py +2 -4
  53. janito/shell/commands/conversation_restart.py +3 -1
  54. janito/shell/commands/edit.py +3 -0
  55. janito/shell/commands/history_view.py +3 -3
  56. janito/shell/commands/lang.py +3 -0
  57. janito/shell/commands/livelogs.py +5 -3
  58. janito/shell/commands/prompt.py +6 -0
  59. janito/shell/commands/session.py +3 -0
  60. janito/shell/commands/session_control.py +3 -0
  61. janito/shell/commands/termweb_log.py +8 -0
  62. janito/shell/commands/tools.py +3 -0
  63. janito/shell/commands/track.py +36 -0
  64. janito/shell/commands/utility.py +13 -18
  65. janito/shell/commands/verbose.py +3 -4
  66. janito/shell/input_history.py +62 -0
  67. janito/shell/main.py +117 -181
  68. janito/shell/session/manager.py +0 -21
  69. janito/shell/ui/interactive.py +0 -2
  70. janito/termweb/static/editor.css +0 -4
  71. janito/tests/test_rich_utils.py +44 -0
  72. janito/web/app.py +0 -75
  73. {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/METADATA +61 -42
  74. {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/RECORD +78 -71
  75. {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/WHEEL +1 -1
  76. janito/agent/providers.py +0 -77
  77. janito/agent/tools/run_python_command.py +0 -161
  78. janito/shell/commands/sum.py +0 -49
  79. {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/entry_points.txt +0 -0
  80. {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/licenses/LICENSE +0 -0
  81. {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/top_level.txt +0 -0
janito/cli/main.py CHANGED
@@ -12,205 +12,183 @@ import janito.agent.tools # noqa: F401
12
12
  from janito.i18n import tr
13
13
 
14
14
 
15
+ def handle_list_sessions(args):
16
+ import os
17
+ import glob
18
+
19
+ n = args.list if args.list is not None else 10
20
+ history_dir = os.path.join(os.path.expanduser(".janito"), "chat_history")
21
+ if not os.path.exists(history_dir):
22
+ print("No session history found.")
23
+ return True
24
+ files = glob.glob(os.path.join(history_dir, "*.json"))
25
+ files = sorted(files, key=os.path.getmtime, reverse=True)
26
+ print(f"Last {n} sessions:")
27
+ for f in files[:n]:
28
+ session_id = os.path.splitext(os.path.basename(f))[0]
29
+ print(session_id)
30
+ return True
31
+
32
+
33
+ def handle_view_session(args):
34
+ import os
35
+ import json
36
+
37
+ history_dir = os.path.join(os.path.expanduser(".janito"), "chat_history")
38
+ session_file = os.path.join(history_dir, f"{args.view}.json")
39
+ if not os.path.exists(session_file):
40
+ print(f"Session '{args.view}' not found.")
41
+ return 1
42
+ with open(session_file, "r", encoding="utf-8") as f:
43
+ try:
44
+ messages = json.load(f)
45
+ except Exception as e:
46
+ print(f"Failed to load session: {e}")
47
+ return 1
48
+ print(f"Conversation history for session '{args.view}':\n")
49
+ for i, msg in enumerate(messages, 1):
50
+ role = msg.get("role", "?")
51
+ content = msg.get("content", "")
52
+ print(f"[{i}] {role}: {content}\n")
53
+ return 0
54
+
55
+
56
+ def handle_lang_selection(args):
57
+ import janito.i18n as i18n
58
+ from janito.agent.runtime_config import runtime_config
59
+
60
+ lang = getattr(args, "lang", None) or unified_config.get("lang", None) or "en"
61
+ runtime_config.set("lang", lang)
62
+ i18n.set_locale(lang)
63
+
64
+
65
+ def handle_help_config(args):
66
+ from janito.agent.config import CONFIG_OPTIONS
67
+ from janito.agent.config_defaults import CONFIG_DEFAULTS
68
+
69
+ print(tr("Available configuration options:\n"))
70
+ for key, desc in CONFIG_OPTIONS.items():
71
+ default = CONFIG_DEFAULTS.get(key, None)
72
+ print(
73
+ tr(
74
+ "{key:15} {desc} (default: {default})",
75
+ key=key,
76
+ desc=desc,
77
+ default=default,
78
+ )
79
+ )
80
+
81
+
82
+ def handle_list_tools(args):
83
+ from janito.agent.tool_registry import get_tool_schemas
84
+ from rich.console import Console
85
+ from rich.table import Table
86
+
87
+ console = Console()
88
+ table = Table(
89
+ title="Ferramentas Registradas", show_lines=True, style="bold magenta"
90
+ )
91
+ table.add_column("Gnome", style="cyan", no_wrap=True)
92
+ table.add_column("Descrição", style="green")
93
+ table.add_column("Parâmetros", style="yellow")
94
+ for schema in get_tool_schemas():
95
+ fn = schema["function"]
96
+ params = "\n".join(
97
+ [
98
+ f"[bold]{k}[/]: {v['type']}"
99
+ for k, v in fn["parameters"].get("properties", {}).items()
100
+ ]
101
+ )
102
+ table.add_row(f"[b]{fn['name']}[/b]", fn["description"], params or "-")
103
+ console.print(table)
104
+
105
+
106
+ def handle_info(args):
107
+ from janito import __version__
108
+ from rich.console import Console
109
+ from rich.text import Text
110
+ from janito.agent.runtime_config import runtime_config
111
+
112
+ model = unified_config.get("model")
113
+ temperature = unified_config.get("temperature")
114
+ max_tokens = unified_config.get("max_tokens")
115
+ system_prompt_val = None
116
+ if getattr(args, "system_file", None):
117
+ try:
118
+ with open(args.system_file, "r", encoding="utf-8") as f:
119
+ system_prompt_val = f.read().strip()
120
+ runtime_config.set("system_prompt_template", system_prompt_val)
121
+ except Exception as e:
122
+ system_prompt_val = f"(error reading system-file: {e})"
123
+ elif getattr(args, "system", None):
124
+ system_prompt_val = args.system
125
+ runtime_config.set("system_prompt_template", system_prompt_val)
126
+ else:
127
+ system_prompt_val = runtime_config.get("system_prompt_template")
128
+ if not system_prompt_val:
129
+ try:
130
+ from janito.agent.profile_manager import AgentProfileManager
131
+ from janito.agent.config import get_api_key
132
+
133
+ role = args.role or unified_config.get("role", "software engineer")
134
+ interaction_mode = "chat" if not getattr(args, "prompt", None) else "prompt"
135
+ profile = "base"
136
+ profile_manager = AgentProfileManager(
137
+ api_key=get_api_key(),
138
+ model=unified_config.get("model"),
139
+ )
140
+ system_prompt_val = profile_manager.get_system_prompt(
141
+ role, interaction_mode, profile
142
+ )
143
+ except Exception as e:
144
+ system_prompt_val = f"(error: {e})"
145
+ console = Console()
146
+ info_text = Text()
147
+ info_text.append(f"Janito v{__version__}", style="bold cyan")
148
+ info_text.append(" | model: ", style="white")
149
+ info_text.append(str(model), style="green")
150
+ info_text.append(" | temp: ", style="white")
151
+ info_text.append(str(temperature), style="yellow")
152
+ info_text.append(" | max_tokens: ", style="white")
153
+ info_text.append(str(max_tokens), style="magenta")
154
+ info_text.append(" | system: ", style="white")
155
+ info_text.append(str(system_prompt_val), style="bold blue")
156
+ console.print(info_text, style="dim")
157
+
158
+
15
159
  def main():
16
160
  """Unified entry point for the Janito CLI and web server."""
17
161
  import sys
18
-
19
162
  from janito.agent.config import local_config, global_config
20
- import janito.i18n as i18n
21
- from janito.agent.runtime_config import runtime_config
22
163
 
23
164
  local_config.load()
24
165
  global_config.load()
25
-
26
166
  parser = create_parser()
27
167
  args = parser.parse_args()
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
168
  # Handle --list [n] before anything else
60
169
  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.")
170
+ if handle_list_sessions(args):
68
171
  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
172
  # Handle --view <id> to print conversation history
78
173
  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
-
100
- # Seleção de idioma: prioridade --lang > config.json > padrão
101
- lang = getattr(args, "lang", None) or unified_config.get("lang", None) or "en"
102
- runtime_config.set("lang", lang)
103
- i18n.set_locale(lang)
104
-
105
- from janito.agent.config import CONFIG_OPTIONS
106
- from janito.agent.config_defaults import CONFIG_DEFAULTS
107
-
174
+ sys.exit(handle_view_session(args))
175
+ handle_lang_selection(args)
108
176
  if getattr(args, "help_config", False):
109
- print(tr("Available configuration options:\n"))
110
- for key, desc in CONFIG_OPTIONS.items():
111
- default = CONFIG_DEFAULTS.get(key, None)
112
- print(
113
- tr(
114
- "{key:15} {desc} (default: {default})",
115
- key=key,
116
- desc=desc,
117
- default=default,
118
- )
119
- )
177
+ handle_help_config(args)
120
178
  sys.exit(0)
121
-
122
179
  if getattr(args, "list_tools", False):
123
- from janito.agent.tool_registry import get_tool_schemas
124
- from rich.console import Console
125
- from rich.table import Table
126
-
127
- console = Console()
128
- table = Table(
129
- title="Ferramentas Registradas", show_lines=True, style="bold magenta"
130
- )
131
- table.add_column("Gnome", style="cyan", no_wrap=True)
132
- table.add_column("Descrição", style="green")
133
- table.add_column("Parâmetros", style="yellow")
134
- for schema in get_tool_schemas():
135
- fn = schema["function"]
136
- params = "\n".join(
137
- [
138
- f"[bold]{k}[/]: {v['type']}"
139
- for k, v in fn["parameters"].get("properties", {}).items()
140
- ]
141
- )
142
- table.add_row(f"[b]{fn['name']}[/b]", fn["description"], params or "-")
143
- console.print(table)
180
+ handle_list_tools(args)
144
181
  sys.exit(0)
145
-
146
182
  if getattr(args, "info", False):
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
151
- from janito.agent.runtime_config import runtime_config
152
-
153
- model = unified_config.get("model")
154
- temperature = unified_config.get("temperature")
155
- max_tokens = unified_config.get("max_tokens")
156
- system_prompt_val = None
157
- if getattr(args, "system_file", None):
158
- try:
159
- with open(args.system_file, "r", encoding="utf-8") as f:
160
- system_prompt_val = f.read().strip()
161
- runtime_config.set("system_prompt_template", system_prompt_val)
162
- except Exception as e:
163
- system_prompt_val = f"(error reading system-file: {e})"
164
- elif getattr(args, "system", None):
165
- system_prompt_val = args.system
166
- runtime_config.set("system_prompt_template", system_prompt_val)
167
- else:
168
- system_prompt_val = runtime_config.get("system_prompt_template")
169
- # if system_prompt_val:
170
- # origem = "runtime_config"
171
- if not system_prompt_val:
172
- try:
173
- from janito.agent.profile_manager import AgentProfileManager
174
- from janito.agent.config import get_api_key
175
-
176
- role = args.role or unified_config.get("role", "software engineer")
177
- interaction_mode = (
178
- "chat" if not getattr(args, "prompt", None) else "prompt"
179
- )
180
- profile = "base"
181
- profile_manager = AgentProfileManager(
182
- api_key=get_api_key(),
183
- model=unified_config.get("model"),
184
- )
185
- system_prompt_val = profile_manager.get_system_prompt(
186
- role, interaction_mode, profile
187
- )
188
- except Exception as e:
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.
204
-
205
- # ... resto do main ...
183
+ handle_info(args)
206
184
  handle_config_commands(args)
207
185
  setup_verbose_logging(args)
208
186
  if getattr(args, "web", False):
209
- import subprocess # Only needed if launching web
187
+ import subprocess
210
188
 
211
189
  subprocess.run([sys.executable, "-m", "janito.web"])
212
190
  elif getattr(args, "live", False):
213
- port = 35729 # Default livereload port
191
+ port = 35729
214
192
  livereload_proc, started, livereload_stdout_path, livereload_stderr_path = (
215
193
  start_livereload(port)
216
194
  )
janito/cli/one_shot.py CHANGED
@@ -3,15 +3,12 @@ from janito.agent.conversation_exceptions import (
3
3
  ProviderError,
4
4
  EmptyResponseError,
5
5
  )
6
+ from janito.agent.api_exceptions import ApiError
7
+ from janito.agent.llm_conversation_history import LLMConversationHistory
6
8
 
7
9
 
8
- def run_oneshot_mode(args, profile_manager, runtime_config):
10
+ def prepare_messages(args, profile_manager, runtime_config):
9
11
  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
12
  messages = []
16
13
  system_prompt_override = runtime_config.get("system_prompt_template")
17
14
  if system_prompt_override:
@@ -26,41 +23,58 @@ def run_oneshot_mode(args, profile_manager, runtime_config):
26
23
  {"role": "system", "content": profile_manager.system_prompt_template}
27
24
  )
28
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
29
49
  import time
30
50
 
51
+ console = Console()
52
+ message_handler = RichMessageHandler()
53
+ messages = prepare_messages(args, profile_manager, runtime_config)
31
54
  info_start_time = None
32
55
  if getattr(args, "info", False):
33
56
  info_start_time = time.time()
34
57
  try:
35
58
  max_rounds = 100
36
- from janito.agent.conversation_history import ConversationHistory
37
-
38
59
  result = profile_manager.agent.chat(
39
- ConversationHistory(messages),
60
+ LLMConversationHistory(messages),
40
61
  message_handler=message_handler,
41
62
  spinner=True,
42
63
  max_rounds=max_rounds,
43
- stream=getattr(args, "stream", False),
44
64
  )
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
- )
65
+ print_usage_info(args, info_start_time, result, console)
61
66
  except MaxRoundsExceededError:
62
67
  console.print("[red]Max conversation rounds exceeded.[/red]")
63
68
  except ProviderError as e:
64
69
  console.print(f"[red]Provider error:[/red] {e}")
65
70
  except EmptyResponseError as e:
66
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
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)
janito/rich_utils.py CHANGED
@@ -3,19 +3,57 @@ Utilities for working with the Rich library.
3
3
  """
4
4
 
5
5
  from rich.console import Console
6
+ from typing import Optional
6
7
 
7
8
 
8
- def print_info(console: Console, message: str):
9
- console.print(message, style="cyan", end="")
9
+ class RichPrinter:
10
+ """
11
+ Utility class for printing styled messages using the Rich library.
10
12
 
13
+ Args:
14
+ console (Optional[Console]): An optional Rich Console instance. If not provided, a default Console will be created.
11
15
 
12
- def print_error(console: Console, message: str):
13
- console.print(message, style="bold red", end="\n")
16
+ Methods:
17
+ print_info(message: str)
18
+ Print an informational message in cyan (no newline at end).
14
19
 
20
+ print_error(message: str)
21
+ Print an error message in bold red.
15
22
 
16
- def print_warning(console: Console, message: str):
17
- console.print(message, style="bold yellow", end="\n")
23
+ print_warning(message: str)
24
+ Print a warning message in bold yellow.
18
25
 
26
+ print_magenta(message: str)
27
+ Print a message in magenta.
28
+ """
19
29
 
20
- def print_magenta(console: Console, message: str):
21
- console.print(message, style="magenta", end="\n")
30
+ def __init__(self, console: Optional[Console] = None):
31
+ self.console = console or Console()
32
+
33
+ def print_info(self, message: str):
34
+ self.console.print(message, style="cyan", end="")
35
+
36
+ def print_error(self, message: str):
37
+ self.console.print(message, style="bold red", end="\n")
38
+
39
+ def print_warning(self, message: str):
40
+ self.console.print(message, style="bold yellow", end="\n")
41
+
42
+ def print_magenta(self, message: str):
43
+ self.console.print(message, style="magenta", end="\n")
44
+
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")
@@ -6,14 +6,13 @@ from .utility import handle_help, handle_clear, handle_multi
6
6
  from .tools import handle_tools
7
7
  from .termweb_log import handle_termweb_log_tail, handle_termweb_status
8
8
  from .livelogs import handle_livelogs
9
- from .sum import handle_sum
10
9
  from .edit import handle_edit
11
-
12
10
  from .history_view import handle_view
13
11
  from janito.shell.session.config import handle_config_shell
14
12
  from .verbose import handle_verbose
15
13
  from .lang import handle_lang
16
14
  from janito.agent.runtime_config import runtime_config
15
+ from .track import handle_track
17
16
 
18
17
  COMMAND_HANDLERS = {
19
18
  "/termweb-logs": handle_termweb_log_tail,
@@ -35,12 +34,11 @@ COMMAND_HANDLERS = {
35
34
  if not runtime_config.get("vanilla_mode", False):
36
35
  COMMAND_HANDLERS["/role"] = handle_role
37
36
 
38
-
39
37
  COMMAND_HANDLERS["/lang"] = handle_lang
38
+ COMMAND_HANDLERS["/track"] = handle_track
40
39
 
41
40
  COMMAND_HANDLERS.update(
42
41
  {
43
- "/sum": handle_sum,
44
42
  "/clear": handle_clear,
45
43
  "/restart": handle_restart,
46
44
  "/config": handle_config_shell,
@@ -1,6 +1,5 @@
1
1
  import os
2
2
 
3
-
4
3
  from janito.shell.session.manager import reset_session_id
5
4
 
6
5
 
@@ -70,3 +69,6 @@ def handle_restart(console, shell_state=None, **kwargs):
70
69
  console.print(
71
70
  "[bold green]Conversation history has been started (context reset).[/bold green]"
72
71
  )
72
+
73
+
74
+ handle_restart.help_text = "Start a new conversation (reset context)"
@@ -19,3 +19,6 @@ def handle_edit(console, args=None, shell_state=None, **kwargs):
19
19
  f"[green]Opening in browser:[/green] [underline blue]{url}[/underline blue]"
20
20
  )
21
21
  webbrowser.open(url)
22
+
23
+
24
+ handle_edit.help_text = "Open a file in the browser-based editor"
@@ -1,7 +1,4 @@
1
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
2
  messages = shell_state.conversation_history.get_messages()
6
3
  if not messages:
7
4
  console.print("[yellow]Conversation history is empty.[/yellow]")
@@ -16,3 +13,6 @@ def handle_view(console, args=None, shell_state=None, **kwargs):
16
13
  console.print(f" [cyan]tool_calls:[/cyan] {tool_calls}")
17
14
  if tool_call_id:
18
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)"
@@ -1,7 +1,4 @@
1
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
2
  lines = 20
6
3
  if args and len(args) > 0 and str(args[0]).isdigit():
7
4
  lines = int(args[0])
@@ -38,3 +35,8 @@ def handle_livelogs(console, args=None, shell_state=None, **kwargs):
38
35
  console.print(f"[red][livereload][stderr] Error: {e}[/red]")
39
36
  if (not stdout_path or not stdout_lines) and (not stderr_path or not stderr_lines):
40
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
+ )
@@ -9,6 +9,9 @@ def handle_prompt(console, shell_state=None, **kwargs):
9
9
  console.print(f"[bold magenta]System Prompt:[/bold magenta]\n{prompt}")
10
10
 
11
11
 
12
+ handle_prompt.help_text = "Show the system prompt"
13
+
14
+
12
15
  def handle_role(console, args=None, shell_state=None, **kwargs):
13
16
  profile_manager = (
14
17
  shell_state.profile_manager
@@ -40,6 +43,9 @@ def handle_role(console, args=None, shell_state=None, **kwargs):
40
43
  console.print(f"[bold green]System role updated to:[/bold green] {new_role}")
41
44
 
42
45
 
46
+ handle_role.help_text = "Change the system role"
47
+
48
+
43
49
  def handle_profile(console, *args, **kwargs):
44
50
  """/profile - Show the current and available Agent Profile (only 'base' is supported)"""
45
51
  console.print("[bold green]Current profile:[/bold green] base")
@@ -30,3 +30,6 @@ def handle_history(console, shell_state=None, *args, **kwargs):
30
30
  role = "user"
31
31
  content = line
32
32
  console.print(f"[bold]{idx} [{role}]:[/bold] {content}")
33
+
34
+
35
+ handle_history.help_text = "Show input history for this session"
@@ -40,3 +40,6 @@ 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
+ handle_exit.help_text = "Exit chat mode"
@@ -51,6 +51,9 @@ def handle_termweb_log_tail(console: Console, *args, shell_state=None, **kwargs)
51
51
  console.print("[termweb] No output or errors captured in logs.")
52
52
 
53
53
 
54
+ handle_termweb_log_tail.help_text = "Show the last lines of the latest termweb logs"
55
+
56
+
54
57
  def handle_termweb_status(console: Console, *args, shell_state=None, **kwargs):
55
58
  if shell_state is None:
56
59
  console.print(
@@ -84,3 +87,8 @@ def handle_termweb_status(console: Console, *args, shell_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
+ )