janito 1.8.1__py3-none-any.whl → 1.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/api_exceptions.py +4 -0
  3. janito/agent/config.py +1 -1
  4. janito/agent/config_defaults.py +2 -3
  5. janito/agent/config_utils.py +0 -9
  6. janito/agent/conversation.py +177 -114
  7. janito/agent/conversation_api.py +179 -159
  8. janito/agent/conversation_tool_calls.py +11 -8
  9. janito/agent/llm_conversation_history.py +70 -0
  10. janito/agent/openai_client.py +44 -21
  11. janito/agent/openai_schema_generator.py +164 -128
  12. janito/agent/platform_discovery.py +134 -77
  13. janito/agent/profile_manager.py +5 -5
  14. janito/agent/rich_message_handler.py +80 -31
  15. janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +9 -8
  16. janito/agent/test_openai_schema_generator.py +93 -0
  17. janito/agent/tool_base.py +7 -2
  18. janito/agent/tool_executor.py +63 -50
  19. janito/agent/tool_registry.py +5 -2
  20. janito/agent/tool_use_tracker.py +42 -5
  21. janito/agent/tools/__init__.py +13 -12
  22. janito/agent/tools/create_directory.py +9 -6
  23. janito/agent/tools/create_file.py +35 -54
  24. janito/agent/tools/delete_text_in_file.py +97 -0
  25. janito/agent/tools/fetch_url.py +50 -5
  26. janito/agent/tools/find_files.py +40 -26
  27. janito/agent/tools/get_file_outline/__init__.py +1 -0
  28. janito/agent/tools/{outline_file/__init__.py → get_file_outline/core.py} +14 -18
  29. janito/agent/tools/get_file_outline/python_outline.py +134 -0
  30. janito/agent/tools/{search_outline.py → get_file_outline/search_outline.py} +11 -0
  31. janito/agent/tools/get_lines.py +21 -12
  32. janito/agent/tools/move_file.py +13 -12
  33. janito/agent/tools/present_choices.py +3 -1
  34. janito/agent/tools/python_command_runner.py +150 -0
  35. janito/agent/tools/python_file_runner.py +148 -0
  36. janito/agent/tools/python_stdin_runner.py +154 -0
  37. janito/agent/tools/remove_directory.py +4 -2
  38. janito/agent/tools/remove_file.py +15 -13
  39. janito/agent/tools/replace_file.py +72 -0
  40. janito/agent/tools/replace_text_in_file.py +7 -5
  41. janito/agent/tools/run_bash_command.py +29 -72
  42. janito/agent/tools/run_powershell_command.py +142 -102
  43. janito/agent/tools/search_text.py +177 -131
  44. janito/agent/tools/validate_file_syntax/__init__.py +1 -0
  45. janito/agent/tools/validate_file_syntax/core.py +94 -0
  46. janito/agent/tools/validate_file_syntax/css_validator.py +35 -0
  47. janito/agent/tools/validate_file_syntax/html_validator.py +77 -0
  48. janito/agent/tools/validate_file_syntax/js_validator.py +27 -0
  49. janito/agent/tools/validate_file_syntax/json_validator.py +6 -0
  50. janito/agent/tools/validate_file_syntax/markdown_validator.py +66 -0
  51. janito/agent/tools/validate_file_syntax/ps1_validator.py +32 -0
  52. janito/agent/tools/validate_file_syntax/python_validator.py +5 -0
  53. janito/agent/tools/validate_file_syntax/xml_validator.py +11 -0
  54. janito/agent/tools/validate_file_syntax/yaml_validator.py +6 -0
  55. janito/agent/tools_utils/__init__.py +1 -0
  56. janito/agent/tools_utils/action_type.py +7 -0
  57. janito/agent/tools_utils/dir_walk_utils.py +24 -0
  58. janito/agent/tools_utils/formatting.py +49 -0
  59. janito/agent/tools_utils/gitignore_utils.py +69 -0
  60. janito/agent/tools_utils/test_gitignore_utils.py +46 -0
  61. janito/agent/tools_utils/utils.py +30 -0
  62. janito/cli/_livereload_log_utils.py +13 -0
  63. janito/cli/_print_config.py +63 -61
  64. janito/cli/arg_parser.py +57 -14
  65. janito/cli/cli_main.py +270 -0
  66. janito/cli/livereload_starter.py +60 -0
  67. janito/cli/main.py +166 -99
  68. janito/cli/one_shot.py +80 -0
  69. janito/cli/termweb_starter.py +2 -2
  70. janito/i18n/__init__.py +1 -1
  71. janito/livereload/app.py +25 -0
  72. janito/rich_utils.py +41 -25
  73. janito/{cli_chat_shell → shell}/commands/__init__.py +19 -14
  74. janito/{cli_chat_shell → shell}/commands/config.py +4 -4
  75. janito/shell/commands/conversation_restart.py +74 -0
  76. janito/shell/commands/edit.py +24 -0
  77. janito/shell/commands/history_view.py +18 -0
  78. janito/{cli_chat_shell → shell}/commands/lang.py +3 -0
  79. janito/shell/commands/livelogs.py +42 -0
  80. janito/{cli_chat_shell → shell}/commands/prompt.py +16 -6
  81. janito/shell/commands/session.py +35 -0
  82. janito/{cli_chat_shell → shell}/commands/session_control.py +3 -5
  83. janito/{cli_chat_shell → shell}/commands/termweb_log.py +18 -10
  84. janito/shell/commands/tools.py +26 -0
  85. janito/shell/commands/track.py +36 -0
  86. janito/shell/commands/utility.py +28 -0
  87. janito/{cli_chat_shell → shell}/commands/verbose.py +4 -5
  88. janito/shell/commands.py +40 -0
  89. janito/shell/input_history.py +62 -0
  90. janito/shell/main.py +257 -0
  91. janito/{cli_chat_shell/shell_command_completer.py → shell/prompt/completer.py} +1 -1
  92. janito/{cli_chat_shell/chat_ui.py → shell/prompt/session_setup.py} +19 -5
  93. janito/shell/session/manager.py +101 -0
  94. janito/{cli_chat_shell/ui.py → shell/ui/interactive.py} +23 -17
  95. janito/termweb/app.py +3 -3
  96. janito/termweb/static/editor.css +142 -0
  97. janito/termweb/static/editor.css.bak +27 -0
  98. janito/termweb/static/editor.html +15 -213
  99. janito/termweb/static/editor.html.bak +16 -215
  100. janito/termweb/static/editor.js +209 -0
  101. janito/termweb/static/editor.js.bak +227 -0
  102. janito/termweb/static/index.html +2 -3
  103. janito/termweb/static/index.html.bak +2 -3
  104. janito/termweb/static/termweb.css.bak +33 -84
  105. janito/termweb/static/termweb.js +15 -34
  106. janito/termweb/static/termweb.js.bak +18 -36
  107. janito/tests/test_rich_utils.py +44 -0
  108. janito/web/app.py +0 -75
  109. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/METADATA +62 -42
  110. janito-1.10.0.dist-info/RECORD +158 -0
  111. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/WHEEL +1 -1
  112. janito/agent/tools/dir_walk_utils.py +0 -16
  113. janito/agent/tools/gitignore_utils.py +0 -46
  114. janito/agent/tools/memory.py +0 -48
  115. janito/agent/tools/outline_file/formatting.py +0 -20
  116. janito/agent/tools/outline_file/python_outline.py +0 -71
  117. janito/agent/tools/present_choices_test.py +0 -18
  118. janito/agent/tools/rich_live.py +0 -44
  119. janito/agent/tools/run_python_command.py +0 -163
  120. janito/agent/tools/tools_utils.py +0 -56
  121. janito/agent/tools/utils.py +0 -33
  122. janito/agent/tools/validate_file_syntax.py +0 -163
  123. janito/cli/runner/cli_main.py +0 -180
  124. janito/cli_chat_shell/chat_loop.py +0 -163
  125. janito/cli_chat_shell/chat_state.py +0 -38
  126. janito/cli_chat_shell/commands/history_start.py +0 -37
  127. janito/cli_chat_shell/commands/session.py +0 -48
  128. janito/cli_chat_shell/commands/sum.py +0 -49
  129. janito/cli_chat_shell/commands/utility.py +0 -32
  130. janito/cli_chat_shell/session_manager.py +0 -72
  131. janito-1.8.1.dist-info/RECORD +0 -127
  132. /janito/agent/tools/{outline_file → get_file_outline}/markdown_outline.py +0 -0
  133. /janito/cli/{runner/_termweb_log_utils.py → _termweb_log_utils.py} +0 -0
  134. /janito/cli/{runner/config.py → config_runner.py} +0 -0
  135. /janito/cli/{runner/formatting.py → formatting_runner.py} +0 -0
  136. /janito/{cli/runner → shell}/__init__.py +0 -0
  137. /janito/{cli_chat_shell → shell/prompt}/load_prompt.py +0 -0
  138. /janito/{cli_chat_shell/config_shell.py → shell/session/config.py} +0 -0
  139. /janito/{cli_chat_shell/__init__.py → shell/session/history.py} +0 -0
  140. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/entry_points.txt +0 -0
  141. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/licenses/LICENSE +0 -0
  142. {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/top_level.txt +0 -0
janito/cli/cli_main.py ADDED
@@ -0,0 +1,270 @@
1
+ import sys
2
+ from janito.agent.llm_conversation_history import LLMConversationHistory
3
+ import socket
4
+ from janito.agent.profile_manager import AgentProfileManager
5
+ from janito.agent.runtime_config import unified_config, runtime_config
6
+ from janito.agent.config import get_api_key
7
+ from janito import __version__
8
+ from janito.agent.conversation_exceptions import (
9
+ MaxRoundsExceededError,
10
+ EmptyResponseError,
11
+ ProviderError,
12
+ )
13
+ from janito.shell.main import start_chat_shell
14
+
15
+
16
+ def is_port_free(port):
17
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
18
+ return s.connect_ex(("localhost", port)) != 0
19
+
20
+
21
+ def normalize_args(args):
22
+ if getattr(args, "vanilla", False):
23
+ runtime_config.set("vanilla_mode", True)
24
+ if getattr(args, "ntt", False):
25
+ runtime_config.set("no_tools_tracking", True)
26
+ for flag in [
27
+ "verbose_http",
28
+ "verbose_http_raw",
29
+ "verbose_response",
30
+ "verbose_reason",
31
+ "verbose_tools",
32
+ "verbose_events",
33
+ "verbose_messages",
34
+ ]:
35
+ if hasattr(args, flag):
36
+ runtime_config.set(flag, getattr(args, flag, False))
37
+ if getattr(args, "trust_tools", False):
38
+ runtime_config.set("trust_tools", True)
39
+ if getattr(args, "model", None):
40
+ runtime_config.set("model", args.model)
41
+ if getattr(args, "max_tools", None) is not None:
42
+ runtime_config.set("max_tools", args.max_tools)
43
+ if getattr(args, "verbose_reason", False):
44
+ runtime_config.set("verbose_reason", True)
45
+ if getattr(args, "max_tokens", None) is not None:
46
+ runtime_config.set("max_tokens", args.max_tokens)
47
+
48
+
49
+ def setup_profile_manager(args, role, interaction_mode, profile, lang):
50
+ return AgentProfileManager(
51
+ api_key=get_api_key(),
52
+ model=unified_config.get("model"),
53
+ role=role,
54
+ profile_name=profile,
55
+ interaction_mode=interaction_mode,
56
+ verbose_tools=args.verbose_tools,
57
+ base_url=unified_config.get("base_url", ""),
58
+ azure_openai_api_version=unified_config.get(
59
+ "azure_openai_api_version", "2023-05-15"
60
+ ),
61
+ use_azure_openai=unified_config.get("use_azure_openai", False),
62
+ lang=lang,
63
+ )
64
+
65
+
66
+ def handle_termweb(args, interaction_mode):
67
+ termweb_proc = None
68
+ selected_port = None
69
+ termweb_stdout_path = None
70
+ termweb_stderr_path = None
71
+ if (
72
+ not getattr(args, "no_termweb", False)
73
+ and interaction_mode == "chat"
74
+ and not runtime_config.get("vanilla_mode", False)
75
+ and not getattr(args, "input_arg", None)
76
+ ):
77
+ default_port = 8088
78
+ max_port = 8100
79
+ requested_port = args.termweb_port
80
+ if requested_port == default_port:
81
+ for port in range(default_port, max_port + 1):
82
+ if is_port_free(port):
83
+ selected_port = port
84
+ break
85
+ if selected_port is None:
86
+ from rich.console import Console
87
+
88
+ console = Console()
89
+ console.print(
90
+ f"[red]No free port found for termweb in range {default_port}-{max_port}.[/red]"
91
+ )
92
+ sys.exit(1)
93
+ else:
94
+ if not is_port_free(requested_port):
95
+ from rich.console import Console
96
+
97
+ console = Console()
98
+ console.print(
99
+ f"[red]Port {requested_port} is not available for termweb.[/red]"
100
+ )
101
+ sys.exit(1)
102
+ selected_port = requested_port
103
+ runtime_config.set("termweb_port", selected_port)
104
+ from janito.cli.termweb_starter import start_termweb
105
+
106
+ termweb_proc, started, termweb_stdout_path, termweb_stderr_path = start_termweb(
107
+ selected_port
108
+ )
109
+ if started:
110
+ from janito.agent.config import local_config
111
+
112
+ local_config.set("termweb_last_running_port", selected_port)
113
+ local_config.save()
114
+ return termweb_proc, termweb_stdout_path, termweb_stderr_path
115
+
116
+
117
+ def handle_continue_session(args):
118
+ continue_session = False
119
+ session_id = None
120
+ if getattr(args, "input_arg", None) or getattr(args, "continue_session", False):
121
+ _cont = getattr(args, "continue_session", False)
122
+ if _cont:
123
+ continue_session = True
124
+ session_id = getattr(args, "input_arg", None)
125
+ if session_id is None:
126
+ import os
127
+ import glob
128
+
129
+ chat_hist_dir = (
130
+ os.path.join(os.path.expanduser("~"), ".janito", "chat_history")
131
+ if not os.path.isabs(".janito")
132
+ else os.path.join(".janito", "chat_history")
133
+ )
134
+ if not os.path.exists(chat_hist_dir):
135
+ session_id = None
136
+ else:
137
+ files = glob.glob(os.path.join(chat_hist_dir, "*.json"))
138
+ if files:
139
+ latest = max(files, key=os.path.getmtime)
140
+ session_id = os.path.splitext(os.path.basename(latest))[0]
141
+ else:
142
+ session_id = None
143
+ else:
144
+ continue_session = False
145
+ session_id = None
146
+ return continue_session, session_id
147
+
148
+
149
+ def handle_prompt_mode(args, profile_manager):
150
+ prompt = getattr(args, "input_arg", None)
151
+ from rich.console import Console
152
+ from janito.agent.rich_message_handler import RichMessageHandler
153
+
154
+ console = Console()
155
+ message_handler = RichMessageHandler()
156
+ messages = []
157
+ system_prompt_override = runtime_config.get("system_prompt_template")
158
+ if system_prompt_override:
159
+ if not runtime_config.get("vanilla_mode", False) or getattr(
160
+ args, "system", None
161
+ ):
162
+ messages.append({"role": "system", "content": system_prompt_override})
163
+ elif profile_manager.system_prompt_template and not runtime_config.get(
164
+ "vanilla_mode", False
165
+ ):
166
+ messages.append(
167
+ {"role": "system", "content": profile_manager.system_prompt_template}
168
+ )
169
+ messages.append({"role": "user", "content": prompt})
170
+ import time
171
+
172
+ info_start_time = None
173
+ if getattr(args, "info", False):
174
+ info_start_time = time.time()
175
+ try:
176
+ max_rounds = 100
177
+ result = profile_manager.agent.chat(
178
+ LLMConversationHistory(messages),
179
+ message_handler=message_handler,
180
+ spinner=True,
181
+ max_rounds=max_rounds,
182
+ tool_user=getattr(args, "tool_user", False),
183
+ )
184
+ if (
185
+ getattr(args, "info", False)
186
+ and info_start_time is not None
187
+ and result is not None
188
+ ):
189
+ usage_info = result.get("usage")
190
+ total_tokens = usage_info.get("total_tokens") if usage_info else None
191
+ prompt_tokens = usage_info.get("prompt_tokens") if usage_info else None
192
+ completion_tokens = (
193
+ usage_info.get("completion_tokens") if usage_info else None
194
+ )
195
+ elapsed = time.time() - info_start_time
196
+ console.print(
197
+ 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]",
198
+ style="dim",
199
+ )
200
+ except MaxRoundsExceededError:
201
+ console.print("[red]Max conversation rounds exceeded.[/red]")
202
+ except ProviderError as e:
203
+ console.print(f"[red]Provider error:[/red] {e}")
204
+ except EmptyResponseError as e:
205
+ console.print(f"[red]Error:[/red] {e}")
206
+
207
+
208
+ def run_cli(args):
209
+ if args.version:
210
+ print(f"janito version {__version__}")
211
+ sys.exit(0)
212
+ normalize_args(args)
213
+ role = args.role or unified_config.get("role", "software engineer")
214
+ if args.role:
215
+ runtime_config.set("role", args.role)
216
+ interaction_mode = "chat" if not getattr(args, "prompt", None) else "prompt"
217
+ profile = "base"
218
+ lang = getattr(args, "lang", None) or runtime_config.get("lang", "en")
219
+ profile_manager = setup_profile_manager(args, role, interaction_mode, profile, lang)
220
+ profile_manager.refresh_prompt()
221
+ if getattr(args, "show_system", False):
222
+ print(profile_manager.render_prompt())
223
+ sys.exit(0)
224
+ termweb_proc, termweb_stdout_path, termweb_stderr_path = handle_termweb(
225
+ args, interaction_mode
226
+ )
227
+ try:
228
+ continue_session, session_id = handle_continue_session(args)
229
+ if getattr(args, "input_arg", None):
230
+ from janito.cli.one_shot import run_oneshot_mode
231
+
232
+ run_oneshot_mode(args, profile_manager, runtime_config)
233
+ return
234
+ import time
235
+
236
+ info_start_time = None
237
+ if getattr(args, "info", False):
238
+ info_start_time = time.time()
239
+ usage_info = start_chat_shell(
240
+ profile_manager,
241
+ continue_session=continue_session,
242
+ session_id=session_id,
243
+ termweb_stdout_path=termweb_stdout_path,
244
+ termweb_stderr_path=termweb_stderr_path,
245
+ livereload_stdout_path=None,
246
+ livereload_stderr_path=None,
247
+ )
248
+ if (
249
+ getattr(args, "info", False)
250
+ and usage_info is not None
251
+ and info_start_time is not None
252
+ ):
253
+ elapsed = time.time() - info_start_time
254
+ from rich.console import Console
255
+
256
+ total_tokens = usage_info.get("total_tokens")
257
+ console = Console()
258
+ console.print(
259
+ f"[bold green]Total tokens used:[/] [yellow]{total_tokens}[/yellow] [bold green]| Elapsed time:[/] [yellow]{elapsed:.2f}s[/yellow]"
260
+ )
261
+ sys.exit(0)
262
+ except KeyboardInterrupt:
263
+ from rich.console import Console
264
+
265
+ console = Console()
266
+ console.print("[yellow]Interrupted by user.[/yellow]")
267
+ finally:
268
+ if termweb_proc:
269
+ termweb_proc.terminate()
270
+ termweb_proc.wait()
@@ -0,0 +1,60 @@
1
+ import sys
2
+ import subprocess
3
+ import tempfile
4
+ import time
5
+ import http.client
6
+ import os
7
+ from rich.console import Console
8
+
9
+
10
+ def wait_for_livereload(port, timeout=3.0):
11
+ deadline = time.time() + timeout
12
+ while time.time() < deadline:
13
+ try:
14
+ conn = http.client.HTTPConnection("localhost", port, timeout=0.5)
15
+ conn.request("GET", "/")
16
+ resp = conn.getresponse()
17
+ if resp.status in (200, 404):
18
+ return True
19
+ except Exception:
20
+ pass
21
+ time.sleep(0.1)
22
+ return False
23
+
24
+
25
+ def start_livereload(selected_port):
26
+ console = Console()
27
+ with console.status("[cyan]Starting live reload server...", spinner="dots"):
28
+ app_py_path = os.path.join(
29
+ os.path.dirname(__file__), "..", "livereload", "app.py"
30
+ )
31
+ app_py_path = os.path.abspath(app_py_path)
32
+ if not os.path.isfile(app_py_path):
33
+ console.print("[red]Could not find livereload app.py![/red]")
34
+ return None, False, None, None
35
+ livereload_stdout = tempfile.NamedTemporaryFile(
36
+ delete=False, mode="w+", encoding="utf-8"
37
+ )
38
+ livereload_stderr = tempfile.NamedTemporaryFile(
39
+ delete=False, mode="w+", encoding="utf-8"
40
+ )
41
+ livereload_proc = subprocess.Popen(
42
+ [sys.executable, app_py_path, "--port", str(selected_port)],
43
+ stdout=livereload_stdout,
44
+ stderr=livereload_stderr,
45
+ )
46
+ if wait_for_livereload(selected_port, timeout=3.0):
47
+ console.print(
48
+ f"LiveReload started... Available at http://localhost:{selected_port}"
49
+ )
50
+ return livereload_proc, True, livereload_stdout.name, livereload_stderr.name
51
+ else:
52
+ livereload_proc.terminate()
53
+ livereload_proc.wait()
54
+ from janito.cli._livereload_log_utils import print_livereload_logs
55
+
56
+ console.print(
57
+ f"[red]Failed to start LiveReload on port {selected_port}. Check logs for details.[/red]"
58
+ )
59
+ print_livereload_logs(livereload_stdout.name, livereload_stderr.name)
60
+ return None, False, livereload_stdout.name, livereload_stderr.name
janito/cli/main.py CHANGED
@@ -3,133 +3,200 @@
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
11
12
  from janito.i18n import tr
12
13
 
13
14
 
14
- def main():
15
- """Unified entry point for the Janito CLI and web server."""
16
- import sys
17
-
18
- from janito.agent.config import local_config, global_config
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):
19
57
  import janito.i18n as i18n
20
58
  from janito.agent.runtime_config import runtime_config
21
59
 
22
- local_config.load()
23
- global_config.load()
24
-
25
- parser = create_parser()
26
- args = parser.parse_args()
27
-
28
- # Seleção de idioma: prioridade --lang > config.json > padrão
29
60
  lang = getattr(args, "lang", None) or unified_config.get("lang", None) or "en"
30
61
  runtime_config.set("lang", lang)
31
62
  i18n.set_locale(lang)
32
63
 
64
+
65
+ def handle_help_config(args):
33
66
  from janito.agent.config import CONFIG_OPTIONS
34
67
  from janito.agent.config_defaults import CONFIG_DEFAULTS
35
68
 
36
- if getattr(args, "help_config", False):
37
- print(tr("Available configuration options:\n"))
38
- for key, desc in CONFIG_OPTIONS.items():
39
- default = CONFIG_DEFAULTS.get(key, None)
40
- print(
41
- tr(
42
- "{key:15} {desc} (default: {default})",
43
- key=key,
44
- desc=desc,
45
- default=default,
46
- )
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,
47
78
  )
48
- sys.exit(0)
79
+ )
49
80
 
50
- if getattr(args, "list_tools", False):
51
- from janito.agent.tool_registry import get_tool_schemas
52
- from rich.console import Console
53
- from rich.table import Table
54
81
 
55
- console = Console()
56
- table = Table(
57
- title="Ferramentas Registradas", show_lines=True, style="bold magenta"
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
+ ]
58
101
  )
59
- table.add_column("Gnome", style="cyan", no_wrap=True)
60
- table.add_column("Descrição", style="green")
61
- table.add_column("Parâmetros", style="yellow")
62
- for schema in get_tool_schemas():
63
- fn = schema["function"]
64
- params = "\n".join(
65
- [
66
- f"[bold]{k}[/]: {v['type']}"
67
- for k, v in fn["parameters"].get("properties", {}).items()
68
- ]
69
- )
70
- table.add_row(f"[b]{fn['name']}[/b]", fn["description"], params or "-")
71
- console.print(table)
72
- sys.exit(0)
102
+ table.add_row(f"[b]{fn['name']}[/b]", fn["description"], params or "-")
103
+ console.print(table)
73
104
 
74
- 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
83
- from janito.agent.runtime_config import runtime_config
84
-
85
- system_prompt_val = None
86
- origem = None
87
- if getattr(args, "system_file", None):
88
- try:
89
- with open(args.system_file, "r", encoding="utf-8") as f:
90
- system_prompt_val = f.read().strip()
91
- runtime_config.set("system_prompt_template", system_prompt_val)
92
- origem = "--system-file"
93
- except Exception as e:
94
- print(f"System prompt: (error reading system-file: {e})")
95
- elif getattr(args, "system", None):
96
- system_prompt_val = args.system
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()
97
120
  runtime_config.set("system_prompt_template", system_prompt_val)
98
- origem = "--system"
99
- else:
100
- 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:
106
- try:
107
- from janito.agent.profile_manager import AgentProfileManager
108
- from janito.agent.config import get_api_key
109
-
110
- role = args.role or unified_config.get("role", "software engineer")
111
- interaction_mode = (
112
- "chat" if not getattr(args, "prompt", None) else "prompt"
113
- )
114
- profile = "base"
115
- profile_manager = AgentProfileManager(
116
- api_key=get_api_key(),
117
- model=unified_config.get("model"),
118
- )
119
- system_prompt_val = profile_manager.get_system_prompt(
120
- role, interaction_mode, profile
121
- )
122
- print(f"System prompt (profile_manager): {system_prompt_val}")
123
- except Exception as e:
124
- print(f"System prompt: (error obtaining from profile_manager: {e})")
125
- sys.exit(0)
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
+
159
+ def main():
160
+ """Unified entry point for the Janito CLI and web server."""
161
+ import sys
162
+ from janito.agent.config import local_config, global_config
126
163
 
127
- # ... resto do main ...
164
+ local_config.load()
165
+ global_config.load()
166
+ parser = create_parser()
167
+ args = parser.parse_args()
168
+ # Handle --list [n] before anything else
169
+ if getattr(args, "list", None) is not None:
170
+ if handle_list_sessions(args):
171
+ sys.exit(0)
172
+ # Handle --view <id> to print conversation history
173
+ if getattr(args, "view", None) is not None:
174
+ sys.exit(handle_view_session(args))
175
+ handle_lang_selection(args)
176
+ if getattr(args, "help_config", False):
177
+ handle_help_config(args)
178
+ sys.exit(0)
179
+ if getattr(args, "list_tools", False):
180
+ handle_list_tools(args)
181
+ sys.exit(0)
182
+ if getattr(args, "info", False):
183
+ handle_info(args)
128
184
  handle_config_commands(args)
129
185
  setup_verbose_logging(args)
130
186
  if getattr(args, "web", False):
131
- import subprocess # Only needed if launching web
187
+ import subprocess
132
188
 
133
189
  subprocess.run([sys.executable, "-m", "janito.web"])
190
+ elif getattr(args, "live", False):
191
+ port = 35729
192
+ livereload_proc, started, livereload_stdout_path, livereload_stderr_path = (
193
+ start_livereload(port)
194
+ )
195
+ try:
196
+ run_cli(args)
197
+ finally:
198
+ if livereload_proc:
199
+ livereload_proc.terminate()
200
+ livereload_proc.wait()
134
201
  else:
135
202
  run_cli(args)