janito 2.3.1__py3-none-any.whl → 2.4.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 +92 -18
- 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/session.py +80 -94
- janito/cli/chat_mode/session_profile_select.py +80 -0
- janito/cli/chat_mode/shell/commands/__init__.py +13 -7
- janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
- janito/cli/chat_mode/shell/commands/conversation_restart.py +30 -0
- janito/cli/chat_mode/shell/commands/execute.py +42 -0
- janito/cli/chat_mode/shell/commands/help.py +6 -3
- janito/cli/chat_mode/shell/commands/model.py +28 -0
- 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/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 +25 -18
- janito/cli/core/setters.py +10 -1
- janito/cli/main_cli.py +28 -5
- janito/cli/prompt_core.py +18 -2
- janito/cli/prompt_setup.py +56 -0
- janito/cli/single_shot_mode/handler.py +14 -73
- janito/cli/verbose_output.py +1 -1
- janito/config_manager.py +125 -112
- janito/drivers/dashscope.bak.zip +0 -0
- janito/drivers/openai/README.md +20 -0
- janito/drivers/openai_responses.bak.zip +0 -0
- janito/event_bus/event.py +2 -2
- 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/azure_openai/model_info.py +16 -16
- janito/providers/dashscope.bak.zip +0 -0
- 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 +2 -2
- 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 -1
- janito/tools/tool_utils.py +4 -6
- janito/tools/tools_adapter.py +25 -20
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/METADATA +51 -16
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/RECORD +88 -74
- 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.4.0.dist-info}/WHEEL +0 -0
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.3.1.dist-info → janito-2.4.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,7 +92,7 @@ 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
|
|
@@ -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 = exec_enabled
|
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
|
+
exec_enabled=exec_enabled,
|
149
|
+
allowed_permissions=allowed_permissions,
|
144
150
|
)
|
145
151
|
handler.handle()
|
146
152
|
else:
|
@@ -157,6 +163,7 @@ def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=F
|
|
157
163
|
verbose_tools=verbose_tools,
|
158
164
|
verbose_agent=getattr(args, "verbose_agent", False),
|
159
165
|
exec_enabled=exec_enabled,
|
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"]
|
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:
|
@@ -0,0 +1,56 @@
|
|
1
|
+
"""
|
2
|
+
Shared utilities to set up an agent together with a GenericPromptHandler that
|
3
|
+
both single–shot and chat modes can reuse. Having one central place avoids the
|
4
|
+
code duplication that previously existed in `chat_mode.session.ChatSession` and
|
5
|
+
`single_shot_mode.handler.PromptHandler`.
|
6
|
+
"""
|
7
|
+
from __future__ import annotations
|
8
|
+
|
9
|
+
from janito.agent.setup_agent import create_configured_agent
|
10
|
+
from janito.cli.prompt_core import (
|
11
|
+
PromptHandler as GenericPromptHandler,
|
12
|
+
)
|
13
|
+
from typing import Any, Optional
|
14
|
+
|
15
|
+
|
16
|
+
def setup_agent_and_prompt_handler(
|
17
|
+
*,
|
18
|
+
args: Any,
|
19
|
+
provider_instance: Any,
|
20
|
+
llm_driver_config: Any,
|
21
|
+
role: Optional[str] = None,
|
22
|
+
verbose_tools: bool = False,
|
23
|
+
verbose_agent: bool = False,
|
24
|
+
exec_enabled: bool = False,
|
25
|
+
allowed_permissions: Optional[list[str]] = None,
|
26
|
+
profile: Optional[str] = None,
|
27
|
+
profile_system_prompt: Optional[str] = None,
|
28
|
+
conversation_history: Any = None,
|
29
|
+
):
|
30
|
+
"""Create a configured *agent* as well as a *GenericPromptHandler* bound to
|
31
|
+
that agent and return them as a tuple.
|
32
|
+
|
33
|
+
This helper consolidates the repetitive boiler-plate that was scattered
|
34
|
+
across *single-shot* and *chat* modes – both of which need an agent plus a
|
35
|
+
prompt handler that points to that agent.
|
36
|
+
"""
|
37
|
+
agent = create_configured_agent(
|
38
|
+
provider_instance=provider_instance,
|
39
|
+
llm_driver_config=llm_driver_config,
|
40
|
+
role=role,
|
41
|
+
verbose_tools=verbose_tools,
|
42
|
+
verbose_agent=verbose_agent,
|
43
|
+
exec_enabled=exec_enabled,
|
44
|
+
allowed_permissions=allowed_permissions,
|
45
|
+
profile=profile,
|
46
|
+
profile_system_prompt=profile_system_prompt,
|
47
|
+
)
|
48
|
+
|
49
|
+
prompt_handler = GenericPromptHandler(
|
50
|
+
args=args,
|
51
|
+
conversation_history=conversation_history,
|
52
|
+
provider_instance=provider_instance,
|
53
|
+
)
|
54
|
+
prompt_handler.agent = agent
|
55
|
+
|
56
|
+
return agent, prompt_handler
|