janito 1.6.0__py3-none-any.whl → 1.8.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/config.py +3 -3
- janito/agent/config_defaults.py +3 -2
- janito/agent/conversation.py +73 -27
- janito/agent/conversation_api.py +104 -4
- janito/agent/conversation_exceptions.py +6 -0
- janito/agent/conversation_tool_calls.py +17 -3
- janito/agent/event.py +24 -0
- janito/agent/event_dispatcher.py +24 -0
- janito/agent/event_handler_protocol.py +5 -0
- janito/agent/event_system.py +15 -0
- janito/agent/message_handler.py +4 -1
- janito/agent/message_handler_protocol.py +5 -0
- janito/agent/openai_client.py +5 -6
- janito/agent/openai_schema_generator.py +23 -4
- janito/agent/platform_discovery.py +90 -0
- janito/agent/profile_manager.py +34 -110
- janito/agent/queued_message_handler.py +22 -3
- janito/agent/rich_message_handler.py +3 -1
- janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +14 -0
- janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +13 -0
- janito/agent/test_handler_protocols.py +47 -0
- janito/agent/tests/__init__.py +1 -0
- janito/agent/tool_base.py +1 -1
- janito/agent/tool_executor.py +109 -0
- janito/agent/tool_registry.py +3 -75
- janito/agent/tool_use_tracker.py +46 -0
- janito/agent/tools/__init__.py +11 -8
- janito/agent/tools/ask_user.py +26 -12
- janito/agent/tools/create_directory.py +50 -18
- janito/agent/tools/create_file.py +60 -29
- janito/agent/tools/dir_walk_utils.py +16 -0
- janito/agent/tools/fetch_url.py +10 -11
- janito/agent/tools/find_files.py +49 -40
- janito/agent/tools/get_lines.py +60 -25
- janito/agent/tools/memory.py +48 -0
- janito/agent/tools/move_file.py +72 -23
- janito/agent/tools/outline_file/__init__.py +85 -0
- janito/agent/tools/outline_file/formatting.py +20 -0
- janito/agent/tools/outline_file/markdown_outline.py +14 -0
- janito/agent/tools/outline_file/python_outline.py +71 -0
- janito/agent/tools/present_choices.py +62 -0
- janito/agent/tools/present_choices_test.py +18 -0
- janito/agent/tools/remove_directory.py +31 -26
- janito/agent/tools/remove_file.py +31 -13
- janito/agent/tools/replace_text_in_file.py +135 -36
- janito/agent/tools/run_bash_command.py +113 -97
- janito/agent/tools/run_powershell_command.py +169 -0
- janito/agent/tools/run_python_command.py +53 -29
- janito/agent/tools/search_outline.py +17 -0
- janito/agent/tools/search_text.py +208 -0
- janito/agent/tools/tools_utils.py +47 -4
- janito/agent/tools/utils.py +14 -15
- janito/agent/tools/validate_file_syntax.py +163 -0
- janito/cli/_print_config.py +1 -1
- janito/cli/arg_parser.py +36 -4
- janito/cli/config_commands.py +1 -1
- janito/cli/logging_setup.py +7 -2
- janito/cli/main.py +97 -3
- janito/cli/runner/__init__.py +0 -2
- janito/cli/runner/_termweb_log_utils.py +17 -0
- janito/cli/runner/cli_main.py +121 -89
- janito/cli/runner/config.py +6 -4
- janito/cli/termweb_starter.py +73 -0
- janito/cli_chat_shell/chat_loop.py +52 -13
- janito/cli_chat_shell/chat_state.py +1 -1
- janito/cli_chat_shell/chat_ui.py +2 -3
- janito/cli_chat_shell/commands/__init__.py +17 -6
- janito/cli_chat_shell/commands/{history_reset.py → history_start.py} +13 -5
- janito/cli_chat_shell/commands/lang.py +16 -0
- janito/cli_chat_shell/commands/prompt.py +42 -0
- janito/cli_chat_shell/commands/session_control.py +36 -1
- janito/cli_chat_shell/commands/sum.py +49 -0
- janito/cli_chat_shell/commands/termweb_log.py +86 -0
- janito/cli_chat_shell/commands/utility.py +5 -2
- janito/cli_chat_shell/commands/verbose.py +29 -0
- janito/cli_chat_shell/load_prompt.py +47 -8
- janito/cli_chat_shell/session_manager.py +9 -1
- janito/cli_chat_shell/shell_command_completer.py +20 -0
- janito/cli_chat_shell/ui.py +110 -93
- janito/i18n/__init__.py +35 -0
- janito/i18n/messages.py +23 -0
- janito/i18n/pt.py +46 -0
- janito/rich_utils.py +43 -43
- janito/termweb/app.py +95 -0
- janito/termweb/static/editor.html +238 -0
- janito/termweb/static/editor.html.bak +238 -0
- janito/termweb/static/explorer.html.bak +59 -0
- janito/termweb/static/favicon.ico +0 -0
- janito/termweb/static/favicon.ico.bak +0 -0
- janito/termweb/static/index.html +55 -0
- janito/termweb/static/index.html.bak +55 -0
- janito/termweb/static/index.html.bak.bak +175 -0
- janito/termweb/static/landing.html.bak +36 -0
- janito/termweb/static/termicon.svg +1 -0
- janito/termweb/static/termweb.css +235 -0
- janito/termweb/static/termweb.css.bak +286 -0
- janito/termweb/static/termweb.js +187 -0
- janito/termweb/static/termweb.js.bak +187 -0
- janito/termweb/static/termweb.js.bak.bak +157 -0
- janito/termweb/static/termweb_quickopen.js +135 -0
- janito/termweb/static/termweb_quickopen.js.bak +125 -0
- janito/web/app.py +10 -13
- {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/METADATA +73 -32
- janito-1.8.0.dist-info/RECORD +127 -0
- {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/WHEEL +1 -1
- janito/agent/tool_registry_core.py +0 -2
- janito/agent/tools/get_file_outline.py +0 -117
- janito/agent/tools/py_compile_file.py +0 -40
- janito/agent/tools/replace_file.py +0 -51
- janito/agent/tools/search_files.py +0 -71
- janito/cli/runner/scan.py +0 -44
- janito/cli_chat_shell/commands/system.py +0 -73
- janito-1.6.0.dist-info/RECORD +0 -81
- {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/entry_points.txt +0 -0
- {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/licenses/LICENSE +0 -0
- {janito-1.6.0.dist-info → janito-1.8.0.dist-info}/top_level.txt +0 -0
@@ -4,34 +4,68 @@ from .chat_ui import setup_prompt_session, print_welcome_message
|
|
4
4
|
from .commands import handle_command
|
5
5
|
from janito.agent.conversation_exceptions import EmptyResponseError, ProviderError
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
# Track the active prompt session for cleanup
|
8
|
+
active_prompt_session = None
|
9
|
+
|
10
|
+
|
11
|
+
def start_chat_shell(
|
12
|
+
profile_manager,
|
13
|
+
continue_session=False,
|
14
|
+
max_rounds=50,
|
15
|
+
termweb_stdout_path=None,
|
16
|
+
termweb_stderr_path=None,
|
17
|
+
):
|
18
|
+
import janito.i18n as i18n
|
19
|
+
from janito.agent.runtime_config import runtime_config
|
20
|
+
|
21
|
+
i18n.set_locale(runtime_config.get("lang", "en"))
|
22
|
+
global active_prompt_session
|
9
23
|
agent = profile_manager.agent
|
10
24
|
message_handler = RichMessageHandler()
|
11
25
|
console = message_handler.console
|
12
26
|
|
13
27
|
# Load state
|
14
28
|
state = load_chat_state(continue_session)
|
29
|
+
if termweb_stdout_path:
|
30
|
+
state["termweb_stdout_path"] = termweb_stdout_path
|
31
|
+
if termweb_stderr_path:
|
32
|
+
state["termweb_stderr_path"] = termweb_stderr_path
|
15
33
|
messages = state["messages"]
|
16
34
|
mem_history = state["mem_history"]
|
17
|
-
|
35
|
+
last_usage_info_ref = {"value": state["last_usage_info"]}
|
18
36
|
last_elapsed = state["last_elapsed"]
|
19
37
|
|
20
|
-
# Add system prompt if needed
|
21
|
-
|
22
|
-
|
38
|
+
# Add system prompt if needed (skip in vanilla mode)
|
39
|
+
from janito.agent.runtime_config import runtime_config
|
40
|
+
|
41
|
+
if (
|
42
|
+
profile_manager.system_prompt_template
|
43
|
+
and (
|
44
|
+
not runtime_config.get("vanilla_mode", False)
|
45
|
+
or runtime_config.get("system_prompt_template")
|
46
|
+
)
|
47
|
+
and not any(m.get("role") == "system" for m in messages)
|
23
48
|
):
|
24
49
|
messages.insert(0, {"role": "system", "content": agent.system_prompt_template})
|
25
50
|
|
26
51
|
print_welcome_message(console, continued=continue_session)
|
27
52
|
|
28
53
|
session = setup_prompt_session(
|
29
|
-
messages,
|
54
|
+
messages, last_usage_info_ref, last_elapsed, mem_history, profile_manager, agent
|
30
55
|
)
|
56
|
+
active_prompt_session = session
|
57
|
+
|
58
|
+
inject_message = state.get("inject_message")
|
59
|
+
if "inject_message" in state:
|
60
|
+
del state["inject_message"]
|
31
61
|
|
32
62
|
while True:
|
33
63
|
try:
|
34
|
-
if
|
64
|
+
if inject_message is not None:
|
65
|
+
user_input = inject_message
|
66
|
+
inject_message = None
|
67
|
+
was_paste_mode = False
|
68
|
+
elif state.get("paste_mode"):
|
35
69
|
console.print("")
|
36
70
|
user_input = session.prompt("Multiline> ", multiline=True)
|
37
71
|
was_paste_mode = True
|
@@ -40,7 +74,7 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
|
|
40
74
|
from prompt_toolkit.formatted_text import HTML
|
41
75
|
|
42
76
|
user_input = session.prompt(
|
43
|
-
HTML("<
|
77
|
+
HTML("<inputline>💬 </inputline>"), multiline=False
|
44
78
|
)
|
45
79
|
was_paste_mode = False
|
46
80
|
except EOFError:
|
@@ -51,7 +85,10 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
|
|
51
85
|
try:
|
52
86
|
confirm = (
|
53
87
|
session.prompt(
|
54
|
-
|
88
|
+
# Use <inputline> for full-line blue background, <prompt> for icon only
|
89
|
+
HTML(
|
90
|
+
"<inputline>Do you really want to exit? (y/n): </inputline>"
|
91
|
+
)
|
55
92
|
)
|
56
93
|
.strip()
|
57
94
|
.lower()
|
@@ -95,8 +132,10 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
|
|
95
132
|
|
96
133
|
start_time = time.time()
|
97
134
|
|
135
|
+
# No need to propagate verbose; ToolExecutor and others fetch from runtime_config
|
136
|
+
|
98
137
|
try:
|
99
|
-
response = profile_manager.agent.
|
138
|
+
response = profile_manager.agent.chat(
|
100
139
|
messages,
|
101
140
|
max_rounds=max_rounds,
|
102
141
|
message_handler=message_handler,
|
@@ -118,7 +157,7 @@ def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
|
|
118
157
|
last_elapsed = time.time() - start_time
|
119
158
|
|
120
159
|
usage = response.get("usage")
|
121
|
-
|
160
|
+
last_usage_info_ref["value"] = usage
|
122
161
|
|
123
162
|
# Save conversation and input history
|
124
|
-
save_chat_state(messages, mem_history,
|
163
|
+
save_chat_state(messages, mem_history, last_usage_info_ref["value"])
|
@@ -9,7 +9,7 @@ from prompt_toolkit.history import InMemoryHistory
|
|
9
9
|
|
10
10
|
def load_chat_state(continue_session: bool):
|
11
11
|
messages = []
|
12
|
-
last_usage_info =
|
12
|
+
last_usage_info = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
|
13
13
|
last_elapsed = None
|
14
14
|
history_list = load_input_history()
|
15
15
|
mem_history = InMemoryHistory()
|
janito/cli_chat_shell/chat_ui.py
CHANGED
@@ -5,7 +5,7 @@ from janito.agent.runtime_config import runtime_config
|
|
5
5
|
|
6
6
|
|
7
7
|
def setup_prompt_session(
|
8
|
-
messages,
|
8
|
+
messages, last_usage_info_ref, last_elapsed, mem_history, profile_manager, agent
|
9
9
|
):
|
10
10
|
model_name = getattr(agent, "model", None)
|
11
11
|
|
@@ -13,7 +13,7 @@ def setup_prompt_session(
|
|
13
13
|
return messages
|
14
14
|
|
15
15
|
def get_usage():
|
16
|
-
return
|
16
|
+
return last_usage_info_ref["value"]
|
17
17
|
|
18
18
|
def get_elapsed():
|
19
19
|
return last_elapsed
|
@@ -32,7 +32,6 @@ def setup_prompt_session(
|
|
32
32
|
)
|
33
33
|
else (runtime_config.get("role") or effective_config.get("role"))
|
34
34
|
),
|
35
|
-
style_ref=lambda: getattr(profile_manager, "interaction_style", "default"),
|
36
35
|
),
|
37
36
|
mem_history,
|
38
37
|
)
|
@@ -1,13 +1,19 @@
|
|
1
1
|
from .session import handle_continue, handle_history
|
2
|
-
from .
|
2
|
+
from .prompt import handle_prompt, handle_role
|
3
3
|
from .session_control import handle_exit, handle_restart
|
4
4
|
from .utility import handle_help, handle_clear, handle_multi
|
5
|
+
from .termweb_log import handle_termweb_log_tail, handle_termweb_status
|
6
|
+
from .sum import handle_sum
|
5
7
|
from .config import handle_reload
|
6
|
-
from .
|
8
|
+
from .history_start import handle_start
|
7
9
|
from ..config_shell import handle_config_shell
|
10
|
+
from .verbose import handle_verbose
|
11
|
+
from .lang import handle_lang
|
8
12
|
from janito.agent.runtime_config import runtime_config
|
9
13
|
|
10
14
|
COMMAND_HANDLERS = {
|
15
|
+
"/termweb-logs": handle_termweb_log_tail,
|
16
|
+
"/termweb-status": handle_termweb_status,
|
11
17
|
"/history": handle_history,
|
12
18
|
"/continue": handle_continue,
|
13
19
|
"/exit": handle_exit,
|
@@ -15,19 +21,23 @@ COMMAND_HANDLERS = {
|
|
15
21
|
"/restart": handle_restart,
|
16
22
|
"/help": handle_help,
|
17
23
|
"/multi": handle_multi,
|
18
|
-
"/
|
24
|
+
"/prompt": handle_prompt,
|
25
|
+
"/verbose": handle_verbose,
|
19
26
|
}
|
20
27
|
|
21
28
|
if not runtime_config.get("vanilla_mode", False):
|
22
29
|
COMMAND_HANDLERS["/role"] = handle_role
|
23
30
|
|
31
|
+
|
32
|
+
COMMAND_HANDLERS["/lang"] = handle_lang
|
33
|
+
|
24
34
|
COMMAND_HANDLERS.update(
|
25
35
|
{
|
36
|
+
"/sum": handle_sum,
|
26
37
|
"/clear": handle_clear,
|
27
|
-
"/
|
38
|
+
"/start": handle_start,
|
28
39
|
"/config": handle_config_shell,
|
29
40
|
"/reload": handle_reload,
|
30
|
-
"/style": handle_style,
|
31
41
|
}
|
32
42
|
)
|
33
43
|
|
@@ -38,7 +48,8 @@ def handle_command(command, console, **kwargs):
|
|
38
48
|
args = parts[1:]
|
39
49
|
handler = COMMAND_HANDLERS.get(cmd)
|
40
50
|
if handler:
|
41
|
-
|
51
|
+
# Pass args as a keyword argument for handlers that expect it
|
52
|
+
return handler(console, args=args, **kwargs)
|
42
53
|
console.print(
|
43
54
|
f"[bold red]Invalid command: {cmd}. Type /help for a list of commands.[/bold red]"
|
44
55
|
)
|
@@ -2,14 +2,22 @@ from prompt_toolkit.history import InMemoryHistory
|
|
2
2
|
import os
|
3
3
|
|
4
4
|
|
5
|
-
def
|
5
|
+
def handle_start(console, state, **kwargs):
|
6
|
+
|
6
7
|
save_path = os.path.join(".janito", "last_conversation.json")
|
7
8
|
|
9
|
+
# Clear the terminal screen
|
10
|
+
os.system("cls" if os.name == "nt" else "clear")
|
11
|
+
|
8
12
|
# Clear in-memory conversation and prompt history
|
9
13
|
state["messages"].clear()
|
10
14
|
state["history_list"].clear()
|
11
15
|
state["mem_history"] = InMemoryHistory()
|
12
|
-
state["last_usage_info"] =
|
16
|
+
state["last_usage_info"] = {
|
17
|
+
"prompt_tokens": 0,
|
18
|
+
"completion_tokens": 0,
|
19
|
+
"total_tokens": 0,
|
20
|
+
}
|
13
21
|
state["last_elapsed"] = None
|
14
22
|
|
15
23
|
# Delete saved conversation file if exists
|
@@ -23,7 +31,7 @@ def handle_reset(console, state, **kwargs):
|
|
23
31
|
console.print(
|
24
32
|
f"[bold red]Failed to delete saved conversation:[/bold red] {e}"
|
25
33
|
)
|
26
|
-
else:
|
27
|
-
console.print("[bold yellow]No saved conversation to delete.[/bold yellow]")
|
28
34
|
|
29
|
-
console.print(
|
35
|
+
console.print(
|
36
|
+
"[bold green]Conversation history has been started (context reset).[/bold green]"
|
37
|
+
)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from janito.agent.runtime_config import runtime_config
|
2
|
+
import janito.i18n as i18n
|
3
|
+
|
4
|
+
|
5
|
+
def handle_lang(console, args=None, **kwargs):
|
6
|
+
if not args or len(args) == 0:
|
7
|
+
console.print(
|
8
|
+
"[bold yellow]Uso: /lang [código_idioma] (ex: pt, en, es)[/bold yellow]"
|
9
|
+
)
|
10
|
+
return
|
11
|
+
lang_code = args[0]
|
12
|
+
runtime_config.set("lang", lang_code)
|
13
|
+
i18n.set_locale(lang_code)
|
14
|
+
console.print(
|
15
|
+
f"[bold green]Idioma alterado para:[/bold green] [cyan]{lang_code}[/cyan]"
|
16
|
+
)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from janito.agent.runtime_config import runtime_config
|
2
|
+
|
3
|
+
|
4
|
+
def handle_prompt(console, **kwargs):
|
5
|
+
profile_manager = kwargs.get("profile_manager")
|
6
|
+
prompt = profile_manager.system_prompt_template if profile_manager else None
|
7
|
+
if not prompt and profile_manager:
|
8
|
+
prompt = profile_manager.system_prompt_template
|
9
|
+
console.print(f"[bold magenta]System Prompt:[/bold magenta]\n{prompt}")
|
10
|
+
|
11
|
+
|
12
|
+
def handle_role(console, *args, **kwargs):
|
13
|
+
state = kwargs.get("state")
|
14
|
+
profile_manager = kwargs.get("profile_manager")
|
15
|
+
if not args:
|
16
|
+
console.print("[bold red]Usage: /role <new role description>[/bold red]")
|
17
|
+
return
|
18
|
+
new_role = " ".join(args)
|
19
|
+
if profile_manager:
|
20
|
+
profile_manager.set_role(new_role)
|
21
|
+
# Update system message in conversation
|
22
|
+
found = False
|
23
|
+
for msg in state["messages"]:
|
24
|
+
if msg.get("role") == "system":
|
25
|
+
msg["content"] = (
|
26
|
+
profile_manager.system_prompt_template if profile_manager else new_role
|
27
|
+
)
|
28
|
+
found = True
|
29
|
+
break
|
30
|
+
if not found:
|
31
|
+
state["messages"].insert(0, {"role": "system", "content": new_role})
|
32
|
+
# Also store the raw role string
|
33
|
+
if profile_manager:
|
34
|
+
setattr(profile_manager, "role_name", new_role)
|
35
|
+
runtime_config.set("role", new_role)
|
36
|
+
console.print(f"[bold green]System role updated to:[/bold green] {new_role}")
|
37
|
+
|
38
|
+
|
39
|
+
def handle_profile(console, *args, **kwargs):
|
40
|
+
"""/profile - Show the current and available Agent Profile (only 'base' is supported)"""
|
41
|
+
console.print("[bold green]Current profile:[/bold green] base")
|
42
|
+
console.print("[bold yellow]Available profiles:[/bold yellow]\n- base")
|
@@ -1,5 +1,40 @@
|
|
1
1
|
import os
|
2
2
|
import sys
|
3
|
+
import subprocess
|
4
|
+
|
5
|
+
|
6
|
+
def restart_cli():
|
7
|
+
# Clean up prompt_toolkit session if active
|
8
|
+
try:
|
9
|
+
from janito.cli_chat_shell import chat_loop
|
10
|
+
|
11
|
+
session = getattr(chat_loop, "active_prompt_session", None)
|
12
|
+
if session is not None and hasattr(session, "app"):
|
13
|
+
session.app.exit()
|
14
|
+
except Exception:
|
15
|
+
pass # Ignore cleanup errors
|
16
|
+
|
17
|
+
if os.name == "nt":
|
18
|
+
if (
|
19
|
+
"powershell" in os.environ.get("SHELL", "").lower()
|
20
|
+
or "pwsh" in sys.executable.lower()
|
21
|
+
):
|
22
|
+
args = [
|
23
|
+
"powershell",
|
24
|
+
"-Command",
|
25
|
+
"Start-Process",
|
26
|
+
sys.executable,
|
27
|
+
"-ArgumentList",
|
28
|
+
"'-m','janito"
|
29
|
+
+ ("','" + "','".join(sys.argv[1:]) if sys.argv[1:] else "")
|
30
|
+
+ "'",
|
31
|
+
]
|
32
|
+
subprocess.Popen(args)
|
33
|
+
else:
|
34
|
+
subprocess.Popen([sys.executable, "-m", "janito"] + sys.argv[1:])
|
35
|
+
sys.exit(0)
|
36
|
+
else:
|
37
|
+
os.execv(sys.executable, [sys.executable, "-m", "janito"] + sys.argv[1:])
|
3
38
|
|
4
39
|
|
5
40
|
def handle_exit(console, **kwargs):
|
@@ -9,4 +44,4 @@ def handle_exit(console, **kwargs):
|
|
9
44
|
|
10
45
|
def handle_restart(console, **kwargs):
|
11
46
|
console.print("[bold yellow]Restarting CLI...[/bold yellow]")
|
12
|
-
|
47
|
+
restart_cli()
|
@@ -0,0 +1,49 @@
|
|
1
|
+
def handle_sum(console, state, **kwargs):
|
2
|
+
"""
|
3
|
+
Summarize the current chat history and replace it with a summary message.
|
4
|
+
"""
|
5
|
+
agent = kwargs.get("agent")
|
6
|
+
if agent is None:
|
7
|
+
console.print("[bold red]Agent not provided to /sum command.[/bold red]")
|
8
|
+
return
|
9
|
+
|
10
|
+
messages = state.get("messages", [])
|
11
|
+
if not messages or len(messages) < 2:
|
12
|
+
console.print(
|
13
|
+
"[bold yellow]Not enough conversation to summarize.[/bold yellow]"
|
14
|
+
)
|
15
|
+
return
|
16
|
+
|
17
|
+
# Find the system message if present
|
18
|
+
system_msg = next((m for m in messages if m.get("role") == "system"), None)
|
19
|
+
|
20
|
+
# Prepare summary prompt
|
21
|
+
summary_prompt = {
|
22
|
+
"role": "user",
|
23
|
+
"content": "Summarize the following conversation in a concise paragraph for context. Only output the summary, do not include any tool calls or formatting.",
|
24
|
+
}
|
25
|
+
# Exclude system messages for the summary context
|
26
|
+
convo_for_summary = [m for m in messages if m.get("role") != "system"]
|
27
|
+
summary_messages = [summary_prompt] + convo_for_summary
|
28
|
+
|
29
|
+
try:
|
30
|
+
summary_response = agent.chat(summary_messages, spinner=True, max_tokens=256)
|
31
|
+
summary_text = (
|
32
|
+
summary_response["content"]
|
33
|
+
if isinstance(summary_response, dict)
|
34
|
+
else str(summary_response)
|
35
|
+
)
|
36
|
+
except Exception as e:
|
37
|
+
console.print(f"[bold red]Error during summarization: {e}[/bold red]")
|
38
|
+
return
|
39
|
+
|
40
|
+
# Rebuild conversation history
|
41
|
+
new_history = []
|
42
|
+
if system_msg:
|
43
|
+
new_history.append(system_msg)
|
44
|
+
new_history.append({"role": "assistant", "content": summary_text})
|
45
|
+
state["messages"] = new_history
|
46
|
+
|
47
|
+
console.print(
|
48
|
+
"[bold green]Conversation summarized and history replaced with summary.[/bold green]"
|
49
|
+
)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import http.client
|
2
|
+
from rich.console import Console
|
3
|
+
from janito.agent.runtime_config import runtime_config
|
4
|
+
|
5
|
+
|
6
|
+
def is_termweb_running(port):
|
7
|
+
"""Check if termweb is running by making an HTTP request to the root endpoint."""
|
8
|
+
try:
|
9
|
+
conn = http.client.HTTPConnection("localhost", port, timeout=0.5)
|
10
|
+
conn.request("GET", "/")
|
11
|
+
resp = conn.getresponse()
|
12
|
+
return resp.status == 200
|
13
|
+
except Exception:
|
14
|
+
return False
|
15
|
+
|
16
|
+
|
17
|
+
def handle_termweb_log_tail(console: Console, *args, state=None, **kwargs):
|
18
|
+
lines = 20
|
19
|
+
if args and args[0].isdigit():
|
20
|
+
lines = int(args[0])
|
21
|
+
stdout_path = state.get("termweb_stdout_path") if state else None
|
22
|
+
stderr_path = state.get("termweb_stderr_path") if state else None
|
23
|
+
if not stdout_path and not stderr_path:
|
24
|
+
console.print(
|
25
|
+
"[yellow][termweb] No termweb log files found for this session.[/yellow]"
|
26
|
+
)
|
27
|
+
return
|
28
|
+
if stdout_path:
|
29
|
+
try:
|
30
|
+
with open(stdout_path, encoding="utf-8") as f:
|
31
|
+
stdout_lines = f.readlines()[-lines:]
|
32
|
+
if stdout_lines:
|
33
|
+
console.print(
|
34
|
+
f"[yellow][termweb][stdout] Tail of {stdout_path}:\n"
|
35
|
+
+ "".join(stdout_lines)
|
36
|
+
)
|
37
|
+
except Exception:
|
38
|
+
pass
|
39
|
+
if stderr_path:
|
40
|
+
try:
|
41
|
+
with open(stderr_path, encoding="utf-8") as f:
|
42
|
+
stderr_lines = f.readlines()[-lines:]
|
43
|
+
if stderr_lines:
|
44
|
+
console.print(
|
45
|
+
f"[red][termweb][stderr] Tail of {stderr_path}:\n"
|
46
|
+
+ "".join(stderr_lines)
|
47
|
+
)
|
48
|
+
except Exception:
|
49
|
+
pass
|
50
|
+
if (not stdout_path or not stdout_lines) and (not stderr_path or not stderr_lines):
|
51
|
+
console.print("[termweb] No output or errors captured in logs.")
|
52
|
+
|
53
|
+
|
54
|
+
def handle_termweb_status(console: Console, *args, state=None, **kwargs):
|
55
|
+
if state is None:
|
56
|
+
console.print(
|
57
|
+
"[red]No shell state available. Cannot determine termweb status.[/red]"
|
58
|
+
)
|
59
|
+
return
|
60
|
+
port = state.get("termweb_port")
|
61
|
+
port_source = "state"
|
62
|
+
if not port:
|
63
|
+
port = runtime_config.get("termweb_port")
|
64
|
+
port_source = "runtime_config"
|
65
|
+
pid = state.get("termweb_pid")
|
66
|
+
stdout_path = state.get("termweb_stdout_path")
|
67
|
+
stderr_path = state.get("termweb_stderr_path")
|
68
|
+
running = False
|
69
|
+
if port:
|
70
|
+
running = is_termweb_running(port)
|
71
|
+
console.print("[bold cyan]TermWeb Server Status:[/bold cyan]")
|
72
|
+
console.print(f" Running: {'[green]Yes[/green]' if running else '[red]No[/red]'}")
|
73
|
+
if pid:
|
74
|
+
console.print(f" PID: {pid}")
|
75
|
+
if port:
|
76
|
+
console.print(f" Port: {port} (from {port_source})")
|
77
|
+
url = f"http://localhost:{port}/"
|
78
|
+
console.print(f" URL: [underline blue]{url}[/underline blue]")
|
79
|
+
else:
|
80
|
+
console.print(
|
81
|
+
" [yellow]No port configured in state or runtime_config.[/yellow]"
|
82
|
+
)
|
83
|
+
if stdout_path:
|
84
|
+
console.print(f" Stdout log: {stdout_path}")
|
85
|
+
if stderr_path:
|
86
|
+
console.print(f" Stderr log: {stderr_path}")
|
@@ -6,12 +6,15 @@ def handle_help(console, **kwargs):
|
|
6
6
|
/restart - Restart the CLI
|
7
7
|
/help - Show this help message
|
8
8
|
/continue - Restore last saved conversation
|
9
|
-
/
|
10
|
-
/
|
9
|
+
/start - Reset conversation history
|
10
|
+
/prompt - Show the system prompt
|
11
11
|
/role - Change the system role
|
12
12
|
/clear - Clear the terminal screen
|
13
13
|
/multi - Provide multiline input as next message
|
14
14
|
/config - Show or set configuration (see: /config show, /config set local|global key=value)
|
15
|
+
/termweb-logs - Show the last lines of the latest termweb logs
|
16
|
+
/termweb-status - Show status information about the running termweb server
|
17
|
+
/verbose [on|off] - Show or set verbose mode for this session
|
15
18
|
"""
|
16
19
|
)
|
17
20
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from janito.agent.runtime_config import runtime_config
|
2
|
+
|
3
|
+
|
4
|
+
def handle_verbose(console, state, **kwargs):
|
5
|
+
"""
|
6
|
+
/verbose [on|off]
|
7
|
+
Shows or sets verbose mode for the current shell session.
|
8
|
+
"""
|
9
|
+
args = kwargs.get("args", [])
|
10
|
+
verbose = runtime_config.get("verbose", False)
|
11
|
+
if not args:
|
12
|
+
status = "ON" if verbose else "OFF"
|
13
|
+
console.print(
|
14
|
+
f"[bold green]/verbose:[/bold green] Verbose mode is currently [bold]{status}[/bold]."
|
15
|
+
)
|
16
|
+
return
|
17
|
+
arg = args[0].lower()
|
18
|
+
if arg == "on":
|
19
|
+
runtime_config["verbose"] = True
|
20
|
+
console.print(
|
21
|
+
"[bold green]/verbose:[/bold green] Verbose mode is now [bold]ON[/bold]."
|
22
|
+
)
|
23
|
+
elif arg == "off":
|
24
|
+
runtime_config["verbose"] = False
|
25
|
+
console.print(
|
26
|
+
"[bold green]/verbose:[/bold green] Verbose mode is now [bold]OFF[/bold]."
|
27
|
+
)
|
28
|
+
else:
|
29
|
+
console.print("[bold red]Usage:[/bold red] /verbose [on|off]")
|
@@ -1,18 +1,57 @@
|
|
1
1
|
import os
|
2
|
+
import importlib.resources
|
2
3
|
|
3
4
|
|
4
5
|
def load_prompt(filename=None):
|
5
6
|
"""
|
6
7
|
Load the system prompt from a file. If filename is None, use the default prompt file.
|
7
8
|
Returns the prompt string.
|
9
|
+
Tries source path first, then falls back to importlib.resources for installed packages.
|
8
10
|
"""
|
11
|
+
default_rel_path = os.path.normpath(
|
12
|
+
os.path.join(
|
13
|
+
os.path.dirname(__file__),
|
14
|
+
"../agent/templates/profiles/system_prompt_template_default.j2",
|
15
|
+
)
|
16
|
+
)
|
9
17
|
if filename is None:
|
10
|
-
|
11
|
-
|
12
|
-
|
18
|
+
filename = default_rel_path
|
19
|
+
|
20
|
+
# Try loading from source path first
|
21
|
+
abs_path = os.path.abspath(filename)
|
22
|
+
if os.path.exists(abs_path):
|
23
|
+
with open(abs_path, "r", encoding="utf-8") as f:
|
24
|
+
return f.read()
|
25
|
+
|
26
|
+
# If not found, try importlib.resources (for installed package)
|
27
|
+
try:
|
28
|
+
# Remove leading directories up to 'janito/agent/templates'
|
29
|
+
# and get the relative path inside the package
|
30
|
+
resource_path = filename
|
31
|
+
for marker in ["janito/agent/templates/", "agent/templates/"]:
|
32
|
+
idx = filename.replace("\\", "/").find(marker)
|
33
|
+
if idx != -1:
|
34
|
+
resource_path = filename[idx + len("janito/agent/templates/") :]
|
35
|
+
break
|
36
|
+
|
37
|
+
# Try loading from janito.agent.templates.profiles
|
38
|
+
if resource_path.startswith("profiles/"):
|
39
|
+
package = "janito.agent.templates.profiles"
|
40
|
+
resource = resource_path[len("profiles/") :]
|
41
|
+
elif resource_path.startswith("features/"):
|
42
|
+
package = "janito.agent.templates.features"
|
43
|
+
resource = resource_path[len("features/") :]
|
44
|
+
else:
|
45
|
+
package = "janito.agent.templates"
|
46
|
+
resource = resource_path
|
47
|
+
|
48
|
+
with (
|
49
|
+
importlib.resources.files(package)
|
50
|
+
.joinpath(resource)
|
51
|
+
.open("r", encoding="utf-8") as f
|
52
|
+
):
|
53
|
+
return f.read()
|
54
|
+
except Exception as e:
|
55
|
+
raise FileNotFoundError(
|
56
|
+
f"Prompt file not found at '{abs_path}' or in package resources: {e}"
|
13
57
|
)
|
14
|
-
filename = os.path.abspath(filename)
|
15
|
-
if not os.path.exists(filename):
|
16
|
-
raise FileNotFoundError(f"Prompt file not found: {filename}")
|
17
|
-
with open(filename, "r", encoding="utf-8") as f:
|
18
|
-
return f.read()
|
@@ -27,8 +27,16 @@ def save_conversation(
|
|
27
27
|
):
|
28
28
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
29
29
|
data = {"messages": messages, "prompts": prompts, "last_usage_info": usage_info}
|
30
|
+
|
31
|
+
def usage_serializer(obj):
|
32
|
+
if hasattr(obj, "to_dict"):
|
33
|
+
return obj.to_dict()
|
34
|
+
if hasattr(obj, "__dict__"):
|
35
|
+
return obj.__dict__
|
36
|
+
return str(obj)
|
37
|
+
|
30
38
|
with open(path, "w", encoding="utf-8") as f:
|
31
|
-
json.dump(data, f, indent=2)
|
39
|
+
json.dump(data, f, indent=2, default=usage_serializer)
|
32
40
|
|
33
41
|
|
34
42
|
def load_input_history():
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from prompt_toolkit.completion import Completer, Completion
|
2
|
+
|
3
|
+
|
4
|
+
class ShellCommandCompleter(Completer):
|
5
|
+
def __init__(self):
|
6
|
+
# Import here to avoid circular import at module level
|
7
|
+
from janito.cli_chat_shell.commands import COMMAND_HANDLERS
|
8
|
+
|
9
|
+
# Only commands starting with '/'
|
10
|
+
self.commands = sorted(
|
11
|
+
[cmd for cmd in COMMAND_HANDLERS.keys() if cmd.startswith("/")]
|
12
|
+
)
|
13
|
+
|
14
|
+
def get_completions(self, document, complete_event):
|
15
|
+
text = document.text_before_cursor
|
16
|
+
if text.startswith("/"):
|
17
|
+
prefix = text[1:]
|
18
|
+
for cmd in self.commands:
|
19
|
+
if cmd[1:].startswith(prefix):
|
20
|
+
yield Completion(cmd, start_position=-(len(prefix) + 1))
|