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
@@ -1,95 +1,95 @@
|
|
1
|
-
"""
|
2
|
-
Utilities for model-related CLI output
|
3
|
-
"""
|
4
|
-
|
5
|
-
|
6
|
-
def _print_models_table(models, provider_name):
|
7
|
-
from rich.table import Table
|
8
|
-
from rich.console import Console
|
9
|
-
|
10
|
-
headers = [
|
11
|
-
"name",
|
12
|
-
"open",
|
13
|
-
"context",
|
14
|
-
"max_input",
|
15
|
-
"max_cot",
|
16
|
-
"max_response",
|
17
|
-
"thinking_supported",
|
18
|
-
"driver",
|
19
|
-
]
|
20
|
-
display_headers = [
|
21
|
-
"Model Name",
|
22
|
-
"Vendor",
|
23
|
-
"context",
|
24
|
-
"max_input",
|
25
|
-
"max_cot",
|
26
|
-
"max_response",
|
27
|
-
"Thinking",
|
28
|
-
"Driver",
|
29
|
-
]
|
30
|
-
table = Table(title=f"Supported models for provider '{provider_name}'")
|
31
|
-
_add_table_columns(table, display_headers)
|
32
|
-
num_fields = {"context", "max_input", "max_cot", "max_response"}
|
33
|
-
for m in models:
|
34
|
-
row = [str(m.get("name", ""))]
|
35
|
-
row.extend(_build_model_row(m, headers, num_fields))
|
36
|
-
table.add_row(*row)
|
37
|
-
import sys
|
38
|
-
if sys.stdout.isatty():
|
39
|
-
from rich.console import Console
|
40
|
-
Console().print(table)
|
41
|
-
else:
|
42
|
-
# ASCII-friendly fallback table when output is redirected
|
43
|
-
print(f"Supported models for provider '{provider_name}'")
|
44
|
-
headers_fallback = [h for h in display_headers]
|
45
|
-
print(' | '.join(headers_fallback))
|
46
|
-
for m in models:
|
47
|
-
row = [str(m.get('name', ''))]
|
48
|
-
row.extend(_build_model_row(m, headers, num_fields))
|
49
|
-
print(' | '.join(row))
|
50
|
-
|
51
|
-
|
52
|
-
def _add_table_columns(table, display_headers):
|
53
|
-
for i, h in enumerate(display_headers):
|
54
|
-
justify = "right" if i == 0 else "center"
|
55
|
-
table.add_column(h, style="bold", justify=justify)
|
56
|
-
|
57
|
-
|
58
|
-
def _format_k(val):
|
59
|
-
try:
|
60
|
-
n = int(val)
|
61
|
-
if n >= 1000:
|
62
|
-
return f"{n // 1000}k"
|
63
|
-
return str(n)
|
64
|
-
except Exception:
|
65
|
-
return str(val)
|
66
|
-
|
67
|
-
|
68
|
-
def _build_model_row(m, headers, num_fields):
|
69
|
-
def format_driver(val):
|
70
|
-
if isinstance(val, (list, tuple)):
|
71
|
-
return ", ".join(val)
|
72
|
-
val_str = str(val)
|
73
|
-
return val_str.removesuffix("ModelDriver").strip()
|
74
|
-
|
75
|
-
row = []
|
76
|
-
for h in headers[1:]:
|
77
|
-
v = m.get(h, "")
|
78
|
-
if h in num_fields and v not in ("", "N/A"):
|
79
|
-
if (
|
80
|
-
h in ("context", "max_input")
|
81
|
-
and isinstance(v, (list, tuple))
|
82
|
-
and len(v) == 2
|
83
|
-
):
|
84
|
-
row.append(f"{_format_k(v[0])} / {_format_k(v[1])}")
|
85
|
-
else:
|
86
|
-
row.append(_format_k(v))
|
87
|
-
elif h == "open":
|
88
|
-
row.append("Open" if v is True or v == "Open" else "Locked")
|
89
|
-
elif h == "thinking_supported":
|
90
|
-
row.append("📖" if v is True or v == "True" else "")
|
91
|
-
elif h == "driver":
|
92
|
-
row.append(format_driver(v))
|
93
|
-
else:
|
94
|
-
row.append(str(v))
|
95
|
-
return row
|
1
|
+
"""
|
2
|
+
Utilities for model-related CLI output
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
def _print_models_table(models, provider_name):
|
7
|
+
from rich.table import Table
|
8
|
+
from rich.console import Console
|
9
|
+
|
10
|
+
headers = [
|
11
|
+
"name",
|
12
|
+
"open",
|
13
|
+
"context",
|
14
|
+
"max_input",
|
15
|
+
"max_cot",
|
16
|
+
"max_response",
|
17
|
+
"thinking_supported",
|
18
|
+
"driver",
|
19
|
+
]
|
20
|
+
display_headers = [
|
21
|
+
"Model Name",
|
22
|
+
"Vendor",
|
23
|
+
"context",
|
24
|
+
"max_input",
|
25
|
+
"max_cot",
|
26
|
+
"max_response",
|
27
|
+
"Thinking",
|
28
|
+
"Driver",
|
29
|
+
]
|
30
|
+
table = Table(title=f"Supported models for provider '{provider_name}'")
|
31
|
+
_add_table_columns(table, display_headers)
|
32
|
+
num_fields = {"context", "max_input", "max_cot", "max_response"}
|
33
|
+
for m in models:
|
34
|
+
row = [str(m.get("name", ""))]
|
35
|
+
row.extend(_build_model_row(m, headers, num_fields))
|
36
|
+
table.add_row(*row)
|
37
|
+
import sys
|
38
|
+
if sys.stdout.isatty():
|
39
|
+
from rich.console import Console
|
40
|
+
Console().print(table)
|
41
|
+
else:
|
42
|
+
# ASCII-friendly fallback table when output is redirected
|
43
|
+
print(f"Supported models for provider '{provider_name}'")
|
44
|
+
headers_fallback = [h for h in display_headers]
|
45
|
+
print(' | '.join(headers_fallback))
|
46
|
+
for m in models:
|
47
|
+
row = [str(m.get('name', ''))]
|
48
|
+
row.extend(_build_model_row(m, headers, num_fields))
|
49
|
+
print(' | '.join(row))
|
50
|
+
|
51
|
+
|
52
|
+
def _add_table_columns(table, display_headers):
|
53
|
+
for i, h in enumerate(display_headers):
|
54
|
+
justify = "right" if i == 0 else "center"
|
55
|
+
table.add_column(h, style="bold", justify=justify)
|
56
|
+
|
57
|
+
|
58
|
+
def _format_k(val):
|
59
|
+
try:
|
60
|
+
n = int(val)
|
61
|
+
if n >= 1000:
|
62
|
+
return f"{n // 1000}k"
|
63
|
+
return str(n)
|
64
|
+
except Exception:
|
65
|
+
return str(val)
|
66
|
+
|
67
|
+
|
68
|
+
def _build_model_row(m, headers, num_fields):
|
69
|
+
def format_driver(val):
|
70
|
+
if isinstance(val, (list, tuple)):
|
71
|
+
return ", ".join(val)
|
72
|
+
val_str = str(val)
|
73
|
+
return val_str.removesuffix("ModelDriver").strip()
|
74
|
+
|
75
|
+
row = []
|
76
|
+
for h in headers[1:]:
|
77
|
+
v = m.get(h, "")
|
78
|
+
if h in num_fields and v not in ("", "N/A"):
|
79
|
+
if (
|
80
|
+
h in ("context", "max_input")
|
81
|
+
and isinstance(v, (list, tuple))
|
82
|
+
and len(v) == 2
|
83
|
+
):
|
84
|
+
row.append(f"{_format_k(v[0])} / {_format_k(v[1])}")
|
85
|
+
else:
|
86
|
+
row.append(_format_k(v))
|
87
|
+
elif h == "open":
|
88
|
+
row.append("Open" if v is True or v == "Open" else "Locked")
|
89
|
+
elif h == "thinking_supported":
|
90
|
+
row.append("📖" if v is True or v == "True" else "")
|
91
|
+
elif h == "driver":
|
92
|
+
row.append(format_driver(v))
|
93
|
+
else:
|
94
|
+
row.append(str(v))
|
95
|
+
return row
|
@@ -1,5 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
CLI Command: Show the resolved system prompt for the main agent (single-shot mode)
|
3
|
+
|
4
|
+
Supports --profile to select a profile-specific system prompt template.
|
3
5
|
"""
|
4
6
|
|
5
7
|
from janito.cli.core.runner import prepare_llm_driver_config
|
@@ -23,39 +25,80 @@ def handle_show_system_prompt(args):
|
|
23
25
|
|
24
26
|
# Prepare context for Jinja2 rendering
|
25
27
|
context = {}
|
26
|
-
context["role"] = agent_role or "
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
context["role"] = agent_role or "developer"
|
29
|
+
context["profile"] = getattr(args, "profile", None)
|
30
|
+
# Compute allowed_permissions from CLI args (as in agent setup)
|
31
|
+
from janito.tools.tool_base import ToolPermissions
|
32
|
+
read = getattr(args, "read", False)
|
33
|
+
write = getattr(args, "write", False)
|
34
|
+
execute = getattr(args, "exec", False)
|
35
|
+
allowed = ToolPermissions(read=read, write=write, execute=execute)
|
36
|
+
perm_str = ""
|
37
|
+
if allowed.read:
|
38
|
+
perm_str += "r"
|
39
|
+
if allowed.write:
|
40
|
+
perm_str += "w"
|
41
|
+
if allowed.execute:
|
42
|
+
perm_str += "x"
|
43
|
+
allowed_permissions = perm_str or None
|
44
|
+
context["allowed_permissions"] = allowed_permissions
|
45
|
+
# DEBUG: Show permissions/context before rendering
|
46
|
+
from rich import print as rich_print
|
47
|
+
debug_flag = False
|
48
|
+
import sys
|
49
|
+
try:
|
50
|
+
debug_flag = (hasattr(sys, 'argv') and ('--debug' in sys.argv or '--verbose' in sys.argv or '-v' in sys.argv))
|
51
|
+
except Exception:
|
52
|
+
pass
|
53
|
+
if debug_flag:
|
54
|
+
rich_print(f"[bold magenta][DEBUG][/bold magenta] Rendering system prompt template '[cyan]{template_filename}[/cyan]' with allowed_permissions: [yellow]{allowed_permissions}[/yellow]")
|
55
|
+
rich_print(f"[bold magenta][DEBUG][/bold magenta] Template context: [green]{context}[/green]")
|
56
|
+
if allowed_permissions and 'x' in allowed_permissions:
|
57
|
+
pd = PlatformDiscovery()
|
58
|
+
context["platform"] = pd.get_platform_name()
|
59
|
+
context["python_version"] = pd.get_python_version()
|
60
|
+
context["shell_info"] = pd.detect_shell()
|
31
61
|
|
32
62
|
# Locate and load the system prompt template
|
33
63
|
templates_dir = (
|
34
64
|
Path(__file__).parent.parent.parent / "agent" / "templates" / "profiles"
|
35
65
|
)
|
36
|
-
|
66
|
+
profile = getattr(args, "profile", None)
|
67
|
+
if profile:
|
68
|
+
template_filename = f"system_prompt_template_{profile}.txt.j2"
|
69
|
+
template_path = templates_dir / template_filename
|
70
|
+
else:
|
71
|
+
# No profile specified means the main agent has no dedicated system prompt template.
|
72
|
+
print("[janito] No profile specified. The main agent runs without a system prompt template.\n"
|
73
|
+
"Use --profile PROFILE to view a profile-specific system prompt.")
|
74
|
+
return
|
37
75
|
template_content = None
|
38
|
-
if template_path.exists():
|
76
|
+
if template_path and template_path.exists():
|
39
77
|
with open(template_path, "r", encoding="utf-8") as file:
|
40
78
|
template_content = file.read()
|
41
79
|
else:
|
42
80
|
# Try package import fallback
|
43
81
|
try:
|
44
82
|
with importlib.resources.files("janito.agent.templates.profiles").joinpath(
|
45
|
-
|
83
|
+
template_filename
|
46
84
|
).open("r", encoding="utf-8") as file:
|
47
85
|
template_content = file.read()
|
48
86
|
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
87
|
+
if profile:
|
88
|
+
raise FileNotFoundError(
|
89
|
+
f"[janito] Could not find profile-specific template '{template_filename}' in {template_path} nor in janito.agent.templates.profiles package."
|
90
|
+
)
|
91
|
+
else:
|
92
|
+
print(
|
93
|
+
f"[janito] Could not find {template_filename} in {template_path} nor in janito.agent.templates.profiles package."
|
94
|
+
)
|
95
|
+
print("No system prompt is set or resolved for this configuration.")
|
96
|
+
return
|
54
97
|
|
55
98
|
template = Template(template_content)
|
56
99
|
system_prompt = template.render(**context)
|
57
100
|
|
58
|
-
print("\n--- System Prompt (resolved) ---\n")
|
101
|
+
print(f"\n--- System Prompt (resolved, profile: {getattr(args, 'profile', 'main')}) ---\n")
|
59
102
|
print(system_prompt)
|
60
103
|
print("\n-------------------------------\n")
|
61
104
|
if agent_role:
|
janito/cli/config.py
CHANGED
@@ -13,16 +13,15 @@ CONFIG_OPTIONS = {
|
|
13
13
|
"profile": "Agent Profile name (only 'base' is supported)",
|
14
14
|
}
|
15
15
|
|
16
|
-
DEFAULT_TERMWEB_PORT = 8088
|
17
16
|
|
18
17
|
|
19
|
-
def
|
20
|
-
port = config.get("
|
18
|
+
def get__port():
|
19
|
+
port = config.get("_port")
|
21
20
|
try:
|
22
21
|
return int(port)
|
23
22
|
except Exception:
|
24
|
-
|
23
|
+
pass
|
25
24
|
|
26
25
|
|
27
|
-
def
|
28
|
-
config.file_set("
|
26
|
+
def set__port(port):
|
27
|
+
config.file_set("_port", int(port))
|
janito/cli/core/getters.py
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
"""Handlers for get-type CLI commands (show_config, list_providers, models, tools)."""
|
2
|
-
import sys
|
3
|
-
|
4
|
-
from janito.cli.cli_commands.list_providers import handle_list_providers
|
5
|
-
from janito.cli.cli_commands.list_models import handle_list_models
|
6
|
-
from janito.cli.cli_commands.list_tools import handle_list_tools
|
7
|
-
from janito.cli.cli_commands.show_config import handle_show_config
|
8
|
-
from functools import partial
|
9
|
-
from janito.provider_registry import ProviderRegistry
|
10
|
-
|
11
|
-
GETTER_KEYS = ["show_config", "list_providers", "list_models", "list_tools"]
|
12
|
-
|
13
|
-
|
14
|
-
def handle_getter(args, config_mgr=None):
|
15
|
-
provider_instance = None
|
16
|
-
if getattr(args, "list_models", False):
|
17
|
-
provider = getattr(args, "provider", None)
|
18
|
-
if not provider:
|
19
|
-
import sys
|
20
|
-
print(
|
21
|
-
"Error: No provider selected. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
22
|
-
)
|
23
|
-
sys.exit(1)
|
24
|
-
provider_instance = ProviderRegistry().get_instance(provider)
|
25
|
-
GETTER_DISPATCH = {
|
26
|
-
"list_providers": partial(handle_list_providers, args),
|
27
|
-
"list_models": partial(handle_list_models, args, provider_instance),
|
28
|
-
"list_tools": partial(handle_list_tools, args),
|
29
|
-
"show_config": partial(handle_show_config, args),
|
30
|
-
}
|
31
|
-
for arg in GETTER_KEYS:
|
32
|
-
if getattr(args, arg, False) and arg in GETTER_DISPATCH:
|
33
|
-
return GETTER_DISPATCH[arg]()
|
1
|
+
"""Handlers for get-type CLI commands (show_config, list_providers, models, tools)."""
|
2
|
+
import sys
|
3
|
+
|
4
|
+
from janito.cli.cli_commands.list_providers import handle_list_providers
|
5
|
+
from janito.cli.cli_commands.list_models import handle_list_models
|
6
|
+
from janito.cli.cli_commands.list_tools import handle_list_tools
|
7
|
+
from janito.cli.cli_commands.show_config import handle_show_config
|
8
|
+
from functools import partial
|
9
|
+
from janito.provider_registry import ProviderRegistry
|
10
|
+
|
11
|
+
GETTER_KEYS = ["show_config", "list_providers", "list_models", "list_tools"]
|
12
|
+
|
13
|
+
|
14
|
+
def handle_getter(args, config_mgr=None):
|
15
|
+
provider_instance = None
|
16
|
+
if getattr(args, "list_models", False):
|
17
|
+
provider = getattr(args, "provider", None)
|
18
|
+
if not provider:
|
19
|
+
import sys
|
20
|
+
print(
|
21
|
+
"Error: No provider selected. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
22
|
+
)
|
23
|
+
sys.exit(1)
|
24
|
+
provider_instance = ProviderRegistry().get_instance(provider)
|
25
|
+
GETTER_DISPATCH = {
|
26
|
+
"list_providers": partial(handle_list_providers, args),
|
27
|
+
"list_models": partial(handle_list_models, args, provider_instance),
|
28
|
+
"list_tools": partial(handle_list_tools, args),
|
29
|
+
"show_config": partial(handle_show_config, args),
|
30
|
+
}
|
31
|
+
for arg in GETTER_KEYS:
|
32
|
+
if getattr(args, arg, False) and arg in GETTER_DISPATCH:
|
33
|
+
return GETTER_DISPATCH[arg]()
|
janito/cli/core/runner.py
CHANGED
@@ -92,11 +92,11 @@ def prepare_llm_driver_config(args, modifiers):
|
|
92
92
|
llm_driver_config = LLMDriverConfig(**driver_config_data)
|
93
93
|
if getattr(llm_driver_config, "verbose_api", None):
|
94
94
|
pass
|
95
|
-
agent_role = modifiers.get("role", "
|
95
|
+
agent_role = modifiers.get("role", "developer")
|
96
96
|
return provider, llm_driver_config, agent_role
|
97
97
|
|
98
98
|
|
99
|
-
def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False,
|
99
|
+
def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False, ):
|
100
100
|
"""
|
101
101
|
Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
|
102
102
|
"""
|
@@ -105,23 +105,26 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
105
105
|
|
106
106
|
# Patch: disable execution/run tools if not enabled
|
107
107
|
import janito.tools
|
108
|
+
from janito.tools.tool_base import ToolPermissions
|
109
|
+
read = getattr(args, "read", False)
|
110
|
+
write = getattr(args, "write", False)
|
111
|
+
execute = getattr(args, "exec", False)
|
112
|
+
from janito.tools.permissions import set_global_allowed_permissions
|
113
|
+
from janito.tools.tool_base import ToolPermissions
|
114
|
+
allowed_permissions = ToolPermissions(read=read, write=write, execute=execute)
|
115
|
+
set_global_allowed_permissions(allowed_permissions)
|
116
|
+
# Store the default permissions for later restoration (e.g., on /restart)
|
117
|
+
from janito.tools.permissions import set_default_allowed_permissions
|
118
|
+
set_default_allowed_permissions(allowed_permissions)
|
108
119
|
adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
from janito.tools.adapters.local import PythonCodeRunTool, PythonCommandRunTool, PythonFileRunTool, RunBashCommandTool, RunPowershellCommandTool
|
118
|
-
for tool_cls in [PythonCodeRunTool, PythonCommandRunTool, PythonFileRunTool, RunBashCommandTool, RunPowershellCommandTool]:
|
119
|
-
try:
|
120
|
-
adapter.register_tool(tool_cls)
|
121
|
-
except Exception:
|
122
|
-
pass # Already registered or error
|
123
|
-
except Exception:
|
124
|
-
pass
|
120
|
+
|
121
|
+
# Print allowed permissions in verbose mode
|
122
|
+
if getattr(args, "verbose", False):
|
123
|
+
print_verbose_info(
|
124
|
+
"Allowed Tool Permissions",
|
125
|
+
f"read={read}, write={write}, execute={execute}",
|
126
|
+
style="yellow"
|
127
|
+
)
|
125
128
|
|
126
129
|
provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
|
127
130
|
if provider_instance is None:
|
@@ -140,7 +143,10 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
140
143
|
# DEBUG: Print exec_enabled propagation at runner
|
141
144
|
|
142
145
|
handler = SingleShotPromptHandler(
|
143
|
-
args, provider_instance, llm_driver_config,
|
146
|
+
args, provider_instance, llm_driver_config,
|
147
|
+
role=agent_role,
|
148
|
+
|
149
|
+
allowed_permissions=allowed_permissions,
|
144
150
|
)
|
145
151
|
handler.handle()
|
146
152
|
else:
|
@@ -156,7 +162,8 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
156
162
|
args=args,
|
157
163
|
verbose_tools=verbose_tools,
|
158
164
|
verbose_agent=getattr(args, "verbose_agent", False),
|
159
|
-
|
165
|
+
|
166
|
+
allowed_permissions=allowed_permissions,
|
160
167
|
)
|
161
168
|
session.run()
|
162
169
|
|
janito/cli/core/setters.py
CHANGED
@@ -43,8 +43,17 @@ def handle_set(args, config_mgr=None):
|
|
43
43
|
return True
|
44
44
|
if ".max_tokens" in key or ".base_url" in key:
|
45
45
|
return _handle_set_provider_level_setting(key, value)
|
46
|
+
# Tool permissions support: janito set tool_permissions=rwx
|
47
|
+
if key == "tool_permissions":
|
48
|
+
from janito.tools.permissions_parse import parse_permissions_string
|
49
|
+
from janito.tools.permissions import set_global_allowed_permissions
|
50
|
+
perms = parse_permissions_string(value)
|
51
|
+
global_config.file_set("tool_permissions", value)
|
52
|
+
set_global_allowed_permissions(perms)
|
53
|
+
print(f"Tool permissions set to '{value}' (parsed: {perms})")
|
54
|
+
return True
|
46
55
|
print(
|
47
|
-
f"Error: Unknown config key '{key}'. Supported: provider, model, <provider>.model, max_tokens, base_url, azure_deployment_name, <provider>.max_tokens, <provider>.base_url, <provider>.<model>.max_tokens, <provider>.<model>.base_url"
|
56
|
+
f"Error: Unknown config key '{key}'. Supported: provider, model, <provider>.model, max_tokens, base_url, azure_deployment_name, <provider>.max_tokens, <provider>.base_url, <provider>.<model>.max_tokens, <provider>.<model>.base_url, tool_permissions"
|
48
57
|
)
|
49
58
|
return True
|
50
59
|
except Exception as e:
|
janito/cli/main_cli.py
CHANGED
@@ -14,6 +14,14 @@ from janito.cli.core.event_logger import (
|
|
14
14
|
)
|
15
15
|
|
16
16
|
definition = [
|
17
|
+
(
|
18
|
+
["--profile"],
|
19
|
+
{
|
20
|
+
"metavar": "PROFILE",
|
21
|
+
"help": "Select the profile name for the system prompt (e.g. 'developer').",
|
22
|
+
"default": None,
|
23
|
+
},
|
24
|
+
),
|
17
25
|
(
|
18
26
|
["-W", "--workdir"],
|
19
27
|
{
|
@@ -57,6 +65,20 @@ definition = [
|
|
57
65
|
"help": "Enable execution/run tools (allows running code or shell tools from the CLI)",
|
58
66
|
},
|
59
67
|
),
|
68
|
+
(
|
69
|
+
["-r", "--read"],
|
70
|
+
{
|
71
|
+
"action": "store_true",
|
72
|
+
"help": "Enable tools that require read permissions",
|
73
|
+
},
|
74
|
+
),
|
75
|
+
(
|
76
|
+
["-w", "--write"],
|
77
|
+
{
|
78
|
+
"action": "store_true",
|
79
|
+
"help": "Enable tools that require write permissions",
|
80
|
+
},
|
81
|
+
),
|
60
82
|
(["--unset"], {"metavar": "KEY", "help": "Unset (remove) a config key"}),
|
61
83
|
(["--version"], {"action": "version", "version": None}),
|
62
84
|
(["--list-tools"], {"action": "store_true", "help": "List all registered tools"}),
|
@@ -85,7 +107,6 @@ definition = [
|
|
85
107
|
"help": "Show the resolved system prompt for the main agent",
|
86
108
|
},
|
87
109
|
),
|
88
|
-
(["-r", "--role"], {"metavar": "ROLE", "help": "Set the role for the agent"}),
|
89
110
|
(["-p", "--provider"], {"metavar": "PROVIDER", "help": "Select the provider"}),
|
90
111
|
(["-m", "--model"], {"metavar": "MODEL", "help": "Select the model"}),
|
91
112
|
(
|
@@ -104,7 +125,7 @@ definition = [
|
|
104
125
|
},
|
105
126
|
),
|
106
127
|
(
|
107
|
-
["
|
128
|
+
["--web"],
|
108
129
|
{
|
109
130
|
"action": "store_true",
|
110
131
|
"default": False,
|
@@ -112,11 +133,11 @@ definition = [
|
|
112
133
|
},
|
113
134
|
),
|
114
135
|
(
|
115
|
-
["
|
136
|
+
["---port"],
|
116
137
|
{
|
117
138
|
"type": int,
|
118
139
|
"default": 8088,
|
119
|
-
"help": "Port for the
|
140
|
+
"help": "Port for the server (default: 8088)",
|
120
141
|
},
|
121
142
|
),
|
122
143
|
(["--effort"],
|
@@ -150,10 +171,12 @@ MODIFIER_KEYS = [
|
|
150
171
|
"verbose",
|
151
172
|
"raw",
|
152
173
|
"web",
|
153
|
-
"
|
174
|
+
"_port",
|
154
175
|
"verbose_api",
|
155
176
|
"verbose_tools",
|
156
177
|
"exec",
|
178
|
+
"read",
|
179
|
+
"write",
|
157
180
|
]
|
158
181
|
SETTER_KEYS = ["set", "set_provider", "set_api_key", "unset"]
|
159
182
|
GETTER_KEYS = ["show_config", "list_providers", "list_models", "list_tools"]
|
@@ -177,6 +200,17 @@ class JanitoCLI:
|
|
177
200
|
self._define_args()
|
178
201
|
self.args = self.parser.parse_args()
|
179
202
|
self._set_all_arg_defaults()
|
203
|
+
# Support reading prompt from stdin if no user_prompt is given
|
204
|
+
import sys
|
205
|
+
if not sys.stdin.isatty():
|
206
|
+
stdin_input = sys.stdin.read().strip()
|
207
|
+
if stdin_input:
|
208
|
+
if self.args.user_prompt and len(self.args.user_prompt) > 0:
|
209
|
+
# Prefix the prompt argument to the stdin input
|
210
|
+
combined = ' '.join(self.args.user_prompt) + ' ' + stdin_input
|
211
|
+
self.args.user_prompt = [combined]
|
212
|
+
else:
|
213
|
+
self.args.user_prompt = [stdin_input]
|
180
214
|
from janito.cli.rich_terminal_reporter import RichTerminalReporter
|
181
215
|
|
182
216
|
self.rich_reporter = RichTerminalReporter(raw_mode=self.args.raw)
|
@@ -212,9 +246,6 @@ class JanitoCLI:
|
|
212
246
|
if getattr(self.args, k, None) is not None
|
213
247
|
}
|
214
248
|
|
215
|
-
def exec_enabled(self):
|
216
|
-
return getattr(self.args, "exec", False)
|
217
|
-
|
218
249
|
def classify(self):
|
219
250
|
if any(getattr(self.args, k, None) for k in SETTER_KEYS):
|
220
251
|
return RunMode.SET
|
@@ -268,8 +299,7 @@ class JanitoCLI:
|
|
268
299
|
llm_driver_config,
|
269
300
|
agent_role,
|
270
301
|
verbose_tools=self.args.verbose_tools,
|
271
|
-
|
272
|
-
)
|
302
|
+
)
|
273
303
|
elif run_mode == RunMode.GET:
|
274
304
|
handle_getter(self.args)
|
275
305
|
|
janito/cli/prompt_core.py
CHANGED
@@ -3,7 +3,7 @@ Core PromptHandler: Handles prompt submission and response formatting for janito
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import time
|
6
|
-
from janito
|
6
|
+
from janito import __version__ as VERSION
|
7
7
|
from janito.performance_collector import PerformanceCollector
|
8
8
|
from rich.status import Status
|
9
9
|
from rich.console import Console
|
@@ -210,7 +210,23 @@ class PromptHandler:
|
|
210
210
|
on_event(final_event)
|
211
211
|
global_event_bus.publish(final_event)
|
212
212
|
except KeyboardInterrupt:
|
213
|
-
|
213
|
+
# Capture user interrupt / cancellation
|
214
|
+
self.console.print("[red]Interrupted by the user.[/red]")
|
215
|
+
try:
|
216
|
+
from janito.driver_events import RequestFinished, RequestStatus
|
217
|
+
# Record a synthetic "cancelled" final event so that downstream
|
218
|
+
# handlers (e.g. single_shot_mode.handler._post_prompt_actions)
|
219
|
+
# can reliably detect that the prompt was interrupted by the
|
220
|
+
# user and avoid showing misleading messages such as
|
221
|
+
# "No output produced by the model.".
|
222
|
+
if hasattr(self, "agent") and self.agent is not None:
|
223
|
+
self.agent.last_event = RequestFinished(
|
224
|
+
status=RequestStatus.CANCELLED,
|
225
|
+
reason="Interrupted by the user",
|
226
|
+
)
|
227
|
+
except Exception:
|
228
|
+
# Do not fail on cleanup – this hook is best-effort only.
|
229
|
+
pass
|
214
230
|
|
215
231
|
def _print_verbose_debug(self, message):
|
216
232
|
if hasattr(self.args, "verbose_agent") and self.args.verbose_agent:
|