janito 2.7.0__py3-none-any.whl → 2.9.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 +0 -1
- janito/__main__.py +0 -1
- janito/_version.py +0 -3
- janito/agent/setup_agent.py +77 -10
- janito/agent/templates/profiles/{system_prompt_template_plain_software_developer.txt.j2 → system_prompt_template_Developer_with_Python_Tools.txt.j2} +5 -1
- janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +3 -12
- janito/cli/__init__.py +0 -1
- janito/cli/chat_mode/bindings.py +1 -1
- janito/cli/chat_mode/chat_entry.py +0 -2
- janito/cli/chat_mode/prompt_style.py +0 -3
- janito/cli/chat_mode/script_runner.py +9 -5
- janito/cli/chat_mode/session.py +100 -37
- janito/cli/chat_mode/session_profile_select.py +61 -52
- janito/cli/chat_mode/shell/commands/__init__.py +1 -5
- janito/cli/chat_mode/shell/commands/_priv_check.py +1 -0
- janito/cli/chat_mode/shell/commands/_priv_status.py +13 -0
- janito/cli/chat_mode/shell/commands/bang.py +10 -3
- janito/cli/chat_mode/shell/commands/conversation_restart.py +24 -7
- janito/cli/chat_mode/shell/commands/execute.py +22 -7
- janito/cli/chat_mode/shell/commands/help.py +4 -1
- janito/cli/chat_mode/shell/commands/model.py +13 -5
- janito/cli/chat_mode/shell/commands/privileges.py +21 -0
- janito/cli/chat_mode/shell/commands/prompt.py +0 -2
- janito/cli/chat_mode/shell/commands/read.py +22 -5
- janito/cli/chat_mode/shell/commands/tools.py +15 -4
- janito/cli/chat_mode/shell/commands/write.py +22 -5
- janito/cli/chat_mode/shell/input_history.py +3 -1
- janito/cli/chat_mode/shell/session/manager.py +0 -2
- janito/cli/chat_mode/toolbar.py +25 -19
- janito/cli/cli_commands/list_config.py +31 -0
- janito/cli/cli_commands/list_models.py +1 -1
- janito/cli/cli_commands/list_profiles.py +79 -0
- janito/cli/cli_commands/list_providers.py +1 -0
- janito/cli/cli_commands/list_tools.py +35 -7
- janito/cli/cli_commands/model_utils.py +5 -3
- janito/cli/cli_commands/show_config.py +16 -11
- janito/cli/cli_commands/show_system_prompt.py +23 -9
- janito/cli/config.py +0 -13
- janito/cli/core/getters.py +16 -1
- janito/cli/core/runner.py +25 -8
- janito/cli/core/setters.py +13 -76
- janito/cli/main_cli.py +60 -27
- janito/cli/prompt_core.py +19 -18
- janito/cli/prompt_setup.py +6 -3
- janito/cli/rich_terminal_reporter.py +19 -5
- janito/cli/single_shot_mode/handler.py +14 -5
- janito/cli/verbose_output.py +5 -1
- janito/config.py +1 -0
- janito/config_manager.py +15 -2
- janito/drivers/azure_openai/driver.py +27 -30
- janito/drivers/openai/driver.py +53 -36
- janito/formatting_token.py +12 -4
- janito/llm/agent.py +15 -6
- janito/llm/driver.py +1 -0
- janito/llm/provider.py +1 -1
- janito/provider_registry.py +31 -70
- janito/providers/__init__.py +1 -0
- janito/providers/anthropic/model_info.py +0 -1
- janito/providers/anthropic/provider.py +9 -14
- janito/providers/azure_openai/provider.py +10 -5
- janito/providers/deepseek/provider.py +5 -4
- janito/providers/google/model_info.py +4 -2
- janito/providers/google/provider.py +11 -5
- janito/providers/groq/__init__.py +1 -0
- janito/providers/groq/model_info.py +45 -0
- janito/providers/groq/provider.py +76 -0
- janito/providers/moonshotai/provider.py +11 -4
- janito/providers/openai/model_info.py +0 -1
- janito/providers/openai/provider.py +6 -7
- janito/tools/__init__.py +2 -0
- janito/tools/adapters/local/__init__.py +2 -1
- janito/tools/adapters/local/adapter.py +21 -4
- janito/tools/adapters/local/ask_user.py +1 -0
- janito/tools/adapters/local/copy_file.py +1 -0
- janito/tools/adapters/local/create_directory.py +1 -0
- janito/tools/adapters/local/create_file.py +1 -0
- janito/tools/adapters/local/delete_text_in_file.py +2 -1
- janito/tools/adapters/local/fetch_url.py +1 -0
- janito/tools/adapters/local/find_files.py +7 -6
- janito/tools/adapters/local/get_file_outline/core.py +1 -0
- janito/tools/adapters/local/get_file_outline/java_outline.py +22 -15
- janito/tools/adapters/local/get_file_outline/search_outline.py +1 -0
- janito/tools/adapters/local/move_file.py +1 -0
- janito/tools/adapters/local/open_html_in_browser.py +15 -5
- janito/tools/adapters/local/open_url.py +1 -0
- janito/tools/adapters/local/python_code_run.py +1 -0
- janito/tools/adapters/local/python_command_run.py +1 -0
- janito/tools/adapters/local/python_file_run.py +1 -0
- janito/tools/adapters/local/read_files.py +19 -4
- janito/tools/adapters/local/remove_directory.py +1 -0
- janito/tools/adapters/local/remove_file.py +1 -0
- janito/tools/adapters/local/replace_text_in_file.py +4 -3
- janito/tools/adapters/local/run_bash_command.py +1 -0
- janito/tools/adapters/local/run_powershell_command.py +1 -0
- janito/tools/adapters/local/search_text/core.py +18 -17
- janito/tools/adapters/local/search_text/match_lines.py +5 -5
- janito/tools/adapters/local/search_text/pattern_utils.py +1 -1
- janito/tools/adapters/local/search_text/traverse_directory.py +7 -7
- janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +8 -1
- janito/tools/disabled_tools.py +68 -0
- janito/tools/path_security.py +18 -11
- janito/tools/permissions.py +6 -0
- janito/tools/permissions_parse.py +4 -3
- janito/tools/tool_base.py +11 -5
- janito/tools/tool_use_tracker.py +1 -4
- janito/tools/tool_utils.py +1 -1
- janito/tools/tools_adapter.py +57 -25
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/METADATA +11 -19
- janito-2.9.0.dist-info/RECORD +205 -0
- janito/cli/chat_mode/shell/commands/livelogs.py +0 -49
- janito/drivers/mistralai/driver.py +0 -41
- janito/providers/mistralai/model_info.py +0 -37
- janito/providers/mistralai/provider.py +0 -72
- janito/providers/provider_static_info.py +0 -21
- janito-2.7.0.dist-info/RECORD +0 -202
- /janito/agent/templates/profiles/{system_prompt_template_assistant.txt.j2 → system_prompt_template_model_conversation_without_tools_or_context.txt.j2} +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/WHEEL +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/entry_points.txt +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/top_level.txt +0 -0
janito/__init__.py
CHANGED
janito/__main__.py
CHANGED
janito/_version.py
CHANGED
janito/agent/setup_agent.py
CHANGED
@@ -17,14 +17,55 @@ from janito.platform_discovery import PlatformDiscovery
|
|
17
17
|
from janito.tools.tool_base import ToolPermissions
|
18
18
|
from janito.tools.permissions import get_global_allowed_permissions
|
19
19
|
|
20
|
+
|
20
21
|
def _load_template_content(profile, templates_dir):
|
21
22
|
"""
|
22
23
|
Loads the template content for the given profile from the specified directory or package resources.
|
23
24
|
If the profile template is not found in the default locations, tries to load from the user profiles directory ~/.janito/profiles.
|
25
|
+
|
26
|
+
Spaces in the profile name are converted to underscores to align with the file-naming convention (e.g. "Developer with Python Tools" ➜ "Developer_with_Python_Tools" (matches: system_prompt_template_Developer_with_Python_Tools.txt.j2)).
|
24
27
|
"""
|
28
|
+
# Sanitize profile for filename resolution (convert whitespace to underscores)
|
29
|
+
sanitized_profile = re.sub(r"\s+", "_", profile.strip()) if profile else profile
|
30
|
+
|
31
|
+
template_filename = f"system_prompt_template_{sanitized_profile}.txt.j2"
|
32
|
+
template_path = templates_dir / template_filename
|
33
|
+
|
34
|
+
# 1) Check local templates directory
|
35
|
+
if template_path.exists():
|
36
|
+
with open(template_path, "r", encoding="utf-8") as file:
|
37
|
+
return file.read(), template_path
|
38
|
+
|
39
|
+
# 2) Try package resources fallback
|
40
|
+
try:
|
41
|
+
with importlib.resources.files("janito.agent.templates.profiles").joinpath(
|
42
|
+
template_filename
|
43
|
+
).open("r", encoding="utf-8") as file:
|
44
|
+
return file.read(), template_path
|
45
|
+
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
46
|
+
pass
|
25
47
|
|
48
|
+
# 3) Finally, look in the user profiles directory (~/.janito/profiles)
|
49
|
+
user_profiles_dir = Path(os.path.expanduser("~/.janito/profiles"))
|
50
|
+
user_template_path = user_profiles_dir / template_filename
|
51
|
+
if user_template_path.exists():
|
52
|
+
with open(user_template_path, "r", encoding="utf-8") as file:
|
53
|
+
return file.read(), user_template_path
|
54
|
+
|
55
|
+
# If nothing matched, raise an informative error
|
56
|
+
raise FileNotFoundError(
|
57
|
+
f"[janito] Could not find profile-specific template '{template_filename}' in {template_path} nor in janito.agent.templates.profiles package nor in user profiles directory {user_template_path}."
|
58
|
+
)
|
59
|
+
# Replace spaces in profile name with underscores for filename resolution
|
60
|
+
sanitized_profile = re.sub(r"\\s+", "_", profile.strip()) if profile else profile
|
61
|
+
"""
|
62
|
+
Loads the template content for the given profile from the specified directory or package resources.
|
63
|
+
If the profile template is not found in the default locations, tries to load from the user profiles directory ~/.janito/profiles.
|
64
|
+
"""
|
26
65
|
|
27
|
-
|
66
|
+
# Sanitize profile name by replacing spaces with underscores to match filename conventions
|
67
|
+
sanitized_profile = re.sub(r"\\s+", "_", profile.strip())
|
68
|
+
template_filename = f"system_prompt_template_{sanitized_profile}.txt.j2"
|
28
69
|
template_path = templates_dir / template_filename
|
29
70
|
if template_path.exists():
|
30
71
|
with open(template_path, "r", encoding="utf-8") as file:
|
@@ -68,7 +109,7 @@ def _prepare_template_context(role, profile, allowed_permissions):
|
|
68
109
|
allowed_permissions = perm_str or None
|
69
110
|
context["allowed_permissions"] = allowed_permissions
|
70
111
|
# Inject platform info if execute permission is present
|
71
|
-
if allowed_permissions and
|
112
|
+
if allowed_permissions and "x" in allowed_permissions:
|
72
113
|
pd = PlatformDiscovery()
|
73
114
|
context["platform"] = pd.get_platform_name()
|
74
115
|
context["python_version"] = pd.get_python_version()
|
@@ -76,7 +117,18 @@ def _prepare_template_context(role, profile, allowed_permissions):
|
|
76
117
|
return context
|
77
118
|
|
78
119
|
|
79
|
-
def _create_agent(
|
120
|
+
def _create_agent(
|
121
|
+
provider_instance,
|
122
|
+
tools_provider,
|
123
|
+
role,
|
124
|
+
system_prompt,
|
125
|
+
input_queue,
|
126
|
+
output_queue,
|
127
|
+
verbose_agent,
|
128
|
+
context,
|
129
|
+
template_path,
|
130
|
+
profile,
|
131
|
+
):
|
80
132
|
"""
|
81
133
|
Creates and returns an LLMAgent instance with the provided parameters.
|
82
134
|
"""
|
@@ -110,12 +162,16 @@ def setup_agent(
|
|
110
162
|
allowed_permissions=None,
|
111
163
|
profile=None,
|
112
164
|
profile_system_prompt=None,
|
165
|
+
no_tools_mode=False,
|
113
166
|
):
|
114
167
|
"""
|
115
168
|
Creates an agent. A system prompt is rendered from a template only when a profile is specified.
|
116
169
|
"""
|
117
|
-
|
118
|
-
|
170
|
+
if no_tools_mode:
|
171
|
+
tools_provider = None
|
172
|
+
else:
|
173
|
+
tools_provider = get_local_tools_adapter()
|
174
|
+
tools_provider.set_verbose_tools(verbose_tools)
|
119
175
|
|
120
176
|
# If zero_mode is enabled or no profile is given we skip the system prompt.
|
121
177
|
if zero_mode or (profile is None and profile_system_prompt is None):
|
@@ -159,17 +215,23 @@ def setup_agent(
|
|
159
215
|
# Debug output if requested
|
160
216
|
debug_flag = False
|
161
217
|
try:
|
162
|
-
debug_flag =
|
218
|
+
debug_flag = hasattr(sys, "argv") and (
|
219
|
+
"--debug" in sys.argv or "--verbose" in sys.argv or "-v" in sys.argv
|
220
|
+
)
|
163
221
|
except Exception:
|
164
222
|
pass
|
165
223
|
if debug_flag:
|
166
|
-
rich_print(
|
167
|
-
|
224
|
+
rich_print(
|
225
|
+
f"[bold magenta][DEBUG][/bold magenta] Rendering system prompt template '[cyan]{template_path.name}[/cyan]' with allowed_permissions: [yellow]{context.get('allowed_permissions')}[/yellow]"
|
226
|
+
)
|
227
|
+
rich_print(
|
228
|
+
f"[bold magenta][DEBUG][/bold magenta] Template context: [green]{context}[/green]"
|
229
|
+
)
|
168
230
|
start_render = time.time()
|
169
231
|
rendered_prompt = template.render(**context)
|
170
232
|
end_render = time.time()
|
171
233
|
# Merge multiple empty lines into a single empty line
|
172
|
-
rendered_prompt = re.sub(r
|
234
|
+
rendered_prompt = re.sub(r"\n{3,}", "\n\n", rendered_prompt)
|
173
235
|
|
174
236
|
return _create_agent(
|
175
237
|
provider_instance,
|
@@ -197,6 +259,7 @@ def create_configured_agent(
|
|
197
259
|
allowed_permissions=None,
|
198
260
|
profile=None,
|
199
261
|
profile_system_prompt=None,
|
262
|
+
no_tools_mode=False,
|
200
263
|
):
|
201
264
|
"""
|
202
265
|
Normalizes agent setup for all CLI modes.
|
@@ -218,6 +281,9 @@ def create_configured_agent(
|
|
218
281
|
driver = None
|
219
282
|
if hasattr(provider_instance, "create_driver"):
|
220
283
|
driver = provider_instance.create_driver()
|
284
|
+
# Ensure no tools are passed to the driver when --no-tools flag is active
|
285
|
+
if no_tools_mode:
|
286
|
+
driver.tools_adapter = None
|
221
287
|
driver.start() # Ensure the driver background thread is started
|
222
288
|
input_queue = getattr(driver, "input_queue", None)
|
223
289
|
output_queue = getattr(driver, "output_queue", None)
|
@@ -235,7 +301,8 @@ def create_configured_agent(
|
|
235
301
|
allowed_permissions=allowed_permissions,
|
236
302
|
profile=profile,
|
237
303
|
profile_system_prompt=profile_system_prompt,
|
304
|
+
no_tools_mode=no_tools_mode,
|
238
305
|
)
|
239
306
|
if driver is not None:
|
240
307
|
agent.driver = driver # Attach driver to agent for thread management
|
241
|
-
return agent
|
308
|
+
return agent
|
@@ -1,9 +1,13 @@
|
|
1
|
-
|
1
|
+
{# General role setup
|
2
|
+
ex. "Search in code" -> Python Developer -> find(*.py) | Java Developer -> find(*.java)
|
3
|
+
#}
|
4
|
+
You are: {{ role }}
|
2
5
|
|
3
6
|
{# Improves tool selection and platform specific constrains, eg, path format, C:\ vs /path #}
|
4
7
|
{% if allowed_permissions and 'x' in allowed_permissions %}
|
5
8
|
You will be using the following environment:
|
6
9
|
Platform: {{ platform }}
|
10
|
+
Python version: {{ python_version }}
|
7
11
|
Shell/Environment: {{ shell_info }}
|
8
12
|
{% endif %}
|
9
13
|
|
@@ -1,21 +1,12 @@
|
|
1
|
-
|
2
|
-
ex. "Search in code" -> Python Developer -> find(*.py) | Java Developer -> find(*.java)
|
3
|
-
#}
|
4
|
-
You are: {{ role }}
|
1
|
+
You are: software developer
|
5
2
|
|
6
3
|
{# Improves tool selection and platform specific constrains, eg, path format, C:\ vs /path #}
|
7
|
-
{% if allowed_permissions and 'x' in allowed_permissions %}
|
8
4
|
You will be using the following environment:
|
9
|
-
Platform:
|
10
|
-
|
11
|
-
Shell/Environment: {{ shell_info }}
|
12
|
-
{% endif %}
|
13
|
-
|
5
|
+
Platform: Windows
|
6
|
+
Shell/Environment: PowerShell
|
14
7
|
|
15
8
|
|
16
|
-
{% if allowed_permissions and 'r' in allowed_permissions %}
|
17
9
|
Before answering map the questions to artifacts found in the current directory - the current project.
|
18
|
-
{% endif %}
|
19
10
|
|
20
11
|
Respond according to the following guidelines:
|
21
12
|
{% if allowed_permissions %}
|
janito/cli/__init__.py
CHANGED
janito/cli/chat_mode/bindings.py
CHANGED
@@ -5,6 +5,7 @@ Key bindings for Janito Chat CLI.
|
|
5
5
|
from prompt_toolkit.key_binding import KeyBindings
|
6
6
|
from janito.tools.permissions import get_global_allowed_permissions
|
7
7
|
|
8
|
+
|
8
9
|
class KeyBindingsFactory:
|
9
10
|
@staticmethod
|
10
11
|
def create():
|
@@ -35,4 +36,3 @@ class KeyBindingsFactory:
|
|
35
36
|
buf.validate_and_handle()
|
36
37
|
|
37
38
|
return bindings
|
38
|
-
|
@@ -15,11 +15,8 @@ chat_shell_style = Style.from_dict(
|
|
15
15
|
"tokens_in": "fg:#00af5f",
|
16
16
|
"tokens_out": "fg:#01814a",
|
17
17
|
"max-tokens": "fg:#888888",
|
18
|
-
|
19
|
-
|
20
18
|
"key-toggle-on": "bg:#ffd700 fg:#232323 bold",
|
21
19
|
"key-toggle-off": "bg:#444444 fg:#ffffff bold",
|
22
20
|
"cmd-label": "bg:#ff9500 fg:#232323 bold",
|
23
21
|
}
|
24
22
|
)
|
25
|
-
|
@@ -23,6 +23,7 @@ Typical usage
|
|
23
23
|
The ``ChatScriptRunner`` purposefully replaces the internal call to the agent
|
24
24
|
with a real agent call by default. If you want to use a stub, you must modify the runner implementation.
|
25
25
|
"""
|
26
|
+
|
26
27
|
from __future__ import annotations
|
27
28
|
|
28
29
|
from types import MethodType
|
@@ -43,7 +44,6 @@ auth_warning = (
|
|
43
44
|
)
|
44
45
|
|
45
46
|
|
46
|
-
|
47
47
|
class ChatScriptRunner:
|
48
48
|
"""Run a **ChatSession** non-interactively using a predefined set of inputs."""
|
49
49
|
|
@@ -81,6 +81,7 @@ class ChatScriptRunner:
|
|
81
81
|
# is incompatible with headless test runs.
|
82
82
|
if "args" not in chat_session_kwargs or chat_session_kwargs["args"] is None:
|
83
83
|
from types import SimpleNamespace
|
84
|
+
|
84
85
|
chat_session_kwargs["args"] = SimpleNamespace(
|
85
86
|
profile="developer",
|
86
87
|
provider=self.provider,
|
@@ -94,6 +95,7 @@ class ChatScriptRunner:
|
|
94
95
|
# 1) Patch *ChatSession._create_prompt_session* to do nothing – the
|
95
96
|
# interactive session object is irrelevant for scripted runs.
|
96
97
|
from types import MethodType as _MT
|
98
|
+
|
97
99
|
if "_original_create_prompt_session" not in ChatSession.__dict__:
|
98
100
|
ChatSession._original_create_prompt_session = ChatSession._create_prompt_session # type: ignore[attr-defined]
|
99
101
|
ChatSession._create_prompt_session = _MT(lambda _self: None, ChatSession) # type: ignore[method-assign]
|
@@ -101,17 +103,20 @@ class ChatScriptRunner:
|
|
101
103
|
# Resolve provider instance now so that ChatSession uses a ready agent
|
102
104
|
provider_instance = ProviderRegistry().get_instance(self.provider)
|
103
105
|
if provider_instance is None:
|
104
|
-
raise RuntimeError(
|
106
|
+
raise RuntimeError(
|
107
|
+
f"Provider '{self.provider}' is not available on this system."
|
108
|
+
)
|
105
109
|
driver_config = LLMDriverConfig(model=self.model)
|
106
110
|
chat_session_kwargs.setdefault("provider_instance", provider_instance)
|
107
111
|
chat_session_kwargs.setdefault("llm_driver_config", driver_config)
|
108
112
|
|
109
113
|
self.chat_session = ChatSession(console=self.console, **chat_session_kwargs)
|
110
114
|
|
111
|
-
|
112
115
|
# Monkey-patch the *ChatSession._handle_input* method so that it pops
|
113
116
|
# from our in-memory queue instead of reading from stdin.
|
114
|
-
def _script_handle_input(
|
117
|
+
def _script_handle_input(
|
118
|
+
this: ChatSession, _prompt_session_unused
|
119
|
+
): # noqa: D401
|
115
120
|
if not self._input_queue:
|
116
121
|
# Signal normal shutdown
|
117
122
|
this._handle_exit()
|
@@ -151,4 +156,3 @@ class ChatScriptRunner:
|
|
151
156
|
|
152
157
|
# Convenience alias so tests can simply call *runner()*
|
153
158
|
__call__ = run
|
154
|
-
|
janito/cli/chat_mode/session.py
CHANGED
@@ -25,17 +25,20 @@ from janito.cli.prompt_setup import setup_agent_and_prompt_handler
|
|
25
25
|
|
26
26
|
import time
|
27
27
|
|
28
|
+
|
28
29
|
class ChatShellState:
|
29
30
|
def __init__(self, mem_history, conversation_history):
|
30
31
|
self.mem_history = mem_history
|
31
32
|
self.conversation_history = conversation_history
|
32
33
|
self.paste_mode = False
|
33
|
-
|
34
|
+
|
34
35
|
self._pid = None
|
35
36
|
self._stdout_path = None
|
36
37
|
self._stderr_path = None
|
37
|
-
|
38
|
-
self._status =
|
38
|
+
|
39
|
+
self._status = (
|
40
|
+
"starting" # Tracks the current status (updated by background thread/UI)
|
41
|
+
)
|
39
42
|
|
40
43
|
self.last_usage_info = {}
|
41
44
|
self.last_elapsed = None
|
@@ -44,6 +47,8 @@ class ChatShellState:
|
|
44
47
|
self.agent = None
|
45
48
|
self.main_agent = None
|
46
49
|
self.main_enabled = False
|
50
|
+
self.no_tools_mode = False
|
51
|
+
|
47
52
|
|
48
53
|
class ChatSession:
|
49
54
|
def __init__(
|
@@ -67,53 +72,92 @@ class ChatSession:
|
|
67
72
|
self.provider_instance = provider_instance
|
68
73
|
self.llm_driver_config = llm_driver_config
|
69
74
|
|
70
|
-
profile, role, profile_system_prompt =
|
75
|
+
profile, role, profile_system_prompt, no_tools_mode = (
|
76
|
+
self._select_profile_and_role(args, role)
|
77
|
+
)
|
78
|
+
# Propagate no_tools_mode flag to downstream components via args
|
79
|
+
if args is not None and not hasattr(args, "no_tools_mode"):
|
80
|
+
try:
|
81
|
+
setattr(args, "no_tools_mode", no_tools_mode)
|
82
|
+
except Exception:
|
83
|
+
pass
|
71
84
|
conversation_history = self._create_conversation_history()
|
72
85
|
self.agent, self._prompt_handler = self._setup_agent_and_prompt_handler(
|
73
|
-
args,
|
86
|
+
args,
|
87
|
+
provider_instance,
|
88
|
+
llm_driver_config,
|
89
|
+
role,
|
90
|
+
verbose_tools,
|
91
|
+
verbose_agent,
|
92
|
+
allowed_permissions,
|
93
|
+
profile,
|
94
|
+
profile_system_prompt,
|
95
|
+
conversation_history,
|
74
96
|
)
|
75
97
|
self.shell_state = ChatShellState(self.mem_history, conversation_history)
|
76
98
|
self.shell_state.agent = self.agent
|
99
|
+
# Set no_tools_mode if present
|
100
|
+
self.shell_state.no_tools_mode = bool(no_tools_mode)
|
77
101
|
self._filter_execution_tools()
|
78
102
|
from janito.perf_singleton import performance_collector
|
103
|
+
|
79
104
|
self.performance_collector = performance_collector
|
80
105
|
self.key_bindings = KeyBindingsFactory.create()
|
81
106
|
self._prompt_handler.agent = self.agent
|
82
|
-
self._prompt_handler.conversation_history =
|
107
|
+
self._prompt_handler.conversation_history = (
|
108
|
+
self.shell_state.conversation_history
|
109
|
+
)
|
83
110
|
self._support = False
|
84
|
-
self._maybe_enable_web_support(args)
|
85
111
|
|
86
112
|
def _select_profile_and_role(self, args, role):
|
87
113
|
profile = getattr(args, "profile", None) if args is not None else None
|
88
114
|
role_arg = getattr(args, "role", None) if args is not None else None
|
89
115
|
profile_system_prompt = None
|
116
|
+
no_tools_mode = False
|
90
117
|
if profile is None and role_arg is None:
|
91
118
|
try:
|
92
119
|
from janito.cli.chat_mode.session_profile_select import select_profile
|
120
|
+
|
93
121
|
result = select_profile()
|
94
122
|
if isinstance(result, dict):
|
95
123
|
profile = result.get("profile")
|
96
124
|
profile_system_prompt = result.get("profile_system_prompt")
|
125
|
+
no_tools_mode = result.get("no_tools_mode", False)
|
97
126
|
elif isinstance(result, str) and result.startswith("role:"):
|
98
127
|
role = result[len("role:") :].strip()
|
99
|
-
profile = "
|
128
|
+
profile = "Developer with Python Tools"
|
100
129
|
else:
|
101
130
|
profile = (
|
102
|
-
"
|
131
|
+
"Developer with Python Tools"
|
132
|
+
if result == "Developer"
|
133
|
+
else result
|
103
134
|
)
|
104
135
|
except ImportError:
|
105
|
-
profile = "
|
136
|
+
profile = "Raw Model Session (no tools, no context)"
|
106
137
|
if role_arg is not None:
|
107
138
|
role = role_arg
|
108
139
|
if profile is None:
|
109
|
-
profile = "
|
110
|
-
return profile, role, profile_system_prompt
|
140
|
+
profile = "Developer with Python Tools"
|
141
|
+
return profile, role, profile_system_prompt, no_tools_mode
|
111
142
|
|
112
143
|
def _create_conversation_history(self):
|
113
144
|
from janito.conversation_history import LLMConversationHistory
|
145
|
+
|
114
146
|
return LLMConversationHistory()
|
115
147
|
|
116
|
-
def _setup_agent_and_prompt_handler(
|
148
|
+
def _setup_agent_and_prompt_handler(
|
149
|
+
self,
|
150
|
+
args,
|
151
|
+
provider_instance,
|
152
|
+
llm_driver_config,
|
153
|
+
role,
|
154
|
+
verbose_tools,
|
155
|
+
verbose_agent,
|
156
|
+
allowed_permissions,
|
157
|
+
profile,
|
158
|
+
profile_system_prompt,
|
159
|
+
conversation_history,
|
160
|
+
):
|
117
161
|
return setup_agent_and_prompt_handler(
|
118
162
|
args=args,
|
119
163
|
provider_instance=provider_instance,
|
@@ -129,23 +173,16 @@ class ChatSession:
|
|
129
173
|
|
130
174
|
def _filter_execution_tools(self):
|
131
175
|
try:
|
132
|
-
getattr(
|
176
|
+
getattr(
|
177
|
+
__import__("janito.tools", fromlist=["get_local_tools_adapter"]),
|
178
|
+
"get_local_tools_adapter",
|
179
|
+
)()
|
133
180
|
except Exception as e:
|
134
|
-
self.console.print(
|
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()
|
181
|
+
self.console.print(
|
182
|
+
f"[yellow]Warning: Could not filter execution tools at startup: {e}[/yellow]"
|
148
183
|
)
|
184
|
+
|
185
|
+
_thread = _start_and_watch(self.shell_state, self._lock, get__port())
|
149
186
|
self._thread = _thread
|
150
187
|
else:
|
151
188
|
self.shell_state._support = False
|
@@ -154,22 +191,43 @@ class ChatSession:
|
|
154
191
|
def run(self):
|
155
192
|
self.console.clear()
|
156
193
|
from janito import __version__
|
194
|
+
|
195
|
+
self.console.print(f"[bold green]Janito Chat Mode v{__version__}[/bold green]")
|
157
196
|
self.console.print(
|
158
|
-
|
197
|
+
"[green]/help for commands /exit or Ctrl+C to quit[/green]"
|
159
198
|
)
|
160
|
-
self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
|
161
199
|
import os
|
200
|
+
|
162
201
|
cwd = os.getcwd()
|
163
|
-
home = os.path.expanduser(
|
202
|
+
home = os.path.expanduser("~")
|
164
203
|
if cwd.startswith(home):
|
165
|
-
cwd_display =
|
204
|
+
cwd_display = "~" + cwd[len(home) :]
|
166
205
|
else:
|
167
206
|
cwd_display = cwd
|
168
|
-
|
207
|
+
from janito.cli.chat_mode.shell.commands._priv_status import (
|
208
|
+
get_privilege_status_message,
|
209
|
+
)
|
210
|
+
|
211
|
+
priv_status = get_privilege_status_message()
|
212
|
+
self.console.print(
|
213
|
+
f"[green]Working Dir:[/green] {cwd_display} | {priv_status}"
|
214
|
+
)
|
169
215
|
|
170
|
-
from janito.cli.chat_mode.shell.commands._priv_check import
|
171
|
-
|
172
|
-
|
216
|
+
from janito.cli.chat_mode.shell.commands._priv_check import (
|
217
|
+
user_has_any_privileges,
|
218
|
+
)
|
219
|
+
|
220
|
+
perms = __import__(
|
221
|
+
"janito.tools.permissions", fromlist=["get_global_allowed_permissions"]
|
222
|
+
).get_global_allowed_permissions()
|
223
|
+
if perms.execute:
|
224
|
+
self.console.print(
|
225
|
+
"[bold red]Commands/Code execution is enabled - Be cautious[/bold red]"
|
226
|
+
)
|
227
|
+
if not (perms.read or perms.write or perms.execute):
|
228
|
+
self.console.print(
|
229
|
+
"[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]"
|
230
|
+
)
|
173
231
|
|
174
232
|
session = self._create_prompt_session()
|
175
233
|
self._chat_loop(session)
|
@@ -204,6 +262,7 @@ class ChatSession:
|
|
204
262
|
def _process_prompt(self, cmd_input):
|
205
263
|
try:
|
206
264
|
import time
|
265
|
+
|
207
266
|
final_event = (
|
208
267
|
self._prompt_handler.agent.last_event
|
209
268
|
if hasattr(self._prompt_handler.agent, "last_event")
|
@@ -215,8 +274,11 @@ class ChatSession:
|
|
215
274
|
elapsed = end_time - start_time
|
216
275
|
self.msg_count += 1
|
217
276
|
from janito.formatting_token import print_token_message_summary
|
277
|
+
|
218
278
|
usage = self.performance_collector.get_last_request_usage()
|
219
|
-
print_token_message_summary(
|
279
|
+
print_token_message_summary(
|
280
|
+
self.console, self.msg_count, usage, elapsed=elapsed
|
281
|
+
)
|
220
282
|
if final_event and hasattr(final_event, "metadata"):
|
221
283
|
exit_reason = (
|
222
284
|
final_event.metadata.get("exit_reason")
|
@@ -230,6 +292,7 @@ class ChatSession:
|
|
230
292
|
except Exception as exc:
|
231
293
|
self.console.print(f"[red]Exception in agent: {exc}[/red]")
|
232
294
|
import traceback
|
295
|
+
|
233
296
|
self.console.print(traceback.format_exc())
|
234
297
|
|
235
298
|
def _create_prompt_session(self):
|