janito 2.3.1__py3-none-any.whl → 2.5.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/_version.py +57 -0
- janito/agent/setup_agent.py +95 -21
- janito/agent/templates/profiles/system_prompt_template_assistant.txt.j2 +1 -0
- janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
- janito/cli/chat_mode/bindings.py +21 -2
- janito/cli/chat_mode/chat_entry.py +2 -3
- janito/cli/chat_mode/prompt_style.py +5 -0
- janito/cli/chat_mode/script_runner.py +153 -0
- janito/cli/chat_mode/session.py +128 -122
- janito/cli/chat_mode/session_profile_select.py +80 -0
- janito/cli/chat_mode/shell/commands/__init__.py +19 -9
- janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
- janito/cli/chat_mode/shell/commands/bang.py +36 -0
- janito/cli/chat_mode/shell/commands/conversation_restart.py +31 -24
- janito/cli/chat_mode/shell/commands/execute.py +42 -0
- janito/cli/chat_mode/shell/commands/help.py +7 -4
- janito/cli/chat_mode/shell/commands/model.py +28 -0
- janito/cli/chat_mode/shell/commands/prompt.py +0 -8
- janito/cli/chat_mode/shell/commands/read.py +37 -0
- janito/cli/chat_mode/shell/commands/tools.py +45 -18
- janito/cli/chat_mode/shell/commands/write.py +37 -0
- janito/cli/chat_mode/shell/commands.bak.zip +0 -0
- janito/cli/chat_mode/shell/input_history.py +1 -1
- janito/cli/chat_mode/shell/session/manager.py +0 -68
- janito/cli/chat_mode/shell/session.bak.zip +0 -0
- janito/cli/chat_mode/toolbar.py +44 -27
- janito/cli/cli_commands/list_tools.py +44 -11
- janito/cli/cli_commands/model_utils.py +95 -95
- janito/cli/cli_commands/show_system_prompt.py +57 -14
- janito/cli/config.py +5 -6
- janito/cli/core/getters.py +33 -33
- janito/cli/core/runner.py +27 -20
- janito/cli/core/setters.py +10 -1
- janito/cli/main_cli.py +40 -10
- janito/cli/prompt_core.py +18 -2
- janito/cli/prompt_setup.py +56 -0
- janito/cli/rich_terminal_reporter.py +21 -6
- janito/cli/single_shot_mode/handler.py +24 -77
- janito/cli/verbose_output.py +1 -1
- janito/config_manager.py +125 -112
- janito/drivers/dashscope.bak.zip +0 -0
- janito/drivers/driver_registry.py +0 -2
- janito/drivers/openai/README.md +20 -0
- janito/drivers/openai_responses.bak.zip +0 -0
- janito/event_bus/event.py +2 -2
- janito/formatting_token.py +7 -6
- janito/i18n/pt.py +0 -1
- janito/llm/README.md +23 -0
- janito/llm/agent.py +80 -16
- janito/llm/auth.py +63 -63
- janito/llm/driver.py +8 -0
- janito/provider_registry.py +178 -176
- janito/providers/__init__.py +0 -2
- janito/providers/azure_openai/model_info.py +16 -16
- janito/providers/dashscope.bak.zip +0 -0
- janito/providers/provider_static_info.py +0 -3
- janito/providers/registry.py +26 -26
- janito/shell.bak.zip +0 -0
- janito/tools/DOCSTRING_STANDARD.txt +33 -0
- janito/tools/README.md +3 -0
- janito/tools/__init__.py +20 -6
- janito/tools/adapters/local/__init__.py +65 -62
- janito/tools/adapters/local/adapter.py +18 -35
- janito/tools/adapters/local/ask_user.py +3 -4
- janito/tools/adapters/local/copy_file.py +2 -2
- janito/tools/adapters/local/create_directory.py +2 -2
- janito/tools/adapters/local/create_file.py +2 -2
- janito/tools/adapters/local/delete_text_in_file.py +2 -2
- janito/tools/adapters/local/fetch_url.py +2 -2
- janito/tools/adapters/local/find_files.py +2 -1
- janito/tools/adapters/local/get_file_outline/core.py +2 -2
- janito/tools/adapters/local/get_file_outline/search_outline.py +2 -2
- janito/tools/adapters/local/move_file.py +2 -2
- janito/tools/adapters/local/open_html_in_browser.py +2 -1
- janito/tools/adapters/local/open_url.py +2 -2
- janito/tools/adapters/local/python_code_run.py +3 -3
- janito/tools/adapters/local/python_command_run.py +3 -3
- janito/tools/adapters/local/python_file_run.py +3 -3
- janito/tools/adapters/local/remove_directory.py +2 -2
- janito/tools/adapters/local/remove_file.py +2 -2
- janito/tools/adapters/local/replace_text_in_file.py +2 -2
- janito/tools/adapters/local/run_bash_command.py +3 -3
- janito/tools/adapters/local/run_powershell_command.py +3 -3
- janito/tools/adapters/local/search_text/core.py +2 -2
- janito/tools/adapters/local/validate_file_syntax/core.py +3 -3
- janito/tools/adapters/local/view_file.py +2 -1
- janito/tools/outline_file.bak.zip +0 -0
- janito/tools/permissions.py +45 -0
- janito/tools/permissions_parse.py +12 -0
- janito/tools/tool_base.py +14 -11
- janito/tools/tool_utils.py +4 -6
- janito/tools/tools_adapter.py +25 -20
- {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/METADATA +46 -24
- {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/RECORD +99 -82
- janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
- janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
- janito/cli/chat_mode/shell/commands/edit.py +0 -25
- janito/cli/chat_mode/shell/commands/exec.py +0 -27
- janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
- janito/cli/termweb_starter.py +0 -122
- janito/termweb/app.py +0 -95
- janito/version.py +0 -4
- {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/WHEEL +0 -0
- {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/entry_points.txt +0 -0
- {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/top_level.txt +0 -0
janito/cli/chat_mode/session.py
CHANGED
@@ -3,6 +3,8 @@ Session management for Janito Chat CLI.
|
|
3
3
|
Defines ChatSession and ChatShellState classes.
|
4
4
|
"""
|
5
5
|
|
6
|
+
from __future__ import annotations
|
7
|
+
|
6
8
|
import types
|
7
9
|
from rich.console import Console
|
8
10
|
from rich.rule import Rule
|
@@ -17,23 +19,22 @@ from janito.cli.chat_mode.bindings import KeyBindingsFactory
|
|
17
19
|
from janito.cli.chat_mode.shell.commands import handle_command
|
18
20
|
from janito.cli.chat_mode.shell.autocomplete import ShellCommandCompleter
|
19
21
|
|
22
|
+
# Shared prompt/agent factory
|
23
|
+
from janito.cli.prompt_setup import setup_agent_and_prompt_handler
|
24
|
+
|
20
25
|
|
21
26
|
class ChatShellState:
|
22
27
|
def __init__(self, mem_history, conversation_history):
|
23
|
-
self.allow_execution = False # Controls whether execution tools are enabled
|
24
28
|
self.mem_history = mem_history
|
25
29
|
self.conversation_history = conversation_history
|
26
30
|
self.paste_mode = False
|
27
|
-
self.
|
28
|
-
self.
|
29
|
-
self.
|
30
|
-
self.
|
31
|
+
self._port = None
|
32
|
+
self._pid = None
|
33
|
+
self._stdout_path = None
|
34
|
+
self._stderr_path = None
|
31
35
|
self.livereload_stderr_path = None
|
32
|
-
self.
|
33
|
-
|
34
|
-
None # 'online', 'offline', updated by background checker
|
35
|
-
)
|
36
|
-
self.termweb_live_checked_time = None # datetime.datetime of last status check
|
36
|
+
self._status = "starting" # Tracks the current status (updated by background thread/UI)
|
37
|
+
|
37
38
|
self.last_usage_info = {}
|
38
39
|
self.last_elapsed = None
|
39
40
|
self.main_agent = {}
|
@@ -53,25 +54,10 @@ class ChatSession:
|
|
53
54
|
args=None,
|
54
55
|
verbose_tools=False,
|
55
56
|
verbose_agent=False,
|
56
|
-
|
57
|
+
|
58
|
+
allowed_permissions=None,
|
57
59
|
):
|
58
|
-
|
59
|
-
if args is not None and hasattr(args, "exec"):
|
60
|
-
allow_execution = bool(getattr(args, "exec", False))
|
61
|
-
else:
|
62
|
-
allow_execution = exec_enabled
|
63
|
-
from janito.cli.prompt_core import PromptHandler as GenericPromptHandler
|
64
|
-
|
65
|
-
self._prompt_handler = GenericPromptHandler(
|
66
|
-
args=None,
|
67
|
-
conversation_history=(
|
68
|
-
None
|
69
|
-
if not hasattr(self, "shell_state")
|
70
|
-
else self.shell_state.conversation_history
|
71
|
-
),
|
72
|
-
provider_instance=provider_instance,
|
73
|
-
)
|
74
|
-
self._prompt_handler.agent = None # Will be set below if agent exists
|
60
|
+
|
75
61
|
self.console = console
|
76
62
|
self.user_input_history = UserInputHistory()
|
77
63
|
self.input_dicts = self.user_input_history.load()
|
@@ -81,27 +67,54 @@ class ChatSession:
|
|
81
67
|
self.mem_history.append_string(item["input"])
|
82
68
|
self.provider_instance = provider_instance
|
83
69
|
self.llm_driver_config = llm_driver_config
|
84
|
-
from janito.agent.setup_agent import create_configured_agent
|
85
70
|
|
86
|
-
|
71
|
+
# --- Profile selection (interactive) ---------------------------------
|
72
|
+
profile = getattr(args, "profile", None) if args is not None else None
|
73
|
+
profile_system_prompt = None
|
74
|
+
if profile is None:
|
75
|
+
try:
|
76
|
+
from janito.cli.chat_mode.session_profile_select import select_profile
|
77
|
+
|
78
|
+
result = select_profile()
|
79
|
+
if isinstance(result, dict):
|
80
|
+
profile = result.get("profile")
|
81
|
+
profile_system_prompt = result.get("profile_system_prompt")
|
82
|
+
elif isinstance(result, str) and result.startswith("role:"):
|
83
|
+
role = result[len("role:") :].strip()
|
84
|
+
profile = "developer"
|
85
|
+
else:
|
86
|
+
profile = (
|
87
|
+
"developer" if result == "software developer" else result
|
88
|
+
)
|
89
|
+
except ImportError:
|
90
|
+
profile = "helpful assistant"
|
91
|
+
|
92
|
+
# ---------------------------------------------------------------------
|
93
|
+
from janito.conversation_history import LLMConversationHistory
|
94
|
+
|
95
|
+
conversation_history = LLMConversationHistory()
|
96
|
+
|
97
|
+
# Build agent and core prompt handler via the shared helper
|
98
|
+
self.agent, self._prompt_handler = setup_agent_and_prompt_handler(
|
99
|
+
args=args,
|
87
100
|
provider_instance=provider_instance,
|
88
101
|
llm_driver_config=llm_driver_config,
|
89
102
|
role=role,
|
90
103
|
verbose_tools=verbose_tools,
|
91
104
|
verbose_agent=verbose_agent,
|
92
|
-
|
105
|
+
|
106
|
+
allowed_permissions=allowed_permissions,
|
107
|
+
profile=profile,
|
108
|
+
profile_system_prompt=profile_system_prompt,
|
109
|
+
conversation_history=conversation_history,
|
93
110
|
)
|
94
|
-
from janito.conversation_history import LLMConversationHistory
|
95
111
|
|
96
|
-
self.shell_state = ChatShellState(self.mem_history,
|
97
|
-
self.shell_state.agent = agent
|
98
|
-
self.shell_state.allow_execution = allow_execution
|
99
|
-
self.agent = agent
|
112
|
+
self.shell_state = ChatShellState(self.mem_history, conversation_history)
|
113
|
+
self.shell_state.agent = self.agent
|
100
114
|
# Filter execution tools at startup
|
101
115
|
try:
|
102
|
-
registry
|
103
|
-
|
104
|
-
registry.set_execution_tools_enabled(allow_execution)
|
116
|
+
# Permissions are now managed globally; registry filtering is automatic
|
117
|
+
getattr(__import__('janito.tools', fromlist=['get_local_tools_adapter']), 'get_local_tools_adapter')()
|
105
118
|
except Exception as e:
|
106
119
|
self.console.print(f"[yellow]Warning: Could not filter execution tools at startup: {e}[/yellow]")
|
107
120
|
from janito.perf_singleton import performance_collector
|
@@ -114,76 +127,54 @@ class ChatSession:
|
|
114
127
|
self.shell_state.conversation_history
|
115
128
|
)
|
116
129
|
|
117
|
-
|
118
|
-
self.termweb_support = False
|
130
|
+
self._support = False
|
119
131
|
if args and getattr(args, "web", False):
|
120
|
-
self.
|
121
|
-
self.shell_state.
|
122
|
-
from janito.cli.
|
123
|
-
from janito.cli.config import
|
132
|
+
self._support = True
|
133
|
+
self.shell_state._support = self._support
|
134
|
+
from janito.cli._starter import _start_and_watch
|
135
|
+
from janito.cli.config import get__port
|
124
136
|
import threading
|
125
137
|
from rich.console import Console
|
126
138
|
|
127
|
-
Console().print("[yellow]Starting
|
128
|
-
self.
|
129
|
-
|
130
|
-
self.shell_state, self.
|
139
|
+
Console().print("[yellow]Starting in background...[/yellow]")
|
140
|
+
self._lock = threading.Lock()
|
141
|
+
_thread = _start_and_watch(
|
142
|
+
self.shell_state, self._lock, get__port()
|
131
143
|
)
|
132
144
|
# Initial status is set to 'starting' by constructor; the watcher will update
|
133
|
-
self.
|
145
|
+
self._thread = _thread
|
134
146
|
|
135
|
-
# Start a background timer to update live
|
147
|
+
# Start a background timer to update live status (for UI responsiveness)
|
136
148
|
import threading, datetime
|
137
149
|
|
138
|
-
|
139
|
-
while True:
|
140
|
-
with self.termweb_lock:
|
141
|
-
port = getattr(self.shell_state, "termweb_port", None)
|
142
|
-
if port:
|
143
|
-
try:
|
144
|
-
# is_termweb_running is removed; inline health check here:
|
145
|
-
try:
|
146
|
-
import http.client
|
147
|
-
|
148
|
-
conn = http.client.HTTPConnection(
|
149
|
-
"localhost", port, timeout=0.5
|
150
|
-
)
|
151
|
-
conn.request("GET", "/")
|
152
|
-
resp = conn.getresponse()
|
153
|
-
running = resp.status == 200
|
154
|
-
except Exception:
|
155
|
-
running = False
|
156
|
-
self.shell_state.termweb_live_status = (
|
157
|
-
"online" if running else "offline"
|
158
|
-
)
|
159
|
-
except Exception:
|
160
|
-
self.shell_state.termweb_live_status = "offline"
|
161
|
-
self.shell_state.termweb_live_checked_time = (
|
162
|
-
datetime.datetime.now()
|
163
|
-
)
|
164
|
-
else:
|
165
|
-
self.shell_state.termweb_live_status = None
|
166
|
-
self.shell_state.termweb_live_checked_time = (
|
167
|
-
datetime.datetime.now()
|
168
|
-
)
|
169
|
-
# sleep outside lock
|
170
|
-
threading.Event().wait(1.0)
|
171
|
-
|
172
|
-
self._termweb_liveness_thread = threading.Thread(
|
173
|
-
target=update_termweb_liveness, daemon=True
|
174
|
-
)
|
175
|
-
self._termweb_liveness_thread.start()
|
176
|
-
# No queue or blocking checks; UI (and timer) will observe self.shell_state fields
|
150
|
+
# Health check and liveness thread removed as per refactor to eliminate localhost references.
|
177
151
|
|
178
152
|
else:
|
179
|
-
self.shell_state.
|
180
|
-
self.shell_state.
|
153
|
+
self.shell_state._support = False
|
154
|
+
self.shell_state._status = "offline"
|
181
155
|
|
182
156
|
def run(self):
|
183
|
-
|
157
|
+
self.console.clear()
|
158
|
+
from janito import __version__
|
184
159
|
self.console.print(
|
185
|
-
"[bold green]
|
160
|
+
f"[bold green]Janito Chat Mode v{__version__}[/bold green]"
|
186
161
|
)
|
162
|
+
self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
|
163
|
+
import os
|
164
|
+
cwd = os.getcwd()
|
165
|
+
home = os.path.expanduser('~')
|
166
|
+
if cwd.startswith(home):
|
167
|
+
cwd_display = '~' + cwd[len(home):]
|
168
|
+
else:
|
169
|
+
cwd_display = cwd
|
170
|
+
self.console.print(f"[green]Working Dir:[/green] {cwd_display}")
|
171
|
+
|
172
|
+
# Inform user if no privileges are enabled
|
173
|
+
from janito.cli.chat_mode.shell.commands._priv_check import user_has_any_privileges
|
174
|
+
if not user_has_any_privileges():
|
175
|
+
self.console.print("[yellow]Note: You currently have no privileges enabled. If you need to interact with files or the system, enable permissions using /read on, /write on, or /execute on.[/yellow]")
|
176
|
+
|
177
|
+
session = self._create_prompt_session()
|
187
178
|
self._chat_loop(session)
|
188
179
|
|
189
180
|
def _chat_loop(self, session):
|
@@ -199,40 +190,55 @@ class ChatSession:
|
|
199
190
|
continue
|
200
191
|
if self._handle_exit_conditions(cmd_input):
|
201
192
|
break
|
202
|
-
if
|
203
|
-
handle_command(cmd_input, shell_state=self.shell_state)
|
193
|
+
if self._handle_command_input(cmd_input):
|
204
194
|
continue
|
205
195
|
self.user_input_history.append(cmd_input)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
196
|
+
self._process_prompt(cmd_input)
|
197
|
+
|
198
|
+
def _handle_command_input(self, cmd_input):
|
199
|
+
if cmd_input.startswith("/"):
|
200
|
+
handle_command(cmd_input, shell_state=self.shell_state)
|
201
|
+
return True
|
202
|
+
if cmd_input.startswith("!"):
|
203
|
+
# Pass everything after ! to the bang handler
|
204
|
+
handle_command(f"! {cmd_input[1:]}", shell_state=self.shell_state)
|
205
|
+
return True
|
206
|
+
return False
|
207
|
+
|
208
|
+
def _process_prompt(self, cmd_input):
|
209
|
+
try:
|
210
|
+
import time
|
211
|
+
final_event = (
|
212
|
+
self._prompt_handler.agent.last_event
|
213
|
+
if hasattr(self._prompt_handler.agent, "last_event")
|
214
|
+
else None
|
215
|
+
)
|
216
|
+
start_time = time.time()
|
217
|
+
self._prompt_handler.run_prompt(cmd_input)
|
218
|
+
end_time = time.time()
|
219
|
+
elapsed = end_time - start_time
|
220
|
+
self.msg_count += 1
|
221
|
+
# After prompt, print the stat line using the shared core function
|
222
|
+
from janito.formatting_token import print_token_message_summary
|
223
|
+
|
224
|
+
usage = self.performance_collector.get_last_request_usage()
|
225
|
+
print_token_message_summary(self.console, self.msg_count, usage, elapsed=elapsed)
|
226
|
+
# Print exit reason if present in the final event
|
227
|
+
if final_event and hasattr(final_event, "metadata"):
|
228
|
+
exit_reason = (
|
229
|
+
final_event.metadata.get("exit_reason")
|
230
|
+
if hasattr(final_event, "metadata")
|
210
231
|
else None
|
211
232
|
)
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
from janito.formatting_token import print_token_message_summary
|
216
|
-
|
217
|
-
usage = self.performance_collector.get_last_request_usage()
|
218
|
-
print_token_message_summary(self.console, self.msg_count, usage)
|
219
|
-
# Print exit reason if present in the final event
|
220
|
-
if final_event and hasattr(final_event, "metadata"):
|
221
|
-
exit_reason = (
|
222
|
-
final_event.metadata.get("exit_reason")
|
223
|
-
if hasattr(final_event, "metadata")
|
224
|
-
else None
|
233
|
+
if exit_reason:
|
234
|
+
self.console.print(
|
235
|
+
f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
|
225
236
|
)
|
226
|
-
if exit_reason:
|
227
|
-
self.console.print(
|
228
|
-
f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
|
229
|
-
)
|
230
|
-
|
231
|
-
except Exception as exc:
|
232
|
-
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
233
|
-
import traceback
|
234
237
|
|
235
|
-
|
238
|
+
except Exception as exc:
|
239
|
+
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
240
|
+
import traceback
|
241
|
+
self.console.print(traceback.format_exc())
|
236
242
|
|
237
243
|
def _create_prompt_session(self):
|
238
244
|
return PromptSession(
|
@@ -0,0 +1,80 @@
|
|
1
|
+
"""
|
2
|
+
Profile selection logic for Janito Chat CLI using questionary.
|
3
|
+
"""
|
4
|
+
import questionary
|
5
|
+
from questionary import Style
|
6
|
+
|
7
|
+
def select_profile():
|
8
|
+
choices = [
|
9
|
+
"helpful assistant",
|
10
|
+
"developer",
|
11
|
+
"using role...",
|
12
|
+
"full custom system prompt..."
|
13
|
+
]
|
14
|
+
custom_style = Style([
|
15
|
+
("highlighted", "bg:#00aaff #ffffff"), # background for item under cursor
|
16
|
+
("question", "fg:#00aaff bold"),
|
17
|
+
])
|
18
|
+
answer = questionary.select(
|
19
|
+
"Select a profile to use:",
|
20
|
+
choices=choices,
|
21
|
+
default=None,
|
22
|
+
style=custom_style
|
23
|
+
).ask()
|
24
|
+
if answer == "helpful assistant":
|
25
|
+
return {"profile": "assistant", "profile_system_prompt": None}
|
26
|
+
if answer == "using role...":
|
27
|
+
role_name = questionary.text("Enter the role name:").ask()
|
28
|
+
return f"role:{role_name}"
|
29
|
+
elif answer == "full custom system prompt...":
|
30
|
+
from prompt_toolkit import PromptSession
|
31
|
+
from prompt_toolkit.key_binding import KeyBindings
|
32
|
+
from prompt_toolkit.enums import EditingMode
|
33
|
+
from prompt_toolkit.formatted_text import HTML
|
34
|
+
from .prompt_style import chat_shell_style
|
35
|
+
|
36
|
+
mode = {"multiline": False}
|
37
|
+
bindings = KeyBindings()
|
38
|
+
|
39
|
+
@bindings.add("c-r")
|
40
|
+
def _(event):
|
41
|
+
pass
|
42
|
+
|
43
|
+
@bindings.add("f12")
|
44
|
+
def _(event):
|
45
|
+
buf = event.app.current_buffer
|
46
|
+
buf.text = "Do It"
|
47
|
+
buf.validate_and_handle()
|
48
|
+
|
49
|
+
def get_toolbar():
|
50
|
+
if mode["multiline"]:
|
51
|
+
return HTML("<b>Multiline mode (Esc+Enter to submit). Type /single to switch.</b>")
|
52
|
+
else:
|
53
|
+
return HTML("<b>Single-line mode (Enter to submit). Type /multi for multiline.</b>")
|
54
|
+
|
55
|
+
session = PromptSession(
|
56
|
+
multiline=False,
|
57
|
+
key_bindings=bindings,
|
58
|
+
editing_mode=EditingMode.EMACS,
|
59
|
+
bottom_toolbar=get_toolbar,
|
60
|
+
style=chat_shell_style,
|
61
|
+
)
|
62
|
+
prompt_icon = HTML("<inputline>📝 </inputline>")
|
63
|
+
while True:
|
64
|
+
response = session.prompt(prompt_icon)
|
65
|
+
if not mode["multiline"] and response.strip() == "/multi":
|
66
|
+
mode["multiline"] = True
|
67
|
+
session.multiline = True
|
68
|
+
continue
|
69
|
+
elif mode["multiline"] and response.strip() == "/single":
|
70
|
+
mode["multiline"] = False
|
71
|
+
session.multiline = False
|
72
|
+
continue
|
73
|
+
else:
|
74
|
+
sanitized = response.strip()
|
75
|
+
try:
|
76
|
+
sanitized.encode("utf-8")
|
77
|
+
except UnicodeEncodeError:
|
78
|
+
sanitized = sanitized.encode("utf-8", errors="replace").decode("utf-8")
|
79
|
+
return {"profile": None, "profile_system_prompt": sanitized}
|
80
|
+
return answer
|
@@ -1,21 +1,30 @@
|
|
1
1
|
from .base import ShellCmdHandler
|
2
|
-
from .edit import EditShellHandler
|
3
2
|
from .history_view import ViewShellHandler
|
4
3
|
from .lang import LangShellHandler
|
5
4
|
from .livelogs import LivelogsShellHandler
|
6
|
-
from .prompt import PromptShellHandler, RoleShellHandler
|
5
|
+
from .prompt import PromptShellHandler, RoleShellHandler
|
7
6
|
from .multi import MultiShellHandler
|
7
|
+
from .model import ModelShellHandler
|
8
8
|
from .role import RoleCommandShellHandler
|
9
9
|
from .session import HistoryShellHandler
|
10
|
-
from .termweb_log import TermwebLogTailShellHandler
|
11
10
|
from .tools import ToolsShellHandler
|
12
11
|
from .help import HelpShellHandler
|
13
12
|
from janito.cli.console import shared_console
|
14
13
|
|
15
14
|
COMMAND_HANDLERS = {
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
# Bang handler for shell commands
|
16
|
+
"!": __import__(
|
17
|
+
"janito.cli.chat_mode.shell.commands.bang", fromlist=["BangShellHandler"]
|
18
|
+
).BangShellHandler,
|
19
|
+
"/execute": __import__(
|
20
|
+
"janito.cli.chat_mode.shell.commands.execute", fromlist=["ExecuteShellHandler"]
|
21
|
+
).ExecuteShellHandler,
|
22
|
+
"/read": __import__(
|
23
|
+
"janito.cli.chat_mode.shell.commands.read", fromlist=["ReadShellHandler"]
|
24
|
+
).ReadShellHandler,
|
25
|
+
"/write": __import__(
|
26
|
+
"janito.cli.chat_mode.shell.commands.write", fromlist=["WriteShellHandler"]
|
27
|
+
).WriteShellHandler,
|
19
28
|
"/clear": __import__(
|
20
29
|
"janito.cli.chat_mode.shell.commands.clear", fromlist=["ClearShellHandler"]
|
21
30
|
).ClearShellHandler,
|
@@ -23,16 +32,17 @@ COMMAND_HANDLERS = {
|
|
23
32
|
"janito.cli.chat_mode.shell.commands.conversation_restart",
|
24
33
|
fromlist=["RestartShellHandler"],
|
25
34
|
).RestartShellHandler,
|
26
|
-
|
35
|
+
|
27
36
|
"/view": ViewShellHandler,
|
28
37
|
"/lang": LangShellHandler,
|
29
38
|
"/livelogs": LivelogsShellHandler,
|
30
39
|
"/prompt": PromptShellHandler,
|
31
40
|
"/role": RoleShellHandler,
|
32
|
-
|
41
|
+
|
33
42
|
"/history": HistoryShellHandler,
|
34
|
-
|
43
|
+
|
35
44
|
"/tools": ToolsShellHandler,
|
45
|
+
"/model": ModelShellHandler,
|
36
46
|
"/multi": MultiShellHandler,
|
37
47
|
"/help": HelpShellHandler,
|
38
48
|
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from janito.cli.console import shared_console
|
2
|
+
from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
|
3
|
+
from janito.platform_discovery import PlatformDiscovery
|
4
|
+
import subprocess
|
5
|
+
import sys
|
6
|
+
|
7
|
+
class BangShellHandler(ShellCmdHandler):
|
8
|
+
help_text = "!<cmd>: Run a shell command in the underlying shell (PowerShell or Bash). Usage: !ls -al or !Get-Process. Use ! with no command to launch an interactive shell."
|
9
|
+
|
10
|
+
def run(self):
|
11
|
+
if not self.shell_state:
|
12
|
+
shared_console.print("[red]Shell state unavailable.[/red]")
|
13
|
+
return
|
14
|
+
cmd = (self.after_cmd_line or "").strip()
|
15
|
+
if not cmd:
|
16
|
+
pd = PlatformDiscovery()
|
17
|
+
if pd.is_windows():
|
18
|
+
shared_console.print("[yellow]Launching interactive PowerShell. Type 'exit' to return.[/yellow]")
|
19
|
+
subprocess.run(["powershell.exe"], check=False)
|
20
|
+
else:
|
21
|
+
shared_console.print("[yellow]Launching interactive Bash shell. Type 'exit' to return.[/yellow]")
|
22
|
+
subprocess.run(["bash"], check=False)
|
23
|
+
return
|
24
|
+
pd = PlatformDiscovery()
|
25
|
+
if pd.is_windows():
|
26
|
+
shared_console.print(f"[cyan]Running in PowerShell:[/cyan] {cmd}")
|
27
|
+
completed = subprocess.run(["powershell.exe", "-Command", cmd], capture_output=True, text=True)
|
28
|
+
else:
|
29
|
+
shared_console.print(f"[cyan]Running in Bash:[/cyan] {cmd}")
|
30
|
+
completed = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
31
|
+
output = completed.stdout
|
32
|
+
error = completed.stderr
|
33
|
+
if output:
|
34
|
+
shared_console.print(output)
|
35
|
+
if error:
|
36
|
+
shared_console.print(f"[red]{error}[/red]")
|
@@ -5,31 +5,8 @@ from janito.cli.console import shared_console
|
|
5
5
|
|
6
6
|
|
7
7
|
def handle_restart(shell_state=None):
|
8
|
-
from janito.cli.chat_mode.shell.session.manager import (
|
9
|
-
load_last_conversation,
|
10
|
-
save_conversation,
|
11
|
-
)
|
12
|
-
|
13
8
|
reset_session_id()
|
14
|
-
|
15
|
-
|
16
|
-
# --- Append end-of-conversation message to old history if it exists and is non-trivial ---
|
17
|
-
if os.path.exists(save_path):
|
18
|
-
try:
|
19
|
-
messages, prompts, usage = load_last_conversation(save_path)
|
20
|
-
if messages and (
|
21
|
-
len(messages) > 1
|
22
|
-
or (len(messages) == 1 and messages[0].get("role") != "system")
|
23
|
-
):
|
24
|
-
messages.append(
|
25
|
-
{"role": "system", "content": "[Session ended by user]"}
|
26
|
-
)
|
27
|
-
# Save to permanent chat history (let save_conversation pick session file)
|
28
|
-
save_conversation(messages, prompts, usage)
|
29
|
-
except Exception as e:
|
30
|
-
shared_console.print(
|
31
|
-
f"[bold red]Failed to update previous conversation history:[/bold red] {e}"
|
32
|
-
)
|
9
|
+
# Conversation history is no longer saved or loaded.
|
33
10
|
|
34
11
|
# Clear the terminal screen
|
35
12
|
shared_console.clear()
|
@@ -37,6 +14,12 @@ def handle_restart(shell_state=None):
|
|
37
14
|
# Reset conversation history using the agent's method
|
38
15
|
if hasattr(shell_state, "agent") and shell_state.agent:
|
39
16
|
shell_state.agent.reset_conversation_history()
|
17
|
+
# Reset system prompt to original template context if available
|
18
|
+
if hasattr(shell_state.agent, "_original_template_vars"):
|
19
|
+
shell_state.agent._template_vars = shell_state.agent._original_template_vars.copy()
|
20
|
+
if hasattr(shell_state.agent, "_refresh_system_prompt_from_template"):
|
21
|
+
shell_state.agent._refresh_system_prompt_from_template()
|
22
|
+
# No need to print the system prompt after restart
|
40
23
|
|
41
24
|
# Reset tool use tracker
|
42
25
|
try:
|
@@ -63,6 +46,30 @@ def handle_restart(shell_state=None):
|
|
63
46
|
f"[bold yellow]Warning: Failed to reset PerformanceCollector token info:[/bold yellow] {e}"
|
64
47
|
)
|
65
48
|
|
49
|
+
# Restore tool permissions to the CLI default on restart
|
50
|
+
try:
|
51
|
+
from janito.tools.permissions import set_global_allowed_permissions, get_default_allowed_permissions
|
52
|
+
import janito.tools
|
53
|
+
default_perms = get_default_allowed_permissions()
|
54
|
+
if default_perms is not None:
|
55
|
+
set_global_allowed_permissions(default_perms)
|
56
|
+
janito.tools.local_tools_adapter.set_allowed_permissions(default_perms)
|
57
|
+
msg = None
|
58
|
+
|
59
|
+
else:
|
60
|
+
from janito.tools.tool_base import ToolPermissions
|
61
|
+
set_global_allowed_permissions(ToolPermissions(read=False, write=False, execute=False))
|
62
|
+
janito.tools.local_tools_adapter.set_allowed_permissions(ToolPermissions(read=False, write=False, execute=False))
|
63
|
+
msg = "[green]All tool permissions have been set to OFF (read, write, execute = False).[/green]"
|
64
|
+
# Refresh system prompt to reflect new permissions
|
65
|
+
if hasattr(shell_state, "agent") and shell_state.agent and hasattr(shell_state.agent, "_refresh_system_prompt_from_template"):
|
66
|
+
shell_state.agent._refresh_system_prompt_from_template()
|
67
|
+
if msg:
|
68
|
+
shared_console.print(msg)
|
69
|
+
|
70
|
+
except Exception as e:
|
71
|
+
shared_console.print(f"[yellow]Warning: Failed to restore tool permissions: {e}[/yellow]")
|
72
|
+
|
66
73
|
shared_console.print(
|
67
74
|
"[bold green]Conversation history has been started (context reset).[/bold green]"
|
68
75
|
)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from janito.cli.console import shared_console
|
2
|
+
from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
|
3
|
+
|
4
|
+
class ExecuteShellHandler(ShellCmdHandler):
|
5
|
+
help_text = "/execute on|off: Enable or disable code and command execution tools. Usage: /execute on or /execute off."
|
6
|
+
|
7
|
+
def run(self):
|
8
|
+
if not self.shell_state:
|
9
|
+
shared_console.print("[red]Shell state unavailable.[/red]")
|
10
|
+
return
|
11
|
+
arg = (self.after_cmd_line or "").strip().lower()
|
12
|
+
if arg not in ("on", "off"):
|
13
|
+
shared_console.print("[yellow]Usage: /execute on|off[/yellow]")
|
14
|
+
return
|
15
|
+
enable = arg == "on"
|
16
|
+
# Dynamically enable/disable execution tools in the registry
|
17
|
+
try:
|
18
|
+
from janito.tools.permissions import set_global_allowed_permissions, get_global_allowed_permissions
|
19
|
+
from janito.tools.tool_base import ToolPermissions
|
20
|
+
current_perms = get_global_allowed_permissions()
|
21
|
+
new_perms = ToolPermissions(
|
22
|
+
read=getattr(current_perms, 'read', False),
|
23
|
+
write=getattr(current_perms, 'write', False),
|
24
|
+
execute=enable
|
25
|
+
)
|
26
|
+
set_global_allowed_permissions(new_perms)
|
27
|
+
# Also update the singleton tools registry permissions
|
28
|
+
import janito.tools
|
29
|
+
janito.tools.local_tools_adapter.set_allowed_permissions(new_perms)
|
30
|
+
|
31
|
+
except Exception as e:
|
32
|
+
shared_console.print(f"[yellow]Warning: Could not update execution tools dynamically: {e}[/yellow]")
|
33
|
+
# Refresh system prompt if agent is available
|
34
|
+
agent = getattr(self.shell_state, "agent", None)
|
35
|
+
if agent:
|
36
|
+
if hasattr(agent, "_refresh_system_prompt_from_template"):
|
37
|
+
agent._refresh_system_prompt_from_template()
|
38
|
+
# No need to print the system prompt after permission change
|
39
|
+
if enable:
|
40
|
+
shared_console.print("[green]Execution tools ENABLED. Tools can now execute code and commands.[/green]")
|
41
|
+
else:
|
42
|
+
shared_console.print("[yellow]Execution tools DISABLED. Tools cannot run code or commands.[/yellow]")
|
@@ -1,16 +1,19 @@
|
|
1
1
|
from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
|
2
2
|
from janito.cli.console import shared_console
|
3
|
-
|
3
|
+
import os
|
4
4
|
|
5
5
|
class HelpShellHandler(ShellCmdHandler):
|
6
6
|
help_text = "Show this help message"
|
7
7
|
|
8
8
|
def run(self):
|
9
|
-
from . import
|
10
|
-
|
11
|
-
) # Import moved inside method to avoid circular import
|
9
|
+
from . import COMMAND_HANDLERS
|
10
|
+
from ._priv_check import user_has_any_privileges
|
12
11
|
|
13
12
|
shared_console.print("[bold magenta]Available commands:[/bold magenta]")
|
14
13
|
for cmd, handler_cls in sorted(COMMAND_HANDLERS.items()):
|
15
14
|
help_text = getattr(handler_cls, "help_text", "")
|
16
15
|
shared_console.print(f"[cyan]{cmd}[/cyan]: {help_text}")
|
16
|
+
|
17
|
+
# After help, print privilege info if user has no privileges
|
18
|
+
if not user_has_any_privileges():
|
19
|
+
shared_console.print("[yellow]Note: You currently have no privileges enabled. If you need to interact with files or the system, enable permissions using /read on, /write on, or /execute on.[/yellow]")
|