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.
- janito/__init__.py +1 -1
- janito/agent/api_exceptions.py +4 -0
- janito/agent/config.py +1 -1
- janito/agent/config_defaults.py +2 -3
- janito/agent/config_utils.py +0 -9
- janito/agent/conversation.py +177 -114
- janito/agent/conversation_api.py +179 -159
- janito/agent/conversation_tool_calls.py +11 -8
- janito/agent/llm_conversation_history.py +70 -0
- janito/agent/openai_client.py +44 -21
- janito/agent/openai_schema_generator.py +164 -128
- janito/agent/platform_discovery.py +134 -77
- janito/agent/profile_manager.py +5 -5
- janito/agent/rich_message_handler.py +80 -31
- janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +9 -8
- janito/agent/test_openai_schema_generator.py +93 -0
- janito/agent/tool_base.py +7 -2
- janito/agent/tool_executor.py +63 -50
- janito/agent/tool_registry.py +5 -2
- janito/agent/tool_use_tracker.py +42 -5
- janito/agent/tools/__init__.py +13 -12
- janito/agent/tools/create_directory.py +9 -6
- janito/agent/tools/create_file.py +35 -54
- janito/agent/tools/delete_text_in_file.py +97 -0
- janito/agent/tools/fetch_url.py +50 -5
- janito/agent/tools/find_files.py +40 -26
- janito/agent/tools/get_file_outline/__init__.py +1 -0
- janito/agent/tools/{outline_file/__init__.py → get_file_outline/core.py} +14 -18
- janito/agent/tools/get_file_outline/python_outline.py +134 -0
- janito/agent/tools/{search_outline.py → get_file_outline/search_outline.py} +11 -0
- janito/agent/tools/get_lines.py +21 -12
- janito/agent/tools/move_file.py +13 -12
- janito/agent/tools/present_choices.py +3 -1
- janito/agent/tools/python_command_runner.py +150 -0
- janito/agent/tools/python_file_runner.py +148 -0
- janito/agent/tools/python_stdin_runner.py +154 -0
- janito/agent/tools/remove_directory.py +4 -2
- janito/agent/tools/remove_file.py +15 -13
- janito/agent/tools/replace_file.py +72 -0
- janito/agent/tools/replace_text_in_file.py +7 -5
- janito/agent/tools/run_bash_command.py +29 -72
- janito/agent/tools/run_powershell_command.py +142 -102
- janito/agent/tools/search_text.py +177 -131
- janito/agent/tools/validate_file_syntax/__init__.py +1 -0
- janito/agent/tools/validate_file_syntax/core.py +94 -0
- janito/agent/tools/validate_file_syntax/css_validator.py +35 -0
- janito/agent/tools/validate_file_syntax/html_validator.py +77 -0
- janito/agent/tools/validate_file_syntax/js_validator.py +27 -0
- janito/agent/tools/validate_file_syntax/json_validator.py +6 -0
- janito/agent/tools/validate_file_syntax/markdown_validator.py +66 -0
- janito/agent/tools/validate_file_syntax/ps1_validator.py +32 -0
- janito/agent/tools/validate_file_syntax/python_validator.py +5 -0
- janito/agent/tools/validate_file_syntax/xml_validator.py +11 -0
- janito/agent/tools/validate_file_syntax/yaml_validator.py +6 -0
- janito/agent/tools_utils/__init__.py +1 -0
- janito/agent/tools_utils/action_type.py +7 -0
- janito/agent/tools_utils/dir_walk_utils.py +24 -0
- janito/agent/tools_utils/formatting.py +49 -0
- janito/agent/tools_utils/gitignore_utils.py +69 -0
- janito/agent/tools_utils/test_gitignore_utils.py +46 -0
- janito/agent/tools_utils/utils.py +30 -0
- janito/cli/_livereload_log_utils.py +13 -0
- janito/cli/_print_config.py +63 -61
- janito/cli/arg_parser.py +57 -14
- janito/cli/cli_main.py +270 -0
- janito/cli/livereload_starter.py +60 -0
- janito/cli/main.py +166 -99
- janito/cli/one_shot.py +80 -0
- janito/cli/termweb_starter.py +2 -2
- janito/i18n/__init__.py +1 -1
- janito/livereload/app.py +25 -0
- janito/rich_utils.py +41 -25
- janito/{cli_chat_shell → shell}/commands/__init__.py +19 -14
- janito/{cli_chat_shell → shell}/commands/config.py +4 -4
- janito/shell/commands/conversation_restart.py +74 -0
- janito/shell/commands/edit.py +24 -0
- janito/shell/commands/history_view.py +18 -0
- janito/{cli_chat_shell → shell}/commands/lang.py +3 -0
- janito/shell/commands/livelogs.py +42 -0
- janito/{cli_chat_shell → shell}/commands/prompt.py +16 -6
- janito/shell/commands/session.py +35 -0
- janito/{cli_chat_shell → shell}/commands/session_control.py +3 -5
- janito/{cli_chat_shell → shell}/commands/termweb_log.py +18 -10
- janito/shell/commands/tools.py +26 -0
- janito/shell/commands/track.py +36 -0
- janito/shell/commands/utility.py +28 -0
- janito/{cli_chat_shell → shell}/commands/verbose.py +4 -5
- janito/shell/commands.py +40 -0
- janito/shell/input_history.py +62 -0
- janito/shell/main.py +257 -0
- janito/{cli_chat_shell/shell_command_completer.py → shell/prompt/completer.py} +1 -1
- janito/{cli_chat_shell/chat_ui.py → shell/prompt/session_setup.py} +19 -5
- janito/shell/session/manager.py +101 -0
- janito/{cli_chat_shell/ui.py → shell/ui/interactive.py} +23 -17
- janito/termweb/app.py +3 -3
- janito/termweb/static/editor.css +142 -0
- janito/termweb/static/editor.css.bak +27 -0
- janito/termweb/static/editor.html +15 -213
- janito/termweb/static/editor.html.bak +16 -215
- janito/termweb/static/editor.js +209 -0
- janito/termweb/static/editor.js.bak +227 -0
- janito/termweb/static/index.html +2 -3
- janito/termweb/static/index.html.bak +2 -3
- janito/termweb/static/termweb.css.bak +33 -84
- janito/termweb/static/termweb.js +15 -34
- janito/termweb/static/termweb.js.bak +18 -36
- janito/tests/test_rich_utils.py +44 -0
- janito/web/app.py +0 -75
- {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/METADATA +62 -42
- janito-1.10.0.dist-info/RECORD +158 -0
- {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/WHEEL +1 -1
- janito/agent/tools/dir_walk_utils.py +0 -16
- janito/agent/tools/gitignore_utils.py +0 -46
- janito/agent/tools/memory.py +0 -48
- janito/agent/tools/outline_file/formatting.py +0 -20
- janito/agent/tools/outline_file/python_outline.py +0 -71
- janito/agent/tools/present_choices_test.py +0 -18
- janito/agent/tools/rich_live.py +0 -44
- janito/agent/tools/run_python_command.py +0 -163
- janito/agent/tools/tools_utils.py +0 -56
- janito/agent/tools/utils.py +0 -33
- janito/agent/tools/validate_file_syntax.py +0 -163
- janito/cli/runner/cli_main.py +0 -180
- janito/cli_chat_shell/chat_loop.py +0 -163
- janito/cli_chat_shell/chat_state.py +0 -38
- janito/cli_chat_shell/commands/history_start.py +0 -37
- janito/cli_chat_shell/commands/session.py +0 -48
- janito/cli_chat_shell/commands/sum.py +0 -49
- janito/cli_chat_shell/commands/utility.py +0 -32
- janito/cli_chat_shell/session_manager.py +0 -72
- janito-1.8.1.dist-info/RECORD +0 -127
- /janito/agent/tools/{outline_file → get_file_outline}/markdown_outline.py +0 -0
- /janito/cli/{runner/_termweb_log_utils.py → _termweb_log_utils.py} +0 -0
- /janito/cli/{runner/config.py → config_runner.py} +0 -0
- /janito/cli/{runner/formatting.py → formatting_runner.py} +0 -0
- /janito/{cli/runner → shell}/__init__.py +0 -0
- /janito/{cli_chat_shell → shell/prompt}/load_prompt.py +0 -0
- /janito/{cli_chat_shell/config_shell.py → shell/session/config.py} +0 -0
- /janito/{cli_chat_shell/__init__.py → shell/session/history.py} +0 -0
- {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/entry_points.txt +0 -0
- {janito-1.8.1.dist-info → janito-1.10.0.dist-info}/licenses/LICENSE +0 -0
- {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.
|
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
|
15
|
-
|
16
|
-
import
|
17
|
-
|
18
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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.
|
60
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
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
|
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)
|