janito 2.3.0__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 +6 -6
- 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/autocomplete.py +21 -21
- 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/clear.py +12 -12
- 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/multi.py +51 -51
- 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 +62 -62
- janito/cli/chat_mode/shell/session.bak.zip +0 -0
- janito/cli/chat_mode/toolbar.py +44 -27
- janito/cli/cli_commands/list_models.py +35 -35
- janito/cli/cli_commands/list_providers.py +9 -9
- janito/cli/cli_commands/list_tools.py +86 -53
- janito/cli/cli_commands/model_selection.py +50 -50
- janito/cli/cli_commands/set_api_key.py +19 -19
- janito/cli/cli_commands/show_config.py +51 -51
- janito/cli/cli_commands/show_system_prompt.py +105 -62
- janito/cli/config.py +5 -6
- janito/cli/core/__init__.py +4 -4
- janito/cli/core/event_logger.py +59 -59
- janito/cli/core/runner.py +25 -18
- janito/cli/core/setters.py +10 -1
- janito/cli/core/unsetters.py +54 -54
- 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/__init__.py +6 -6
- janito/cli/single_shot_mode/handler.py +14 -73
- janito/cli/verbose_output.py +1 -1
- janito/config.py +5 -5
- janito/config_manager.py +13 -0
- janito/drivers/anthropic/driver.py +113 -113
- 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/formatting_token.py +54 -54
- janito/i18n/__init__.py +35 -35
- janito/i18n/messages.py +23 -23
- janito/i18n/pt.py +46 -47
- janito/llm/README.md +23 -0
- janito/llm/__init__.py +5 -5
- janito/llm/agent.py +507 -443
- janito/llm/driver.py +8 -0
- janito/llm/driver_config_builder.py +34 -34
- janito/llm/driver_input.py +12 -12
- janito/llm/message_parts.py +60 -60
- janito/llm/model.py +38 -38
- janito/llm/provider.py +196 -196
- janito/provider_registry.py +8 -6
- janito/providers/anthropic/model_info.py +22 -22
- janito/providers/anthropic/provider.py +2 -0
- janito/providers/azure_openai/provider.py +3 -0
- janito/providers/dashscope.bak.zip +0 -0
- janito/providers/deepseek/__init__.py +1 -1
- janito/providers/deepseek/model_info.py +16 -16
- janito/providers/deepseek/provider.py +94 -91
- janito/providers/google/provider.py +3 -0
- janito/providers/mistralai/provider.py +3 -0
- janito/providers/openai/provider.py +4 -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/__init__.py +1 -1
- janito/tools/adapters/local/__init__.py +65 -62
- janito/tools/adapters/local/adapter.py +18 -35
- janito/tools/adapters/local/ask_user.py +101 -102
- janito/tools/adapters/local/copy_file.py +84 -84
- janito/tools/adapters/local/create_directory.py +69 -69
- janito/tools/adapters/local/create_file.py +82 -82
- janito/tools/adapters/local/delete_text_in_file.py +2 -2
- janito/tools/adapters/local/fetch_url.py +97 -97
- janito/tools/adapters/local/find_files.py +139 -138
- janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
- janito/tools/adapters/local/get_file_outline/core.py +117 -117
- janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
- janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
- janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
- janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
- janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
- 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 +166 -166
- janito/tools/adapters/local/python_command_run.py +164 -164
- janito/tools/adapters/local/python_file_run.py +163 -163
- 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 +176 -176
- janito/tools/adapters/local/run_powershell_command.py +219 -219
- janito/tools/adapters/local/search_text/__init__.py +1 -1
- janito/tools/adapters/local/search_text/core.py +201 -201
- janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
- janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
- janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
- janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
- janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
- janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
- janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
- janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
- janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
- janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
- janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
- janito/tools/adapters/local/view_file.py +168 -167
- janito/tools/inspect_registry.py +17 -17
- 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 +118 -105
- janito/tools/tool_events.py +58 -58
- janito/tools/tool_run_exception.py +12 -12
- janito/tools/tool_use_tracker.py +81 -81
- janito/tools/tool_utils.py +43 -45
- janito/tools/tools_adapter.py +25 -20
- janito/tools/tools_schema.py +104 -104
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/METADATA +425 -388
- janito-2.4.0.dist-info/RECORD +195 -0
- 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.0.dist-info/RECORD +0 -181
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/WHEEL +0 -0
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/top_level.txt +0 -0
janito/tools/tools_adapter.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
from janito.tools.tool_base import ToolBase
|
2
2
|
from janito.tools.tool_events import ToolCallStarted, ToolCallFinished, ToolCallError
|
3
3
|
from janito.exceptions import ToolCallException
|
4
|
-
from
|
5
|
-
|
4
|
+
from janito.tools.tool_base import ToolPermissions
|
6
5
|
|
7
6
|
class ToolsAdapterBase:
|
8
7
|
"""
|
@@ -13,11 +12,10 @@ class ToolsAdapterBase:
|
|
13
12
|
"""
|
14
13
|
|
15
14
|
def __init__(
|
16
|
-
self, tools=None, event_bus=None
|
15
|
+
self, tools=None, event_bus=None
|
17
16
|
):
|
18
17
|
self._tools = tools or []
|
19
18
|
self._event_bus = event_bus # event bus can be set on all adapters
|
20
|
-
self._enabled_tools = set(enabled_tools) if enabled_tools is not None else None
|
21
19
|
self.verbose_tools = False
|
22
20
|
|
23
21
|
def set_verbose_tools(self, value: bool):
|
@@ -31,11 +29,28 @@ class ToolsAdapterBase:
|
|
31
29
|
def event_bus(self, bus):
|
32
30
|
self._event_bus = bus
|
33
31
|
|
32
|
+
def is_tool_allowed(self, tool):
|
33
|
+
"""Check if a tool is allowed based on current global AllowedPermissionsState."""
|
34
|
+
from janito.tools.permissions import get_global_allowed_permissions
|
35
|
+
allowed_permissions = get_global_allowed_permissions()
|
36
|
+
perms = tool.permissions # permissions are mandatory and type-checked
|
37
|
+
# If all permissions are False, block all tools
|
38
|
+
if not (allowed_permissions.read or allowed_permissions.write or allowed_permissions.execute):
|
39
|
+
return False
|
40
|
+
for perm in ['read', 'write', 'execute']:
|
41
|
+
if getattr(perms, perm) and not getattr(allowed_permissions, perm):
|
42
|
+
return False
|
43
|
+
return True
|
44
|
+
|
34
45
|
def get_tools(self):
|
35
|
-
"""Return the list of enabled tools managed by this provider."""
|
36
|
-
|
37
|
-
|
38
|
-
|
46
|
+
"""Return the list of enabled tools managed by this provider, filtered by allowed permissions."""
|
47
|
+
tools = [tool for tool in self._tools if self.is_tool_allowed(tool)]
|
48
|
+
return tools
|
49
|
+
|
50
|
+
def set_allowed_permissions(self, allowed_permissions):
|
51
|
+
"""Set the allowed permissions at runtime. This now updates the global AllowedPermissionsState only."""
|
52
|
+
from janito.tools.permissions import set_global_allowed_permissions
|
53
|
+
set_global_allowed_permissions(allowed_permissions)
|
39
54
|
|
40
55
|
def add_tool(self, tool):
|
41
56
|
self._tools.append(tool)
|
@@ -231,18 +246,8 @@ class ToolsAdapterBase:
|
|
231
246
|
)
|
232
247
|
|
233
248
|
def _check_tool_permissions(self, tool_name, request_id, arguments):
|
234
|
-
|
235
|
-
|
236
|
-
if self._event_bus:
|
237
|
-
self._event_bus.publish(
|
238
|
-
ToolCallError(
|
239
|
-
tool_name=tool_name,
|
240
|
-
request_id=request_id,
|
241
|
-
error=error_msg,
|
242
|
-
arguments=arguments,
|
243
|
-
)
|
244
|
-
)
|
245
|
-
raise ToolCallException(tool_name, error_msg, arguments=arguments)
|
249
|
+
# No enabled_tools check anymore; permission checks are handled by is_tool_allowed
|
250
|
+
pass
|
246
251
|
|
247
252
|
def _ensure_tool_exists(self, tool, tool_name, request_id, arguments):
|
248
253
|
if tool is None:
|
janito/tools/tools_schema.py
CHANGED
@@ -1,104 +1,104 @@
|
|
1
|
-
import inspect
|
2
|
-
import typing
|
3
|
-
import re
|
4
|
-
|
5
|
-
|
6
|
-
class ToolSchemaBase:
|
7
|
-
def parse_param_section(self, lines, param_section_headers):
|
8
|
-
param_descs = {}
|
9
|
-
in_params = False
|
10
|
-
for line in lines:
|
11
|
-
stripped_line = line.strip()
|
12
|
-
if any(
|
13
|
-
stripped_line.lower().startswith(h + ":") or stripped_line.lower() == h
|
14
|
-
for h in param_section_headers
|
15
|
-
):
|
16
|
-
in_params = True
|
17
|
-
continue
|
18
|
-
if in_params:
|
19
|
-
m = re.match(
|
20
|
-
r"([a-zA-Z_][a-zA-Z0-9_]*)\s*(?:\(([^)]+)\))?\s*[:\-]?\s*(.+)",
|
21
|
-
stripped_line,
|
22
|
-
)
|
23
|
-
if m:
|
24
|
-
param, _, desc = m.groups()
|
25
|
-
param_descs[param] = desc.strip()
|
26
|
-
elif stripped_line and stripped_line[0] != "-":
|
27
|
-
if param_descs:
|
28
|
-
last = list(param_descs)[-1]
|
29
|
-
param_descs[last] += " " + stripped_line
|
30
|
-
if (
|
31
|
-
stripped_line.lower().startswith("returns:")
|
32
|
-
or stripped_line.lower() == "returns"
|
33
|
-
):
|
34
|
-
break
|
35
|
-
return param_descs
|
36
|
-
|
37
|
-
def parse_return_section(self, lines):
|
38
|
-
in_returns = False
|
39
|
-
return_desc = ""
|
40
|
-
for line in lines:
|
41
|
-
stripped_line = line.strip()
|
42
|
-
if (
|
43
|
-
stripped_line.lower().startswith("returns:")
|
44
|
-
or stripped_line.lower() == "returns"
|
45
|
-
):
|
46
|
-
in_returns = True
|
47
|
-
continue
|
48
|
-
if in_returns:
|
49
|
-
if stripped_line:
|
50
|
-
return_desc += (" " if return_desc else "") + stripped_line
|
51
|
-
return return_desc
|
52
|
-
|
53
|
-
def parse_docstring(self, docstring: str):
|
54
|
-
if not docstring:
|
55
|
-
return "", {}, ""
|
56
|
-
lines = docstring.strip().split("\n")
|
57
|
-
summary = lines[0].strip()
|
58
|
-
param_section_headers = ("args", "arguments", "params", "parameters")
|
59
|
-
param_descs = self.parse_param_section(lines[1:], param_section_headers)
|
60
|
-
return_desc = self.parse_return_section(lines[1:])
|
61
|
-
return summary, param_descs, return_desc
|
62
|
-
|
63
|
-
def validate_tool_class(self, tool_class):
|
64
|
-
if not hasattr(tool_class, "tool_name") or not isinstance(
|
65
|
-
tool_class.tool_name, str
|
66
|
-
):
|
67
|
-
raise ValueError(
|
68
|
-
"Tool class must have a class-level 'tool_name' attribute (str) for registry and schema generation."
|
69
|
-
)
|
70
|
-
if not hasattr(tool_class, "run") or not callable(getattr(tool_class, "run")):
|
71
|
-
raise ValueError("Tool class must have a callable 'run' method.")
|
72
|
-
func = tool_class.run
|
73
|
-
tool_name = tool_class.tool_name
|
74
|
-
sig = inspect.signature(func)
|
75
|
-
if sig.return_annotation is inspect._empty or sig.return_annotation is not str:
|
76
|
-
raise ValueError(
|
77
|
-
f"Tool '{tool_name}' must have an explicit return type of 'str'. Found: {sig.return_annotation}"
|
78
|
-
)
|
79
|
-
missing_type_hints = [
|
80
|
-
name
|
81
|
-
for name, param in sig.parameters.items()
|
82
|
-
if name != "self" and param.annotation is inspect._empty
|
83
|
-
]
|
84
|
-
if missing_type_hints:
|
85
|
-
raise ValueError(
|
86
|
-
f"Tool '{tool_name}' is missing type hints for parameter(s): {', '.join(missing_type_hints)}.\nAll parameters must have explicit type hints for schema generation."
|
87
|
-
)
|
88
|
-
class_doc = (
|
89
|
-
tool_class.__doc__.strip() if tool_class and tool_class.__doc__ else ""
|
90
|
-
)
|
91
|
-
summary, param_descs, return_desc = self.parse_docstring(class_doc)
|
92
|
-
description = summary
|
93
|
-
if return_desc:
|
94
|
-
description += f"\n\nReturns: {return_desc}"
|
95
|
-
undocumented = [
|
96
|
-
name
|
97
|
-
for name, param in sig.parameters.items()
|
98
|
-
if name != "self" and name not in param_descs
|
99
|
-
]
|
100
|
-
if undocumented:
|
101
|
-
raise ValueError(
|
102
|
-
f"Tool '{tool_name}' is missing docstring documentation for parameter(s): {', '.join(undocumented)}.\nParameter documentation must be provided in the Tool class docstring, not the method docstring."
|
103
|
-
)
|
104
|
-
return func, tool_name, sig, summary, param_descs, return_desc, description
|
1
|
+
import inspect
|
2
|
+
import typing
|
3
|
+
import re
|
4
|
+
|
5
|
+
|
6
|
+
class ToolSchemaBase:
|
7
|
+
def parse_param_section(self, lines, param_section_headers):
|
8
|
+
param_descs = {}
|
9
|
+
in_params = False
|
10
|
+
for line in lines:
|
11
|
+
stripped_line = line.strip()
|
12
|
+
if any(
|
13
|
+
stripped_line.lower().startswith(h + ":") or stripped_line.lower() == h
|
14
|
+
for h in param_section_headers
|
15
|
+
):
|
16
|
+
in_params = True
|
17
|
+
continue
|
18
|
+
if in_params:
|
19
|
+
m = re.match(
|
20
|
+
r"([a-zA-Z_][a-zA-Z0-9_]*)\s*(?:\(([^)]+)\))?\s*[:\-]?\s*(.+)",
|
21
|
+
stripped_line,
|
22
|
+
)
|
23
|
+
if m:
|
24
|
+
param, _, desc = m.groups()
|
25
|
+
param_descs[param] = desc.strip()
|
26
|
+
elif stripped_line and stripped_line[0] != "-":
|
27
|
+
if param_descs:
|
28
|
+
last = list(param_descs)[-1]
|
29
|
+
param_descs[last] += " " + stripped_line
|
30
|
+
if (
|
31
|
+
stripped_line.lower().startswith("returns:")
|
32
|
+
or stripped_line.lower() == "returns"
|
33
|
+
):
|
34
|
+
break
|
35
|
+
return param_descs
|
36
|
+
|
37
|
+
def parse_return_section(self, lines):
|
38
|
+
in_returns = False
|
39
|
+
return_desc = ""
|
40
|
+
for line in lines:
|
41
|
+
stripped_line = line.strip()
|
42
|
+
if (
|
43
|
+
stripped_line.lower().startswith("returns:")
|
44
|
+
or stripped_line.lower() == "returns"
|
45
|
+
):
|
46
|
+
in_returns = True
|
47
|
+
continue
|
48
|
+
if in_returns:
|
49
|
+
if stripped_line:
|
50
|
+
return_desc += (" " if return_desc else "") + stripped_line
|
51
|
+
return return_desc
|
52
|
+
|
53
|
+
def parse_docstring(self, docstring: str):
|
54
|
+
if not docstring:
|
55
|
+
return "", {}, ""
|
56
|
+
lines = docstring.strip().split("\n")
|
57
|
+
summary = lines[0].strip()
|
58
|
+
param_section_headers = ("args", "arguments", "params", "parameters")
|
59
|
+
param_descs = self.parse_param_section(lines[1:], param_section_headers)
|
60
|
+
return_desc = self.parse_return_section(lines[1:])
|
61
|
+
return summary, param_descs, return_desc
|
62
|
+
|
63
|
+
def validate_tool_class(self, tool_class):
|
64
|
+
if not hasattr(tool_class, "tool_name") or not isinstance(
|
65
|
+
tool_class.tool_name, str
|
66
|
+
):
|
67
|
+
raise ValueError(
|
68
|
+
"Tool class must have a class-level 'tool_name' attribute (str) for registry and schema generation."
|
69
|
+
)
|
70
|
+
if not hasattr(tool_class, "run") or not callable(getattr(tool_class, "run")):
|
71
|
+
raise ValueError("Tool class must have a callable 'run' method.")
|
72
|
+
func = tool_class.run
|
73
|
+
tool_name = tool_class.tool_name
|
74
|
+
sig = inspect.signature(func)
|
75
|
+
if sig.return_annotation is inspect._empty or sig.return_annotation is not str:
|
76
|
+
raise ValueError(
|
77
|
+
f"Tool '{tool_name}' must have an explicit return type of 'str'. Found: {sig.return_annotation}"
|
78
|
+
)
|
79
|
+
missing_type_hints = [
|
80
|
+
name
|
81
|
+
for name, param in sig.parameters.items()
|
82
|
+
if name != "self" and param.annotation is inspect._empty
|
83
|
+
]
|
84
|
+
if missing_type_hints:
|
85
|
+
raise ValueError(
|
86
|
+
f"Tool '{tool_name}' is missing type hints for parameter(s): {', '.join(missing_type_hints)}.\nAll parameters must have explicit type hints for schema generation."
|
87
|
+
)
|
88
|
+
class_doc = (
|
89
|
+
tool_class.__doc__.strip() if tool_class and tool_class.__doc__ else ""
|
90
|
+
)
|
91
|
+
summary, param_descs, return_desc = self.parse_docstring(class_doc)
|
92
|
+
description = summary
|
93
|
+
if return_desc:
|
94
|
+
description += f"\n\nReturns: {return_desc}"
|
95
|
+
undocumented = [
|
96
|
+
name
|
97
|
+
for name, param in sig.parameters.items()
|
98
|
+
if name != "self" and name not in param_descs
|
99
|
+
]
|
100
|
+
if undocumented:
|
101
|
+
raise ValueError(
|
102
|
+
f"Tool '{tool_name}' is missing docstring documentation for parameter(s): {', '.join(undocumented)}.\nParameter documentation must be provided in the Tool class docstring, not the method docstring."
|
103
|
+
)
|
104
|
+
return func, tool_name, sig, summary, param_descs, return_desc, description
|