janito 2.6.0__py3-none-any.whl → 2.6.1__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 +7 -6
- janito/__main__.py +5 -4
- janito/_version.py +58 -57
- janito/agent/setup_agent.py +13 -3
- janito/cli/__init__.py +10 -9
- janito/cli/chat_mode/bindings.py +38 -37
- janito/cli/chat_mode/chat_entry.py +23 -22
- janito/cli/chat_mode/prompt_style.py +25 -24
- janito/cli/chat_mode/script_runner.py +154 -153
- janito/cli/chat_mode/session.py +282 -282
- {janito-2.6.0.dist-info → janito-2.6.1.dist-info}/METADATA +14 -9
- {janito-2.6.0.dist-info → janito-2.6.1.dist-info}/RECORD +17 -17
- /janito/agent/templates/profiles/{system_prompt_template_software_developer.txt.j2 → system_prompt_template_software developer.txt.j2} +0 -0
- {janito-2.6.0.dist-info → janito-2.6.1.dist-info}/WHEEL +0 -0
- {janito-2.6.0.dist-info → janito-2.6.1.dist-info}/entry_points.txt +0 -0
- {janito-2.6.0.dist-info → janito-2.6.1.dist-info}/licenses/LICENSE +0 -0
- {janito-2.6.0.dist-info → janito-2.6.1.dist-info}/top_level.txt +0 -0
janito/cli/chat_mode/session.py
CHANGED
@@ -1,282 +1,282 @@
|
|
1
|
-
"""
|
2
|
-
Session management for Janito Chat CLI.
|
3
|
-
Defines ChatSession and ChatShellState classes.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from __future__ import annotations
|
7
|
-
|
8
|
-
import types
|
9
|
-
from rich.console import Console
|
10
|
-
from rich.rule import Rule
|
11
|
-
from prompt_toolkit.history import InMemoryHistory
|
12
|
-
from janito.cli.chat_mode.shell.input_history import UserInputHistory
|
13
|
-
from prompt_toolkit.formatted_text import HTML
|
14
|
-
from prompt_toolkit import PromptSession
|
15
|
-
from janito.cli.chat_mode.toolbar import get_toolbar_func
|
16
|
-
from prompt_toolkit.enums import EditingMode
|
17
|
-
from janito.cli.chat_mode.prompt_style import chat_shell_style
|
18
|
-
from janito.cli.chat_mode.bindings import KeyBindingsFactory
|
19
|
-
from janito.cli.chat_mode.shell.commands import handle_command
|
20
|
-
from janito.cli.chat_mode.shell.autocomplete import ShellCommandCompleter
|
21
|
-
import time
|
22
|
-
|
23
|
-
# Shared prompt/agent factory
|
24
|
-
from janito.cli.prompt_setup import setup_agent_and_prompt_handler
|
25
|
-
|
26
|
-
import time
|
27
|
-
|
28
|
-
class ChatShellState:
|
29
|
-
def __init__(self, mem_history, conversation_history):
|
30
|
-
self.mem_history = mem_history
|
31
|
-
self.conversation_history = conversation_history
|
32
|
-
self.paste_mode = False
|
33
|
-
self._port = None
|
34
|
-
self._pid = None
|
35
|
-
self._stdout_path = None
|
36
|
-
self._stderr_path = None
|
37
|
-
self.livereload_stderr_path = None
|
38
|
-
self._status = "starting" # Tracks the current status (updated by background thread/UI)
|
39
|
-
|
40
|
-
self.last_usage_info = {}
|
41
|
-
self.last_elapsed = None
|
42
|
-
self.main_agent = {}
|
43
|
-
self.mode = None
|
44
|
-
self.agent = None
|
45
|
-
self.main_agent = None
|
46
|
-
self.main_enabled = False
|
47
|
-
|
48
|
-
class ChatSession:
|
49
|
-
def __init__(
|
50
|
-
self,
|
51
|
-
console,
|
52
|
-
provider_instance=None,
|
53
|
-
llm_driver_config=None,
|
54
|
-
role=None,
|
55
|
-
args=None,
|
56
|
-
verbose_tools=False,
|
57
|
-
verbose_agent=False,
|
58
|
-
allowed_permissions=None,
|
59
|
-
):
|
60
|
-
self.console = console
|
61
|
-
self.user_input_history = UserInputHistory()
|
62
|
-
self.input_dicts = self.user_input_history.load()
|
63
|
-
self.mem_history = InMemoryHistory()
|
64
|
-
for item in self.input_dicts:
|
65
|
-
if isinstance(item, dict) and "input" in item:
|
66
|
-
self.mem_history.append_string(item["input"])
|
67
|
-
self.provider_instance = provider_instance
|
68
|
-
self.llm_driver_config = llm_driver_config
|
69
|
-
|
70
|
-
profile, role, profile_system_prompt = self._select_profile_and_role(args, role)
|
71
|
-
conversation_history = self._create_conversation_history()
|
72
|
-
self.agent, self._prompt_handler = self._setup_agent_and_prompt_handler(
|
73
|
-
args, provider_instance, llm_driver_config, role, verbose_tools, verbose_agent, allowed_permissions, profile, profile_system_prompt, conversation_history
|
74
|
-
)
|
75
|
-
self.shell_state = ChatShellState(self.mem_history, conversation_history)
|
76
|
-
self.shell_state.agent = self.agent
|
77
|
-
self._filter_execution_tools()
|
78
|
-
from janito.perf_singleton import performance_collector
|
79
|
-
self.performance_collector = performance_collector
|
80
|
-
self.key_bindings = KeyBindingsFactory.create()
|
81
|
-
self._prompt_handler.agent = self.agent
|
82
|
-
self._prompt_handler.conversation_history = self.shell_state.conversation_history
|
83
|
-
self._support = False
|
84
|
-
self._maybe_enable_web_support(args)
|
85
|
-
|
86
|
-
def _select_profile_and_role(self, args, role):
|
87
|
-
profile = getattr(args, "profile", None) if args is not None else None
|
88
|
-
role_arg = getattr(args, "role", None) if args is not None else None
|
89
|
-
profile_system_prompt = None
|
90
|
-
if profile is None and role_arg is None:
|
91
|
-
try:
|
92
|
-
from janito.cli.chat_mode.session_profile_select import select_profile
|
93
|
-
result = select_profile()
|
94
|
-
if isinstance(result, dict):
|
95
|
-
profile = result.get("profile")
|
96
|
-
profile_system_prompt = result.get("profile_system_prompt")
|
97
|
-
elif isinstance(result, str) and result.startswith("role:"):
|
98
|
-
role = result[len("role:") :].strip()
|
99
|
-
profile = "developer"
|
100
|
-
else:
|
101
|
-
profile = (
|
102
|
-
"developer" if result == "software developer" else result
|
103
|
-
)
|
104
|
-
except ImportError:
|
105
|
-
profile = "helpful assistant"
|
106
|
-
if role_arg is not None:
|
107
|
-
role = role_arg
|
108
|
-
if profile is None:
|
109
|
-
profile = "developer"
|
110
|
-
return profile, role, profile_system_prompt
|
111
|
-
|
112
|
-
def _create_conversation_history(self):
|
113
|
-
from janito.conversation_history import LLMConversationHistory
|
114
|
-
return LLMConversationHistory()
|
115
|
-
|
116
|
-
def _setup_agent_and_prompt_handler(self, args, provider_instance, llm_driver_config, role, verbose_tools, verbose_agent, allowed_permissions, profile, profile_system_prompt, conversation_history):
|
117
|
-
return setup_agent_and_prompt_handler(
|
118
|
-
args=args,
|
119
|
-
provider_instance=provider_instance,
|
120
|
-
llm_driver_config=llm_driver_config,
|
121
|
-
role=role,
|
122
|
-
verbose_tools=verbose_tools,
|
123
|
-
verbose_agent=verbose_agent,
|
124
|
-
allowed_permissions=allowed_permissions,
|
125
|
-
profile=profile,
|
126
|
-
profile_system_prompt=profile_system_prompt,
|
127
|
-
conversation_history=conversation_history,
|
128
|
-
)
|
129
|
-
|
130
|
-
def _filter_execution_tools(self):
|
131
|
-
try:
|
132
|
-
getattr(__import__('janito.tools', fromlist=['get_local_tools_adapter']), 'get_local_tools_adapter')()
|
133
|
-
except Exception as e:
|
134
|
-
self.console.print(f"[yellow]Warning: Could not filter execution tools at startup: {e}[/yellow]")
|
135
|
-
|
136
|
-
def _maybe_enable_web_support(self, args):
|
137
|
-
if args and getattr(args, "web", False):
|
138
|
-
self._support = True
|
139
|
-
self.shell_state._support = self._support
|
140
|
-
from janito.cli._starter import _start_and_watch
|
141
|
-
from janito.cli.config import get__port
|
142
|
-
import threading
|
143
|
-
from rich.console import Console
|
144
|
-
Console().print("[yellow]Starting in background...[/yellow]")
|
145
|
-
self._lock = threading.Lock()
|
146
|
-
_thread = _start_and_watch(
|
147
|
-
self.shell_state, self._lock, get__port()
|
148
|
-
)
|
149
|
-
self._thread = _thread
|
150
|
-
else:
|
151
|
-
self.shell_state._support = False
|
152
|
-
self.shell_state._status = "offline"
|
153
|
-
|
154
|
-
def run(self):
|
155
|
-
self.console.clear()
|
156
|
-
from janito import __version__
|
157
|
-
self.console.print(
|
158
|
-
f"[bold green]Janito Chat Mode v{__version__}[/bold green]"
|
159
|
-
)
|
160
|
-
self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
|
161
|
-
import os
|
162
|
-
cwd = os.getcwd()
|
163
|
-
home = os.path.expanduser('~')
|
164
|
-
if cwd.startswith(home):
|
165
|
-
cwd_display = '~' + cwd[len(home):]
|
166
|
-
else:
|
167
|
-
cwd_display = cwd
|
168
|
-
self.console.print(f"[green]Working Dir:[/green] {cwd_display}")
|
169
|
-
|
170
|
-
from janito.cli.chat_mode.shell.commands._priv_check import user_has_any_privileges
|
171
|
-
if not user_has_any_privileges():
|
172
|
-
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]")
|
173
|
-
|
174
|
-
session = self._create_prompt_session()
|
175
|
-
self._chat_loop(session)
|
176
|
-
|
177
|
-
def _chat_loop(self, session):
|
178
|
-
self.msg_count = 0
|
179
|
-
timer_started = False
|
180
|
-
while True:
|
181
|
-
if not timer_started:
|
182
|
-
timer_started = True
|
183
|
-
cmd_input = self._handle_input(session)
|
184
|
-
if cmd_input is None:
|
185
|
-
break
|
186
|
-
if not cmd_input:
|
187
|
-
continue
|
188
|
-
if self._handle_exit_conditions(cmd_input):
|
189
|
-
break
|
190
|
-
if self._handle_command_input(cmd_input):
|
191
|
-
continue
|
192
|
-
self.user_input_history.append(cmd_input)
|
193
|
-
self._process_prompt(cmd_input)
|
194
|
-
|
195
|
-
def _handle_command_input(self, cmd_input):
|
196
|
-
if cmd_input.startswith("/"):
|
197
|
-
handle_command(cmd_input, shell_state=self.shell_state)
|
198
|
-
return True
|
199
|
-
if cmd_input.startswith("!"):
|
200
|
-
handle_command(f"! {cmd_input[1:]}", shell_state=self.shell_state)
|
201
|
-
return True
|
202
|
-
return False
|
203
|
-
|
204
|
-
def _process_prompt(self, cmd_input):
|
205
|
-
try:
|
206
|
-
import time
|
207
|
-
final_event = (
|
208
|
-
self._prompt_handler.agent.last_event
|
209
|
-
if hasattr(self._prompt_handler.agent, "last_event")
|
210
|
-
else None
|
211
|
-
)
|
212
|
-
start_time = time.time()
|
213
|
-
self._prompt_handler.run_prompt(cmd_input)
|
214
|
-
end_time = time.time()
|
215
|
-
elapsed = end_time - start_time
|
216
|
-
self.msg_count += 1
|
217
|
-
from janito.formatting_token import print_token_message_summary
|
218
|
-
usage = self.performance_collector.get_last_request_usage()
|
219
|
-
print_token_message_summary(self.console, self.msg_count, usage, elapsed=elapsed)
|
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
|
225
|
-
)
|
226
|
-
if exit_reason:
|
227
|
-
self.console.print(
|
228
|
-
f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
|
229
|
-
)
|
230
|
-
except Exception as exc:
|
231
|
-
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
232
|
-
import traceback
|
233
|
-
self.console.print(traceback.format_exc())
|
234
|
-
|
235
|
-
def _create_prompt_session(self):
|
236
|
-
return PromptSession(
|
237
|
-
style=chat_shell_style,
|
238
|
-
completer=ShellCommandCompleter(),
|
239
|
-
history=self.mem_history,
|
240
|
-
editing_mode=EditingMode.EMACS,
|
241
|
-
key_bindings=self.key_bindings,
|
242
|
-
bottom_toolbar=lambda: get_toolbar_func(
|
243
|
-
self.performance_collector, 0, self.shell_state
|
244
|
-
)(),
|
245
|
-
)
|
246
|
-
|
247
|
-
def _handle_input(self, session):
|
248
|
-
injected = getattr(self.shell_state, "injected_input", None)
|
249
|
-
if injected is not None:
|
250
|
-
cmd_input = injected
|
251
|
-
self.shell_state.injected_input = None
|
252
|
-
else:
|
253
|
-
try:
|
254
|
-
cmd_input = session.prompt(HTML("<inputline>💬 </inputline>"))
|
255
|
-
except (KeyboardInterrupt, EOFError):
|
256
|
-
self._handle_exit()
|
257
|
-
return None
|
258
|
-
sanitized = cmd_input.strip()
|
259
|
-
try:
|
260
|
-
sanitized.encode("utf-8")
|
261
|
-
except UnicodeEncodeError:
|
262
|
-
sanitized = sanitized.encode("utf-8", errors="replace").decode("utf-8")
|
263
|
-
self.console.print(
|
264
|
-
"[yellow]Warning: Some characters in your input were not valid UTF-8 and have been replaced.[/yellow]"
|
265
|
-
)
|
266
|
-
return sanitized
|
267
|
-
|
268
|
-
def _handle_exit(self):
|
269
|
-
self.console.print("[bold yellow]Exiting chat. Goodbye![/bold yellow]")
|
270
|
-
if hasattr(self, "agent") and hasattr(self.agent, "join_driver"):
|
271
|
-
if (
|
272
|
-
hasattr(self.agent, "input_queue")
|
273
|
-
and self.agent.input_queue is not None
|
274
|
-
):
|
275
|
-
self.agent.input_queue.put(None)
|
276
|
-
self.agent.join_driver()
|
277
|
-
|
278
|
-
def _handle_exit_conditions(self, cmd_input):
|
279
|
-
if cmd_input.lower() in ("/exit", ":q", ":quit"):
|
280
|
-
self._handle_exit()
|
281
|
-
return True
|
282
|
-
return False
|
1
|
+
"""
|
2
|
+
Session management for Janito Chat CLI.
|
3
|
+
Defines ChatSession and ChatShellState classes.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from __future__ import annotations
|
7
|
+
|
8
|
+
import types
|
9
|
+
from rich.console import Console
|
10
|
+
from rich.rule import Rule
|
11
|
+
from prompt_toolkit.history import InMemoryHistory
|
12
|
+
from janito.cli.chat_mode.shell.input_history import UserInputHistory
|
13
|
+
from prompt_toolkit.formatted_text import HTML
|
14
|
+
from prompt_toolkit import PromptSession
|
15
|
+
from janito.cli.chat_mode.toolbar import get_toolbar_func
|
16
|
+
from prompt_toolkit.enums import EditingMode
|
17
|
+
from janito.cli.chat_mode.prompt_style import chat_shell_style
|
18
|
+
from janito.cli.chat_mode.bindings import KeyBindingsFactory
|
19
|
+
from janito.cli.chat_mode.shell.commands import handle_command
|
20
|
+
from janito.cli.chat_mode.shell.autocomplete import ShellCommandCompleter
|
21
|
+
import time
|
22
|
+
|
23
|
+
# Shared prompt/agent factory
|
24
|
+
from janito.cli.prompt_setup import setup_agent_and_prompt_handler
|
25
|
+
|
26
|
+
import time
|
27
|
+
|
28
|
+
class ChatShellState:
|
29
|
+
def __init__(self, mem_history, conversation_history):
|
30
|
+
self.mem_history = mem_history
|
31
|
+
self.conversation_history = conversation_history
|
32
|
+
self.paste_mode = False
|
33
|
+
self._port = None
|
34
|
+
self._pid = None
|
35
|
+
self._stdout_path = None
|
36
|
+
self._stderr_path = None
|
37
|
+
self.livereload_stderr_path = None
|
38
|
+
self._status = "starting" # Tracks the current status (updated by background thread/UI)
|
39
|
+
|
40
|
+
self.last_usage_info = {}
|
41
|
+
self.last_elapsed = None
|
42
|
+
self.main_agent = {}
|
43
|
+
self.mode = None
|
44
|
+
self.agent = None
|
45
|
+
self.main_agent = None
|
46
|
+
self.main_enabled = False
|
47
|
+
|
48
|
+
class ChatSession:
|
49
|
+
def __init__(
|
50
|
+
self,
|
51
|
+
console,
|
52
|
+
provider_instance=None,
|
53
|
+
llm_driver_config=None,
|
54
|
+
role=None,
|
55
|
+
args=None,
|
56
|
+
verbose_tools=False,
|
57
|
+
verbose_agent=False,
|
58
|
+
allowed_permissions=None,
|
59
|
+
):
|
60
|
+
self.console = console
|
61
|
+
self.user_input_history = UserInputHistory()
|
62
|
+
self.input_dicts = self.user_input_history.load()
|
63
|
+
self.mem_history = InMemoryHistory()
|
64
|
+
for item in self.input_dicts:
|
65
|
+
if isinstance(item, dict) and "input" in item:
|
66
|
+
self.mem_history.append_string(item["input"])
|
67
|
+
self.provider_instance = provider_instance
|
68
|
+
self.llm_driver_config = llm_driver_config
|
69
|
+
|
70
|
+
profile, role, profile_system_prompt = self._select_profile_and_role(args, role)
|
71
|
+
conversation_history = self._create_conversation_history()
|
72
|
+
self.agent, self._prompt_handler = self._setup_agent_and_prompt_handler(
|
73
|
+
args, provider_instance, llm_driver_config, role, verbose_tools, verbose_agent, allowed_permissions, profile, profile_system_prompt, conversation_history
|
74
|
+
)
|
75
|
+
self.shell_state = ChatShellState(self.mem_history, conversation_history)
|
76
|
+
self.shell_state.agent = self.agent
|
77
|
+
self._filter_execution_tools()
|
78
|
+
from janito.perf_singleton import performance_collector
|
79
|
+
self.performance_collector = performance_collector
|
80
|
+
self.key_bindings = KeyBindingsFactory.create()
|
81
|
+
self._prompt_handler.agent = self.agent
|
82
|
+
self._prompt_handler.conversation_history = self.shell_state.conversation_history
|
83
|
+
self._support = False
|
84
|
+
self._maybe_enable_web_support(args)
|
85
|
+
|
86
|
+
def _select_profile_and_role(self, args, role):
|
87
|
+
profile = getattr(args, "profile", None) if args is not None else None
|
88
|
+
role_arg = getattr(args, "role", None) if args is not None else None
|
89
|
+
profile_system_prompt = None
|
90
|
+
if profile is None and role_arg is None:
|
91
|
+
try:
|
92
|
+
from janito.cli.chat_mode.session_profile_select import select_profile
|
93
|
+
result = select_profile()
|
94
|
+
if isinstance(result, dict):
|
95
|
+
profile = result.get("profile")
|
96
|
+
profile_system_prompt = result.get("profile_system_prompt")
|
97
|
+
elif isinstance(result, str) and result.startswith("role:"):
|
98
|
+
role = result[len("role:") :].strip()
|
99
|
+
profile = "developer"
|
100
|
+
else:
|
101
|
+
profile = (
|
102
|
+
"developer" if result == "software developer" else result
|
103
|
+
)
|
104
|
+
except ImportError:
|
105
|
+
profile = "helpful assistant"
|
106
|
+
if role_arg is not None:
|
107
|
+
role = role_arg
|
108
|
+
if profile is None:
|
109
|
+
profile = "developer"
|
110
|
+
return profile, role, profile_system_prompt
|
111
|
+
|
112
|
+
def _create_conversation_history(self):
|
113
|
+
from janito.conversation_history import LLMConversationHistory
|
114
|
+
return LLMConversationHistory()
|
115
|
+
|
116
|
+
def _setup_agent_and_prompt_handler(self, args, provider_instance, llm_driver_config, role, verbose_tools, verbose_agent, allowed_permissions, profile, profile_system_prompt, conversation_history):
|
117
|
+
return setup_agent_and_prompt_handler(
|
118
|
+
args=args,
|
119
|
+
provider_instance=provider_instance,
|
120
|
+
llm_driver_config=llm_driver_config,
|
121
|
+
role=role,
|
122
|
+
verbose_tools=verbose_tools,
|
123
|
+
verbose_agent=verbose_agent,
|
124
|
+
allowed_permissions=allowed_permissions,
|
125
|
+
profile=profile,
|
126
|
+
profile_system_prompt=profile_system_prompt,
|
127
|
+
conversation_history=conversation_history,
|
128
|
+
)
|
129
|
+
|
130
|
+
def _filter_execution_tools(self):
|
131
|
+
try:
|
132
|
+
getattr(__import__('janito.tools', fromlist=['get_local_tools_adapter']), 'get_local_tools_adapter')()
|
133
|
+
except Exception as e:
|
134
|
+
self.console.print(f"[yellow]Warning: Could not filter execution tools at startup: {e}[/yellow]")
|
135
|
+
|
136
|
+
def _maybe_enable_web_support(self, args):
|
137
|
+
if args and getattr(args, "web", False):
|
138
|
+
self._support = True
|
139
|
+
self.shell_state._support = self._support
|
140
|
+
from janito.cli._starter import _start_and_watch
|
141
|
+
from janito.cli.config import get__port
|
142
|
+
import threading
|
143
|
+
from rich.console import Console
|
144
|
+
Console().print("[yellow]Starting in background...[/yellow]")
|
145
|
+
self._lock = threading.Lock()
|
146
|
+
_thread = _start_and_watch(
|
147
|
+
self.shell_state, self._lock, get__port()
|
148
|
+
)
|
149
|
+
self._thread = _thread
|
150
|
+
else:
|
151
|
+
self.shell_state._support = False
|
152
|
+
self.shell_state._status = "offline"
|
153
|
+
|
154
|
+
def run(self):
|
155
|
+
self.console.clear()
|
156
|
+
from janito import __version__
|
157
|
+
self.console.print(
|
158
|
+
f"[bold green]Janito Chat Mode v{__version__}[/bold green]"
|
159
|
+
)
|
160
|
+
self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
|
161
|
+
import os
|
162
|
+
cwd = os.getcwd()
|
163
|
+
home = os.path.expanduser('~')
|
164
|
+
if cwd.startswith(home):
|
165
|
+
cwd_display = '~' + cwd[len(home):]
|
166
|
+
else:
|
167
|
+
cwd_display = cwd
|
168
|
+
self.console.print(f"[green]Working Dir:[/green] {cwd_display}")
|
169
|
+
|
170
|
+
from janito.cli.chat_mode.shell.commands._priv_check import user_has_any_privileges
|
171
|
+
if not user_has_any_privileges():
|
172
|
+
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]")
|
173
|
+
|
174
|
+
session = self._create_prompt_session()
|
175
|
+
self._chat_loop(session)
|
176
|
+
|
177
|
+
def _chat_loop(self, session):
|
178
|
+
self.msg_count = 0
|
179
|
+
timer_started = False
|
180
|
+
while True:
|
181
|
+
if not timer_started:
|
182
|
+
timer_started = True
|
183
|
+
cmd_input = self._handle_input(session)
|
184
|
+
if cmd_input is None:
|
185
|
+
break
|
186
|
+
if not cmd_input:
|
187
|
+
continue
|
188
|
+
if self._handle_exit_conditions(cmd_input):
|
189
|
+
break
|
190
|
+
if self._handle_command_input(cmd_input):
|
191
|
+
continue
|
192
|
+
self.user_input_history.append(cmd_input)
|
193
|
+
self._process_prompt(cmd_input)
|
194
|
+
|
195
|
+
def _handle_command_input(self, cmd_input):
|
196
|
+
if cmd_input.startswith("/"):
|
197
|
+
handle_command(cmd_input, shell_state=self.shell_state)
|
198
|
+
return True
|
199
|
+
if cmd_input.startswith("!"):
|
200
|
+
handle_command(f"! {cmd_input[1:]}", shell_state=self.shell_state)
|
201
|
+
return True
|
202
|
+
return False
|
203
|
+
|
204
|
+
def _process_prompt(self, cmd_input):
|
205
|
+
try:
|
206
|
+
import time
|
207
|
+
final_event = (
|
208
|
+
self._prompt_handler.agent.last_event
|
209
|
+
if hasattr(self._prompt_handler.agent, "last_event")
|
210
|
+
else None
|
211
|
+
)
|
212
|
+
start_time = time.time()
|
213
|
+
self._prompt_handler.run_prompt(cmd_input)
|
214
|
+
end_time = time.time()
|
215
|
+
elapsed = end_time - start_time
|
216
|
+
self.msg_count += 1
|
217
|
+
from janito.formatting_token import print_token_message_summary
|
218
|
+
usage = self.performance_collector.get_last_request_usage()
|
219
|
+
print_token_message_summary(self.console, self.msg_count, usage, elapsed=elapsed)
|
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
|
225
|
+
)
|
226
|
+
if exit_reason:
|
227
|
+
self.console.print(
|
228
|
+
f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
|
229
|
+
)
|
230
|
+
except Exception as exc:
|
231
|
+
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
232
|
+
import traceback
|
233
|
+
self.console.print(traceback.format_exc())
|
234
|
+
|
235
|
+
def _create_prompt_session(self):
|
236
|
+
return PromptSession(
|
237
|
+
style=chat_shell_style,
|
238
|
+
completer=ShellCommandCompleter(),
|
239
|
+
history=self.mem_history,
|
240
|
+
editing_mode=EditingMode.EMACS,
|
241
|
+
key_bindings=self.key_bindings,
|
242
|
+
bottom_toolbar=lambda: get_toolbar_func(
|
243
|
+
self.performance_collector, 0, self.shell_state
|
244
|
+
)(),
|
245
|
+
)
|
246
|
+
|
247
|
+
def _handle_input(self, session):
|
248
|
+
injected = getattr(self.shell_state, "injected_input", None)
|
249
|
+
if injected is not None:
|
250
|
+
cmd_input = injected
|
251
|
+
self.shell_state.injected_input = None
|
252
|
+
else:
|
253
|
+
try:
|
254
|
+
cmd_input = session.prompt(HTML("<inputline>💬 </inputline>"))
|
255
|
+
except (KeyboardInterrupt, EOFError):
|
256
|
+
self._handle_exit()
|
257
|
+
return None
|
258
|
+
sanitized = cmd_input.strip()
|
259
|
+
try:
|
260
|
+
sanitized.encode("utf-8")
|
261
|
+
except UnicodeEncodeError:
|
262
|
+
sanitized = sanitized.encode("utf-8", errors="replace").decode("utf-8")
|
263
|
+
self.console.print(
|
264
|
+
"[yellow]Warning: Some characters in your input were not valid UTF-8 and have been replaced.[/yellow]"
|
265
|
+
)
|
266
|
+
return sanitized
|
267
|
+
|
268
|
+
def _handle_exit(self):
|
269
|
+
self.console.print("[bold yellow]Exiting chat. Goodbye![/bold yellow]")
|
270
|
+
if hasattr(self, "agent") and hasattr(self.agent, "join_driver"):
|
271
|
+
if (
|
272
|
+
hasattr(self.agent, "input_queue")
|
273
|
+
and self.agent.input_queue is not None
|
274
|
+
):
|
275
|
+
self.agent.input_queue.put(None)
|
276
|
+
self.agent.join_driver()
|
277
|
+
|
278
|
+
def _handle_exit_conditions(self, cmd_input):
|
279
|
+
if cmd_input.lower() in ("/exit", ":q", ":quit"):
|
280
|
+
self._handle_exit()
|
281
|
+
return True
|
282
|
+
return False
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: janito
|
3
|
-
Version: 2.6.
|
3
|
+
Version: 2.6.1
|
4
4
|
Summary: A new Python package called janito.
|
5
5
|
Author-email: João Pinto <lamego.pinto@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/janito-dev/janito
|
@@ -66,7 +66,7 @@ pip install git+https://github.com/janito-dev/janito.git
|
|
66
66
|
Janito integrates with external LLM providers (list below), and most of them require a subscription to get an API_KEY.
|
67
67
|
|
68
68
|
> [!NOTE]
|
69
|
-
> Today, on June the 26th 2025, Google has a free tier subscription for its Gemini-2.5-flash
|
69
|
+
> Today, on June the 26th 2025, Google has a free tier subscription for its Gemini-2.5-flash and Gemini-2.5-pro models. Despite the limitation of the models and of the rate limit of the free tier, they can be used for testing janito. The API_KEY for Gemini is available [here](https://aistudio.google.com/app/apikey).
|
70
70
|
|
71
71
|
> [!NOTE]
|
72
72
|
> [Here](https://github.com/cheahjs/free-llm-api-resources/blob/main/README.md) a list of various services that provide free access or credits towards API-based LLM usage. Note that not all of them are supported by Janito, yet.
|
@@ -98,7 +98,7 @@ janito -set provider=PROVIDER
|
|
98
98
|
```
|
99
99
|
|
100
100
|
> [!WARNING]
|
101
|
-
> Currently the supported providers are: `openai`, `google`, `azure_openai`. You can get more details with `janito --list-providers`.
|
101
|
+
> Currently the supported providers are: `openai`, `google`, `anthropic`, `azure_openai`. You can get more details with `janito --list-providers`.
|
102
102
|
|
103
103
|
5. for more advanced setup, continue reading.
|
104
104
|
|
@@ -219,7 +219,6 @@ janito -r -w -x "Run this code: print('Hello, world!')"
|
|
219
219
|
### Core CLI Options
|
220
220
|
| Option | Description |
|
221
221
|
|------------------------|-----------------------------------------------------------------------------|
|
222
|
-
|
223
222
|
| `--version` | Show program version |
|
224
223
|
| `--list-tools` | List all registered tools |
|
225
224
|
| `--list-providers` | List all supported LLM providers |
|
@@ -262,16 +261,20 @@ Once inside the interactive chat mode, you can use these slash commands:
|
|
262
261
|
| Command | Description |
|
263
262
|
|----------------------|----------------------------------------------|
|
264
263
|
| `/tools` | List available tools |
|
265
|
-
| `/-status`
|
266
|
-
| `/-logs`
|
267
|
-
| `/livelogs` | Show live updates from server log file
|
268
|
-
| `/edit <filename>` | Open file in browser-based editor
|
264
|
+
| `/-status` | Show status of server |
|
265
|
+
| `/-logs` | Show last lines of logs |
|
266
|
+
| `/livelogs` | Show live updates from server log file |
|
267
|
+
| `/edit <filename>` | Open file in browser-based editor |
|
268
|
+
| `/write [on\|off]` | Enable or disable write tool permissions |
|
269
|
+
| `/read [on\|off]` | Enable or disable read tool permissions |
|
270
|
+
| `/execute [on\|off]` | Enable or disable execute tool permissions |
|
271
|
+
|
269
272
|
|
270
273
|
#### 📊 Output Control
|
271
274
|
| Command | Description |
|
272
275
|
|---------------------|----------------------------------------------|
|
273
276
|
| `/verbose` | Show current verbose mode status |
|
274
|
-
| `/verbose [on
|
277
|
+
| `/verbose [on\|off]` | Set verbose mode |
|
275
278
|
|
276
279
|
## Extending Janito
|
277
280
|
|
@@ -283,6 +286,7 @@ Janito is built to be extensible. You can add new LLM providers or tools by impl
|
|
283
286
|
- OpenAI over Azure
|
284
287
|
- Google Gemini
|
285
288
|
- DeepSeek
|
289
|
+
- Anthropic
|
286
290
|
|
287
291
|
See [docs/supported-providers-models.md](docs/supported-providers-models.md) for more details.
|
288
292
|
|
@@ -382,6 +386,7 @@ Each LLM provider has its own models, the best way to check what are the availab
|
|
382
386
|
janito -p openai --list-models
|
383
387
|
janito -p google --list-models
|
384
388
|
janito -p azure_openai --list-models
|
389
|
+
janito -p anthropic --list-models
|
385
390
|
janito -p deepseek --list-models
|
386
391
|
```
|
387
392
|
|