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.
- janito/__init__.py +1 -1
- janito/agent/api_exceptions.py +4 -0
- janito/agent/config.py +1 -1
- janito/agent/config_defaults.py +2 -26
- janito/agent/conversation.py +163 -122
- janito/agent/conversation_api.py +149 -159
- janito/agent/{conversation_history.py → llm_conversation_history.py} +18 -1
- janito/agent/openai_client.py +38 -23
- janito/agent/openai_schema_generator.py +162 -129
- 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 +5 -4
- janito/agent/test_openai_schema_generator.py +93 -0
- janito/agent/tool_base.py +7 -2
- janito/agent/tool_executor.py +54 -49
- janito/agent/tool_registry.py +5 -2
- janito/agent/tool_use_tracker.py +26 -5
- janito/agent/tools/__init__.py +6 -3
- janito/agent/tools/create_directory.py +3 -1
- janito/agent/tools/create_file.py +7 -1
- janito/agent/tools/fetch_url.py +40 -3
- janito/agent/tools/find_files.py +3 -1
- janito/agent/tools/get_file_outline/core.py +6 -7
- janito/agent/tools/get_file_outline/search_outline.py +3 -1
- janito/agent/tools/get_lines.py +7 -2
- janito/agent/tools/move_file.py +3 -1
- 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 +3 -1
- janito/agent/tools/remove_file.py +5 -1
- janito/agent/tools/replace_file.py +12 -2
- janito/agent/tools/replace_text_in_file.py +4 -2
- janito/agent/tools/run_bash_command.py +30 -69
- janito/agent/tools/run_powershell_command.py +134 -105
- janito/agent/tools/search_text.py +172 -122
- janito/agent/tools/validate_file_syntax/core.py +3 -1
- janito/agent/tools_utils/action_type.py +7 -0
- janito/agent/tools_utils/dir_walk_utils.py +3 -2
- janito/agent/tools_utils/formatting.py +47 -21
- janito/agent/tools_utils/gitignore_utils.py +66 -40
- janito/agent/tools_utils/test_gitignore_utils.py +46 -0
- janito/cli/_print_config.py +63 -61
- janito/cli/arg_parser.py +13 -12
- janito/cli/cli_main.py +137 -147
- janito/cli/main.py +152 -174
- janito/cli/one_shot.py +40 -26
- janito/i18n/__init__.py +1 -1
- janito/rich_utils.py +46 -8
- janito/shell/commands/__init__.py +2 -4
- janito/shell/commands/conversation_restart.py +3 -1
- janito/shell/commands/edit.py +3 -0
- janito/shell/commands/history_view.py +3 -3
- janito/shell/commands/lang.py +3 -0
- janito/shell/commands/livelogs.py +5 -3
- janito/shell/commands/prompt.py +6 -0
- janito/shell/commands/session.py +3 -0
- janito/shell/commands/session_control.py +3 -0
- janito/shell/commands/termweb_log.py +8 -0
- janito/shell/commands/tools.py +3 -0
- janito/shell/commands/track.py +36 -0
- janito/shell/commands/utility.py +13 -18
- janito/shell/commands/verbose.py +3 -4
- janito/shell/input_history.py +62 -0
- janito/shell/main.py +117 -181
- janito/shell/session/manager.py +0 -21
- janito/shell/ui/interactive.py +0 -2
- janito/termweb/static/editor.css +0 -4
- janito/tests/test_rich_utils.py +44 -0
- janito/web/app.py +0 -75
- {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/METADATA +61 -42
- {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/RECORD +78 -71
- {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/WHEEL +1 -1
- janito/agent/providers.py +0 -77
- janito/agent/tools/run_python_command.py +0 -161
- janito/shell/commands/sum.py +0 -49
- {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/entry_points.txt +0 -0
- {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/licenses/LICENSE +0 -0
- {janito-1.9.0.dist-info → janito-1.10.0.dist-info}/top_level.txt +0 -0
janito/cli/_print_config.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import os
|
2
|
-
from janito.rich_utils import
|
2
|
+
from janito.rich_utils import RichPrinter
|
3
|
+
|
4
|
+
_rich_printer = RichPrinter()
|
3
5
|
from ._utils import home_shorten
|
4
6
|
|
5
7
|
|
@@ -7,17 +9,65 @@ def print_config_items(items, color_label=None):
|
|
7
9
|
if not items:
|
8
10
|
return
|
9
11
|
if color_label:
|
10
|
-
print_info(color_label)
|
12
|
+
_rich_printer.print_info(color_label)
|
11
13
|
home = os.path.expanduser("~")
|
12
14
|
for key, value in items.items():
|
13
15
|
if key == "system_prompt_template" and isinstance(value, str):
|
14
16
|
if value.startswith(home):
|
15
17
|
print(f"{key} = {home_shorten(value)}")
|
16
18
|
else:
|
17
|
-
print_info(f"{key} = {value}")
|
19
|
+
_rich_printer.print_info(f"{key} = {value}")
|
20
|
+
else:
|
21
|
+
_rich_printer.print_info(f"{key} = {value}")
|
22
|
+
_rich_printer.print_info("")
|
23
|
+
|
24
|
+
|
25
|
+
def _mask_api_key(value):
|
26
|
+
if value and len(value) > 8:
|
27
|
+
return value[:4] + "..." + value[-4:]
|
28
|
+
elif value:
|
29
|
+
return "***"
|
30
|
+
return None
|
31
|
+
|
32
|
+
|
33
|
+
def _collect_config_items(config, unified_config, keys):
|
34
|
+
items = {}
|
35
|
+
for key in sorted(keys):
|
36
|
+
if key == "api_key":
|
37
|
+
value = config.get("api_key")
|
38
|
+
value = _mask_api_key(value)
|
18
39
|
else:
|
19
|
-
|
20
|
-
|
40
|
+
value = unified_config.get(key)
|
41
|
+
items[key] = value
|
42
|
+
return items
|
43
|
+
|
44
|
+
|
45
|
+
def _print_defaults(config_defaults, shown_keys):
|
46
|
+
default_items = {
|
47
|
+
k: v
|
48
|
+
for k, v in config_defaults.items()
|
49
|
+
if k not in shown_keys and k != "api_key"
|
50
|
+
}
|
51
|
+
if default_items:
|
52
|
+
_rich_printer.print_magenta(
|
53
|
+
"[green]\U0001f7e2 Defaults (not set in config files)[/green]"
|
54
|
+
)
|
55
|
+
from pathlib import Path
|
56
|
+
|
57
|
+
template_path = (
|
58
|
+
Path(__file__).parent
|
59
|
+
/ "agent"
|
60
|
+
/ "templates"
|
61
|
+
/ "system_prompt_template_default.j2"
|
62
|
+
)
|
63
|
+
for key, value in default_items.items():
|
64
|
+
if key == "system_prompt_template" and value is None:
|
65
|
+
_rich_printer.print_info(
|
66
|
+
f"{key} = (default template path: {home_shorten(str(template_path))})"
|
67
|
+
)
|
68
|
+
else:
|
69
|
+
_rich_printer.print_info(f"{key} = {value}")
|
70
|
+
_rich_printer.print_info("")
|
21
71
|
|
22
72
|
|
23
73
|
def print_full_config(
|
@@ -27,68 +77,20 @@ def print_full_config(
|
|
27
77
|
Print local, global, and default config values in a unified way.
|
28
78
|
Handles masking API keys and showing the template file for system_prompt_template if not set.
|
29
79
|
"""
|
30
|
-
local_items = {}
|
31
|
-
global_items = {}
|
32
80
|
local_keys = set(local_config.all().keys())
|
33
81
|
global_keys = set(global_config.all().keys())
|
34
82
|
if not (local_keys or global_keys):
|
35
|
-
print_warning("No configuration found.")
|
83
|
+
_rich_printer.print_warning("No configuration found.")
|
36
84
|
else:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
value[:4] + "..." + value[-4:]
|
42
|
-
if value and len(value) > 8
|
43
|
-
else ("***" if value else None)
|
44
|
-
)
|
45
|
-
else:
|
46
|
-
value = unified_config.get(key)
|
47
|
-
local_items[key] = value
|
48
|
-
for key in sorted(global_keys - local_keys):
|
49
|
-
if key == "api_key":
|
50
|
-
value = global_config.get("api_key")
|
51
|
-
value = (
|
52
|
-
value[:4] + "..." + value[-4:]
|
53
|
-
if value and len(value) > 8
|
54
|
-
else ("***" if value else None)
|
55
|
-
)
|
56
|
-
else:
|
57
|
-
value = unified_config.get(key)
|
58
|
-
global_items[key] = value
|
59
|
-
# Mask API key
|
60
|
-
for cfg in (local_items, global_items):
|
61
|
-
if "api_key" in cfg and cfg["api_key"]:
|
62
|
-
val = cfg["api_key"]
|
63
|
-
cfg["api_key"] = val[:4] + "..." + val[-4:] if len(val) > 8 else "***"
|
85
|
+
local_items = _collect_config_items(local_config, unified_config, local_keys)
|
86
|
+
global_items = _collect_config_items(
|
87
|
+
global_config, unified_config, global_keys - local_keys
|
88
|
+
)
|
64
89
|
print_config_items(
|
65
|
-
local_items, color_label="[cyan]
|
90
|
+
local_items, color_label="[cyan]\U0001f3e0 Local Configuration[/cyan]"
|
66
91
|
)
|
67
92
|
print_config_items(
|
68
|
-
global_items, color_label="[yellow]
|
93
|
+
global_items, color_label="[yellow]\U0001f310 Global Configuration[/yellow]"
|
69
94
|
)
|
70
|
-
# Show defaults for unset keys
|
71
95
|
shown_keys = set(local_items.keys()) | set(global_items.keys())
|
72
|
-
|
73
|
-
k: v
|
74
|
-
for k, v in config_defaults.items()
|
75
|
-
if k not in shown_keys and k != "api_key"
|
76
|
-
}
|
77
|
-
if default_items:
|
78
|
-
print_magenta("[green]🟢 Defaults (not set in config files)[/green]")
|
79
|
-
from pathlib import Path
|
80
|
-
|
81
|
-
template_path = (
|
82
|
-
Path(__file__).parent
|
83
|
-
/ "agent"
|
84
|
-
/ "templates"
|
85
|
-
/ "system_prompt_template_default.j2"
|
86
|
-
)
|
87
|
-
for key, value in default_items.items():
|
88
|
-
if key == "system_prompt_template" and value is None:
|
89
|
-
print_info(
|
90
|
-
f"{key} = (default template path: {home_shorten(str(template_path))})"
|
91
|
-
)
|
92
|
-
else:
|
93
|
-
print_info(f"{key} = {value}")
|
94
|
-
print_info("")
|
96
|
+
_print_defaults(config_defaults, shown_keys)
|
janito/cli/arg_parser.py
CHANGED
@@ -34,7 +34,7 @@ def create_parser():
|
|
34
34
|
"--set-provider-config",
|
35
35
|
nargs=3,
|
36
36
|
metavar=("NAME", "KEY", "VALUE"),
|
37
|
-
help="Set a provider config parameter (e.g., --set-provider-config
|
37
|
+
help="Set a provider config parameter (e.g., --set-provider-config openai api_key sk-xxx).",
|
38
38
|
)
|
39
39
|
parser.add_argument(
|
40
40
|
"--lang",
|
@@ -52,7 +52,7 @@ def create_parser():
|
|
52
52
|
"--max-tokens",
|
53
53
|
type=int,
|
54
54
|
default=None,
|
55
|
-
help="Maximum tokens for model response (overrides config, default:
|
55
|
+
help="Maximum tokens for model response (overrides config, default: 32000)",
|
56
56
|
)
|
57
57
|
parser.add_argument(
|
58
58
|
"--max-tools",
|
@@ -212,6 +212,11 @@ def create_parser():
|
|
212
212
|
action="store_true",
|
213
213
|
help="Print all agent events before dispatching to the message handler (for debugging)",
|
214
214
|
)
|
215
|
+
parser.add_argument(
|
216
|
+
"--verbose-messages",
|
217
|
+
action="store_true",
|
218
|
+
help="Print every new message added to the conversation history with a colored background.",
|
219
|
+
)
|
215
220
|
parser.add_argument(
|
216
221
|
"-V",
|
217
222
|
"--vanilla",
|
@@ -231,16 +236,6 @@ def create_parser():
|
|
231
236
|
default=None,
|
232
237
|
help="Agent Profile name (only 'base' is supported)",
|
233
238
|
)
|
234
|
-
parser.add_argument(
|
235
|
-
"--stream",
|
236
|
-
action="store_true",
|
237
|
-
help="Enable OpenAI streaming mode (yields tokens as they arrive)",
|
238
|
-
)
|
239
|
-
parser.add_argument(
|
240
|
-
"--verbose-stream",
|
241
|
-
action="store_true",
|
242
|
-
help="Print raw chunks as they are fetched from OpenAI (for debugging)",
|
243
|
-
)
|
244
239
|
parser.add_argument(
|
245
240
|
"--no-termweb",
|
246
241
|
action="store_true",
|
@@ -263,4 +258,10 @@ def create_parser():
|
|
263
258
|
action="store_true",
|
264
259
|
help="Disable tool call reason tracking (no tools tracking)",
|
265
260
|
)
|
261
|
+
parser.add_argument(
|
262
|
+
"--tool-user",
|
263
|
+
action="store_true",
|
264
|
+
default=False,
|
265
|
+
help="When set, tool responses will use role 'user' instead of 'tool' in the conversation history.",
|
266
|
+
)
|
266
267
|
return parser
|
janito/cli/cli_main.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import sys
|
2
|
+
from janito.agent.llm_conversation_history import LLMConversationHistory
|
2
3
|
import socket
|
3
4
|
from janito.agent.profile_manager import AgentProfileManager
|
4
5
|
from janito.agent.runtime_config import unified_config, runtime_config
|
@@ -17,19 +18,11 @@ def is_port_free(port):
|
|
17
18
|
return s.connect_ex(("localhost", port)) != 0
|
18
19
|
|
19
20
|
|
20
|
-
def
|
21
|
-
if args.version:
|
22
|
-
print(f"janito version {__version__}")
|
23
|
-
sys.exit(0)
|
24
|
-
|
25
|
-
# Set vanilla mode if -V/--vanilla is passed
|
21
|
+
def normalize_args(args):
|
26
22
|
if getattr(args, "vanilla", False):
|
27
23
|
runtime_config.set("vanilla_mode", True)
|
28
|
-
|
29
|
-
# Set no_tools_tracking if --ntt is passed
|
30
24
|
if getattr(args, "ntt", False):
|
31
25
|
runtime_config.set("no_tools_tracking", True)
|
32
|
-
# Normalize all verbose flags into runtime_config
|
33
26
|
for flag in [
|
34
27
|
"verbose_http",
|
35
28
|
"verbose_http_raw",
|
@@ -37,58 +30,49 @@ def run_cli(args):
|
|
37
30
|
"verbose_reason",
|
38
31
|
"verbose_tools",
|
39
32
|
"verbose_events",
|
40
|
-
"
|
33
|
+
"verbose_messages",
|
41
34
|
]:
|
42
35
|
if hasattr(args, flag):
|
43
36
|
runtime_config.set(flag, getattr(args, flag, False))
|
44
|
-
|
45
|
-
|
46
|
-
if args.role:
|
47
|
-
runtime_config.set("role", args.role)
|
37
|
+
if getattr(args, "trust_tools", False):
|
38
|
+
runtime_config.set("trust_tools", True)
|
48
39
|
if getattr(args, "model", None):
|
49
40
|
runtime_config.set("model", args.model)
|
50
41
|
if getattr(args, "max_tools", None) is not None:
|
51
42
|
runtime_config.set("max_tools", args.max_tools)
|
52
|
-
if getattr(args, "
|
53
|
-
runtime_config.set("
|
54
|
-
if
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
lang = getattr(args, "lang", None) or runtime_config.get("lang", "en")
|
61
|
-
profile_manager = AgentProfileManager(
|
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(
|
62
51
|
api_key=get_api_key(),
|
63
52
|
model=unified_config.get("model"),
|
64
53
|
role=role,
|
65
54
|
profile_name=profile,
|
66
55
|
interaction_mode=interaction_mode,
|
67
56
|
verbose_tools=args.verbose_tools,
|
68
|
-
base_url=unified_config.get("base_url", "
|
57
|
+
base_url=unified_config.get("base_url", ""),
|
69
58
|
azure_openai_api_version=unified_config.get(
|
70
59
|
"azure_openai_api_version", "2023-05-15"
|
71
60
|
),
|
72
61
|
use_azure_openai=unified_config.get("use_azure_openai", False),
|
73
62
|
lang=lang,
|
74
63
|
)
|
75
|
-
profile_manager.refresh_prompt()
|
76
|
-
if getattr(args, "show_system", False):
|
77
|
-
print(profile_manager.render_prompt())
|
78
|
-
sys.exit(0)
|
79
|
-
if args.max_tokens is not None:
|
80
|
-
runtime_config.set("max_tokens", args.max_tokens)
|
81
|
-
if getattr(args, "verbose_reason", False):
|
82
|
-
runtime_config.set("verbose_reason", True)
|
83
64
|
|
84
|
-
|
65
|
+
|
66
|
+
def handle_termweb(args, interaction_mode):
|
85
67
|
termweb_proc = None
|
86
68
|
selected_port = None
|
69
|
+
termweb_stdout_path = None
|
70
|
+
termweb_stderr_path = None
|
87
71
|
if (
|
88
72
|
not getattr(args, "no_termweb", False)
|
89
73
|
and interaction_mode == "chat"
|
90
74
|
and not runtime_config.get("vanilla_mode", False)
|
91
|
-
and not getattr(args, "input_arg", None)
|
75
|
+
and not getattr(args, "input_arg", None)
|
92
76
|
):
|
93
77
|
default_port = 8088
|
94
78
|
max_port = 8100
|
@@ -122,54 +106,131 @@ def run_cli(args):
|
|
122
106
|
termweb_proc, started, termweb_stdout_path, termweb_stderr_path = start_termweb(
|
123
107
|
selected_port
|
124
108
|
)
|
125
|
-
# Store last running port in .janito/config.json if started
|
126
109
|
if started:
|
127
110
|
from janito.agent.config import local_config
|
128
111
|
|
129
112
|
local_config.set("termweb_last_running_port", selected_port)
|
130
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
|
+
|
131
207
|
|
132
|
-
|
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
|
+
)
|
133
227
|
try:
|
134
|
-
|
135
|
-
livereload_stderr_path = None
|
136
|
-
continue_session = False
|
137
|
-
session_id = None
|
228
|
+
continue_session, session_id = handle_continue_session(args)
|
138
229
|
if getattr(args, "input_arg", None):
|
139
230
|
from janito.cli.one_shot import run_oneshot_mode
|
140
231
|
|
141
232
|
run_oneshot_mode(args, profile_manager, runtime_config)
|
142
233
|
return
|
143
|
-
if not getattr(args, "input_arg", None) or getattr(
|
144
|
-
args, "continue_session", False
|
145
|
-
):
|
146
|
-
# Determine continue_session and session_id
|
147
|
-
_cont = getattr(args, "continue_session", False)
|
148
|
-
if _cont:
|
149
|
-
continue_session = True
|
150
|
-
session_id = getattr(args, "input_arg", None)
|
151
|
-
if session_id is None:
|
152
|
-
# Find the most recent session id from .janito/chat_history/*.json
|
153
|
-
import os
|
154
|
-
import glob
|
155
|
-
|
156
|
-
chat_hist_dir = (
|
157
|
-
os.path.join(os.path.expanduser("~"), ".janito", "chat_history")
|
158
|
-
if not os.path.isabs(".janito")
|
159
|
-
else os.path.join(".janito", "chat_history")
|
160
|
-
)
|
161
|
-
if not os.path.exists(chat_hist_dir):
|
162
|
-
session_id = None
|
163
|
-
else:
|
164
|
-
files = glob.glob(os.path.join(chat_hist_dir, "*.json"))
|
165
|
-
if files:
|
166
|
-
latest = max(files, key=os.path.getmtime)
|
167
|
-
session_id = os.path.splitext(os.path.basename(latest))[0]
|
168
|
-
else:
|
169
|
-
session_id = None
|
170
|
-
else:
|
171
|
-
continue_session = False
|
172
|
-
session_id = None
|
173
234
|
import time
|
174
235
|
|
175
236
|
info_start_time = None
|
@@ -179,18 +240,10 @@ def run_cli(args):
|
|
179
240
|
profile_manager,
|
180
241
|
continue_session=continue_session,
|
181
242
|
session_id=session_id,
|
182
|
-
termweb_stdout_path=
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
termweb_stderr_path if "termweb_stderr_path" in locals() else None
|
187
|
-
),
|
188
|
-
livereload_stdout_path=(
|
189
|
-
livereload_stdout_path if "livereload_stdout_path" in locals() else None
|
190
|
-
),
|
191
|
-
livereload_stderr_path=(
|
192
|
-
livereload_stderr_path if "livereload_stderr_path" in locals() else None
|
193
|
-
),
|
243
|
+
termweb_stdout_path=termweb_stdout_path,
|
244
|
+
termweb_stderr_path=termweb_stderr_path,
|
245
|
+
livereload_stdout_path=None,
|
246
|
+
livereload_stderr_path=None,
|
194
247
|
)
|
195
248
|
if (
|
196
249
|
getattr(args, "info", False)
|
@@ -200,75 +253,12 @@ def run_cli(args):
|
|
200
253
|
elapsed = time.time() - info_start_time
|
201
254
|
from rich.console import Console
|
202
255
|
|
203
|
-
console = Console()
|
204
256
|
total_tokens = usage_info.get("total_tokens")
|
257
|
+
console = Console()
|
205
258
|
console.print(
|
206
259
|
f"[bold green]Total tokens used:[/] [yellow]{total_tokens}[/yellow] [bold green]| Elapsed time:[/] [yellow]{elapsed:.2f}s[/yellow]"
|
207
260
|
)
|
208
261
|
sys.exit(0)
|
209
|
-
# --- Prompt mode ---
|
210
|
-
prompt = getattr(args, "input_arg", None)
|
211
|
-
from rich.console import Console
|
212
|
-
from janito.agent.rich_message_handler import RichMessageHandler
|
213
|
-
|
214
|
-
console = Console()
|
215
|
-
message_handler = RichMessageHandler()
|
216
|
-
messages = []
|
217
|
-
system_prompt_override = runtime_config.get("system_prompt_template")
|
218
|
-
if system_prompt_override:
|
219
|
-
# Só adiciona system prompt se NÃO for vanilla, ou se foi explicitamente passado via --system
|
220
|
-
if not runtime_config.get("vanilla_mode", False) or getattr(
|
221
|
-
args, "system", None
|
222
|
-
):
|
223
|
-
messages.append({"role": "system", "content": system_prompt_override})
|
224
|
-
elif profile_manager.system_prompt_template and not runtime_config.get(
|
225
|
-
"vanilla_mode", False
|
226
|
-
):
|
227
|
-
messages.append(
|
228
|
-
{"role": "system", "content": profile_manager.system_prompt_template}
|
229
|
-
)
|
230
|
-
messages.append({"role": "user", "content": prompt})
|
231
|
-
import time
|
232
|
-
|
233
|
-
info_start_time = None
|
234
|
-
if getattr(args, "info", False):
|
235
|
-
info_start_time = time.time()
|
236
|
-
try:
|
237
|
-
max_rounds = 100
|
238
|
-
from janito.agent.conversation_history import ConversationHistory
|
239
|
-
|
240
|
-
result = profile_manager.agent.chat(
|
241
|
-
ConversationHistory(messages),
|
242
|
-
message_handler=message_handler,
|
243
|
-
spinner=True,
|
244
|
-
max_rounds=max_rounds,
|
245
|
-
stream=getattr(args, "stream", False),
|
246
|
-
)
|
247
|
-
if (
|
248
|
-
getattr(args, "info", False)
|
249
|
-
and info_start_time is not None
|
250
|
-
and result is not None
|
251
|
-
):
|
252
|
-
usage_info = result.get("usage")
|
253
|
-
total_tokens = usage_info.get("total_tokens") if usage_info else None
|
254
|
-
prompt_tokens = usage_info.get("prompt_tokens") if usage_info else None
|
255
|
-
completion_tokens = (
|
256
|
-
usage_info.get("completion_tokens") if usage_info else None
|
257
|
-
)
|
258
|
-
elapsed = time.time() - info_start_time
|
259
|
-
from rich.console import Console
|
260
|
-
|
261
|
-
console = Console()
|
262
|
-
console.print(
|
263
|
-
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]",
|
264
|
-
style="dim",
|
265
|
-
)
|
266
|
-
except MaxRoundsExceededError:
|
267
|
-
console.print("[red]Max conversation rounds exceeded.[/red]")
|
268
|
-
except ProviderError as e:
|
269
|
-
console.print(f"[red]Provider error:[/red] {e}")
|
270
|
-
except EmptyResponseError as e:
|
271
|
-
console.print(f"[red]Error:[/red] {e}")
|
272
262
|
except KeyboardInterrupt:
|
273
263
|
from rich.console import Console
|
274
264
|
|