janito 3.1.0__py3-none-any.whl → 3.2.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/README.md +3 -0
- janito/cli/chat_mode/bindings.py +14 -14
- janito/cli/chat_mode/session.py +6 -1
- janito/cli/chat_mode/shell/commands/security/allowed_sites.py +47 -33
- janito/cli/core/model_guesser.py +40 -24
- janito/cli/prompt_core.py +4 -3
- janito/i18n/it.py +46 -46
- janito/llm/agent.py +8 -5
- janito/llm/cancellation_manager.py +9 -8
- janito/llm/driver.py +1 -0
- janito/llm/enter_cancellation.py +58 -44
- janito/plugin_system/core_loader.py +76 -3
- janito/plugin_system/core_loader_fixed.py +79 -3
- janito/plugins/auto_loader.py +12 -11
- janito/plugins/core/filemanager/tools/create_file.py +2 -2
- janito/plugins/core_adapter.py +79 -3
- janito/plugins/discovery_core.py +14 -9
- janito/plugins/tools/core_tools_plugin.py +9 -10
- janito/plugins/tools/create_file.py +2 -2
- janito/providers/__init__.py +1 -0
- janito/providers/together/__init__.py +1 -0
- janito/providers/together/model_info.py +69 -0
- janito/providers/together/provider.py +108 -0
- janito/tools/loop_protection_decorator.py +114 -117
- {janito-3.1.0.dist-info → janito-3.2.0.dist-info}/METADATA +1 -1
- {janito-3.1.0.dist-info → janito-3.2.0.dist-info}/RECORD +30 -28
- janito/tools/function_adapter.py +0 -142
- {janito-3.1.0.dist-info → janito-3.2.0.dist-info}/WHEEL +0 -0
- {janito-3.1.0.dist-info → janito-3.2.0.dist-info}/entry_points.txt +0 -0
- {janito-3.1.0.dist-info → janito-3.2.0.dist-info}/licenses/LICENSE +0 -0
- {janito-3.1.0.dist-info → janito-3.2.0.dist-info}/top_level.txt +0 -0
@@ -1,143 +1,140 @@
|
|
1
1
|
import functools
|
2
2
|
import time
|
3
3
|
import threading
|
4
|
-
from typing import
|
5
|
-
from janito.tools.loop_protection import LoopProtection
|
6
|
-
from janito.tools.tool_use_tracker import normalize_path
|
7
|
-
|
4
|
+
from typing import Any, Tuple
|
8
5
|
|
9
6
|
# Global tracking for decorator-based loop protection
|
10
7
|
_decorator_call_tracker = {}
|
11
8
|
_decorator_call_tracker_lock = threading.Lock()
|
12
9
|
|
13
10
|
|
11
|
+
def _normalize_key_value(key_field: str, key_value: Any) -> Any:
|
12
|
+
"""Normalize key values, especially paths, so different representations map to the same key."""
|
13
|
+
if key_value is None:
|
14
|
+
return None
|
15
|
+
|
16
|
+
try:
|
17
|
+
if isinstance(key_field, str) and "path" in key_field.lower():
|
18
|
+
from janito.tools.tool_use_tracker import (
|
19
|
+
normalize_path as _norm, # reuse existing normalization
|
20
|
+
)
|
21
|
+
|
22
|
+
if isinstance(key_value, str):
|
23
|
+
return _norm(key_value)
|
24
|
+
if isinstance(key_value, (list, tuple)):
|
25
|
+
return tuple(_norm(v) if isinstance(v, str) else v for v in key_value)
|
26
|
+
except Exception:
|
27
|
+
# Best-effort normalization – fall back to original value
|
28
|
+
pass
|
29
|
+
|
30
|
+
return key_value
|
31
|
+
|
32
|
+
|
33
|
+
def _get_param_value(func, args, kwargs, key_field: str):
|
34
|
+
"""Extract the watched parameter value from args/kwargs using function signature."""
|
35
|
+
if key_field in kwargs:
|
36
|
+
return kwargs[key_field]
|
37
|
+
|
38
|
+
# Handle positional arguments by mapping to parameter names
|
39
|
+
if len(args) > 1: # args[0] is self
|
40
|
+
import inspect
|
41
|
+
|
42
|
+
try:
|
43
|
+
sig = inspect.signature(func)
|
44
|
+
param_names = list(sig.parameters.keys())
|
45
|
+
if key_field in param_names:
|
46
|
+
idx = param_names.index(key_field)
|
47
|
+
if idx < len(args):
|
48
|
+
return args[idx]
|
49
|
+
except Exception:
|
50
|
+
return None
|
51
|
+
|
52
|
+
return None
|
53
|
+
|
54
|
+
|
55
|
+
def _determine_operation_name(func, args, kwargs, key_field: str) -> str:
|
56
|
+
"""Build the operation name for rate limiting, optionally including a normalized key value."""
|
57
|
+
if key_field:
|
58
|
+
raw_value = _get_param_value(func, args, kwargs, key_field)
|
59
|
+
if raw_value is not None:
|
60
|
+
norm_value = _normalize_key_value(key_field, raw_value)
|
61
|
+
return f"{func.__name__}_{norm_value}"
|
62
|
+
return func.__name__
|
63
|
+
|
64
|
+
|
65
|
+
def _check_and_record(
|
66
|
+
op_name: str,
|
67
|
+
current_time: float,
|
68
|
+
time_window: float,
|
69
|
+
max_calls: int,
|
70
|
+
tool_instance: Any,
|
71
|
+
) -> Tuple[bool, str]:
|
72
|
+
"""Check loop limits for op_name and record the call. Returns (exceeded, message)."""
|
73
|
+
with _decorator_call_tracker_lock:
|
74
|
+
# Clean old timestamps
|
75
|
+
if op_name in _decorator_call_tracker:
|
76
|
+
_decorator_call_tracker[op_name] = [
|
77
|
+
ts
|
78
|
+
for ts in _decorator_call_tracker[op_name]
|
79
|
+
if current_time - ts <= time_window
|
80
|
+
]
|
81
|
+
|
82
|
+
# Check limit
|
83
|
+
if (
|
84
|
+
op_name in _decorator_call_tracker
|
85
|
+
and len(_decorator_call_tracker[op_name]) >= max_calls
|
86
|
+
):
|
87
|
+
if all(
|
88
|
+
current_time - ts <= time_window
|
89
|
+
for ts in _decorator_call_tracker[op_name]
|
90
|
+
):
|
91
|
+
msg = (
|
92
|
+
f"Loop protection: Too many {op_name} operations in a short time period "
|
93
|
+
f"({max_calls} calls in {time_window}s). Please try a different approach or wait before retrying."
|
94
|
+
)
|
95
|
+
if hasattr(tool_instance, "report_error"):
|
96
|
+
try:
|
97
|
+
tool_instance.report_error(msg)
|
98
|
+
except Exception:
|
99
|
+
pass
|
100
|
+
return True, msg
|
101
|
+
|
102
|
+
# Record this call
|
103
|
+
if op_name not in _decorator_call_tracker:
|
104
|
+
_decorator_call_tracker[op_name] = []
|
105
|
+
_decorator_call_tracker[op_name].append(current_time)
|
106
|
+
|
107
|
+
return False, ""
|
108
|
+
|
109
|
+
|
14
110
|
def protect_against_loops(
|
15
111
|
max_calls: int = 5, time_window: float = 10.0, key_field: str = None
|
16
112
|
):
|
17
113
|
"""
|
18
114
|
Decorator that adds loop protection to tool run methods.
|
19
115
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
When the configured limits are exceeded, the decorator raises a RuntimeError
|
25
|
-
with a descriptive message. This exception will propagate up the call stack
|
26
|
-
unless caught by a try/except block in the calling code.
|
27
|
-
|
28
|
-
The decorator works by:
|
29
|
-
1. Tracking the number of calls to the decorated function
|
30
|
-
2. Checking if the calls exceed the configured limits
|
31
|
-
3. Raising a RuntimeError if a potential loop is detected
|
32
|
-
4. Allowing the method to proceed normally if the operation is safe
|
33
|
-
|
34
|
-
Args:
|
35
|
-
max_calls (int): Maximum number of calls allowed within the time window.
|
36
|
-
Defaults to 5 calls.
|
37
|
-
time_window (float): Time window in seconds for detecting excessive calls.
|
38
|
-
Defaults to 10.0 seconds.
|
39
|
-
key_field (str, optional): The parameter name to use for key matching instead of function name.
|
40
|
-
If provided, the decorator will track calls based on the value of this
|
41
|
-
parameter rather than the function name. Useful for tools that operate
|
42
|
-
on specific files or resources.
|
43
|
-
|
44
|
-
Example:
|
45
|
-
>>> @protect_against_loops(max_calls=3, time_window=5.0)
|
46
|
-
>>> def run(self, path: str) -> str:
|
47
|
-
>>> # Implementation here
|
48
|
-
>>> pass
|
49
|
-
|
50
|
-
>>> @protect_against_loops(max_calls=10, time_window=30.0)
|
51
|
-
>>> def run(self, file_paths: list) -> str:
|
52
|
-
>>> # Implementation here
|
53
|
-
>>> pass
|
54
|
-
|
55
|
-
>>> @protect_against_loops(max_calls=5, time_window=10.0, key_field='path')
|
56
|
-
>>> def run(self, path: str) -> str:
|
57
|
-
>>> # This will track calls per unique path value
|
58
|
-
>>> pass
|
59
|
-
|
60
|
-
Note:
|
61
|
-
When loop protection is triggered, a RuntimeError will be raised with a
|
62
|
-
descriptive message. This exception will propagate up the call stack
|
63
|
-
unless caught by a try/except block in the calling code.
|
116
|
+
Tracks calls within a sliding time window and prevents excessive repeated operations.
|
117
|
+
When key_field is provided, the limit is applied per unique normalized value of that parameter
|
118
|
+
(e.g., per-path protection for file tools).
|
64
119
|
"""
|
65
120
|
|
66
121
|
def decorator(func):
|
67
122
|
@functools.wraps(func)
|
68
123
|
def wrapper(*args, **kwargs):
|
69
|
-
#
|
124
|
+
# Methods should always have self; if not, execute directly.
|
70
125
|
if not args:
|
71
|
-
# This shouldn't happen in normal usage as methods need self
|
72
126
|
return func(*args, **kwargs)
|
73
127
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
try:
|
85
|
-
sig = inspect.signature(func)
|
86
|
-
param_names = list(sig.parameters.keys())
|
87
|
-
if key_field in param_names:
|
88
|
-
field_index = param_names.index(key_field)
|
89
|
-
if field_index < len(args):
|
90
|
-
key_value = args[field_index]
|
91
|
-
except (ValueError, TypeError):
|
92
|
-
pass
|
93
|
-
|
94
|
-
if key_value is not None:
|
95
|
-
op_name = f"{func.__name__}_{key_value}"
|
96
|
-
else:
|
97
|
-
op_name = func.__name__
|
98
|
-
else:
|
99
|
-
# Use the function name as the operation name
|
100
|
-
op_name = func.__name__
|
101
|
-
|
102
|
-
# Check call limits
|
103
|
-
current_time = time.time()
|
104
|
-
|
105
|
-
with _decorator_call_tracker_lock:
|
106
|
-
# Clean up old entries outside the time window
|
107
|
-
if op_name in _decorator_call_tracker:
|
108
|
-
_decorator_call_tracker[op_name] = [
|
109
|
-
timestamp
|
110
|
-
for timestamp in _decorator_call_tracker[op_name]
|
111
|
-
if current_time - timestamp <= time_window
|
112
|
-
]
|
113
|
-
|
114
|
-
# Check if we're exceeding the limit
|
115
|
-
if op_name in _decorator_call_tracker:
|
116
|
-
if len(_decorator_call_tracker[op_name]) >= max_calls:
|
117
|
-
# Check if all recent calls are within the time window
|
118
|
-
if all(
|
119
|
-
current_time - timestamp <= time_window
|
120
|
-
for timestamp in _decorator_call_tracker[op_name]
|
121
|
-
):
|
122
|
-
# Return loop protection message as string instead of raising exception
|
123
|
-
error_msg = f"Loop protection: Too many {op_name} operations in a short time period ({max_calls} calls in {time_window}s). Please try a different approach or wait before retrying."
|
124
|
-
|
125
|
-
# Try to report the error through the tool's reporting mechanism
|
126
|
-
tool_instance = args[0] if args else None
|
127
|
-
if hasattr(tool_instance, "report_error"):
|
128
|
-
try:
|
129
|
-
tool_instance.report_error(error_msg)
|
130
|
-
except Exception:
|
131
|
-
pass # If reporting fails, we still return the message
|
132
|
-
|
133
|
-
return error_msg
|
134
|
-
|
135
|
-
# Record this call
|
136
|
-
if op_name not in _decorator_call_tracker:
|
137
|
-
_decorator_call_tracker[op_name] = []
|
138
|
-
_decorator_call_tracker[op_name].append(current_time)
|
139
|
-
|
140
|
-
# Proceed with the original function
|
128
|
+
op_name = _determine_operation_name(func, args, kwargs, key_field)
|
129
|
+
exceeded, msg = _check_and_record(
|
130
|
+
op_name=op_name,
|
131
|
+
current_time=time.time(),
|
132
|
+
time_window=time_window,
|
133
|
+
max_calls=max_calls,
|
134
|
+
tool_instance=args[0],
|
135
|
+
)
|
136
|
+
if exceeded:
|
137
|
+
return msg
|
141
138
|
return func(*args, **kwargs)
|
142
139
|
|
143
140
|
return wrapper
|
@@ -1,4 +1,4 @@
|
|
1
|
-
janito/README.md,sha256=
|
1
|
+
janito/README.md,sha256=Wrt6pMVT9UaXsFpoE3m9hgn28OAHWhkZ_vwWTNcSH8Q,4947
|
2
2
|
janito/__init__.py,sha256=a0pFui3A_AfWJiUfg93yE-Vf4868bqG3y9yg2fkTIuY,244
|
3
3
|
janito/__main__.py,sha256=lPQ8kAyYfyeS1KopmJ8EVY5g1YswlIqCS615mM_B_rM,70
|
4
4
|
janito/_version.py,sha256=PtAVr2K9fOS5sv6aXzmcb7UaR5NLGMFOofL7Ndjh75o,2344
|
@@ -30,17 +30,17 @@ janito/cli/config.py,sha256=HkZ14701HzIqrvaNyDcDhGlVHfpX_uHlLp2rHmhRm_k,872
|
|
30
30
|
janito/cli/console.py,sha256=gJolqzWL7jEPLxeuH-CwBDRFpXt976KdZOEAB2tdBDs,64
|
31
31
|
janito/cli/main.py,sha256=s5odou0txf8pzTf1ADk2yV7T5m8B6cejJ81e7iu776U,312
|
32
32
|
janito/cli/main_cli.py,sha256=_OOQqeLiqvmYeB_928Av920Gk43rbXecMIOTL6JeT0Y,16674
|
33
|
-
janito/cli/prompt_core.py,sha256=
|
33
|
+
janito/cli/prompt_core.py,sha256=GSpq0_J-PS455SPkF-nCe9WtOQqseR08DWN7XhGIJXA,12044
|
34
34
|
janito/cli/prompt_handler.py,sha256=SnPTlL64noeAMGlI08VBDD5IDD8jlVMIYA4-fS8zVLg,215
|
35
35
|
janito/cli/prompt_setup.py,sha256=s48gvNfZhKjsEhf4EzL1tKIGm4wDidPMDvlM6TAPYes,2116
|
36
36
|
janito/cli/rich_terminal_reporter.py,sha256=Hitf5U13gncad4GPVAcDMfdSwlfzQzOn9KdeX4TjTWU,6806
|
37
37
|
janito/cli/utils.py,sha256=plCQiDKIf3V8mFhhX5H9-MF2W86i-xRdWf8Xi117Z0w,677
|
38
38
|
janito/cli/verbose_output.py,sha256=wY_B4of5e8Vv7w1fRwOZzNGU2JqbMdcFnGjtEr4hLus,7686
|
39
|
-
janito/cli/chat_mode/bindings.py,sha256=
|
39
|
+
janito/cli/chat_mode/bindings.py,sha256=vyaT5k454dSqxXPFWW0bOCHwBDCpTuxhcAu0AsDO-Gg,2013
|
40
40
|
janito/cli/chat_mode/chat_entry.py,sha256=RFdPd23jsA2DMHRacpjAdwI_1dFBaWrtnwyQEgb2fHA,475
|
41
41
|
janito/cli/chat_mode/prompt_style.py,sha256=vsqQ9xxmrYjj1pWuVe9CayQf39fo2EIXrkKPkflSVn4,805
|
42
42
|
janito/cli/chat_mode/script_runner.py,sha256=WFTFVWzg_VQrD2Ujj02XWjscfGgHwmjBeRxaEjWw9ps,6505
|
43
|
-
janito/cli/chat_mode/session.py,sha256=
|
43
|
+
janito/cli/chat_mode/session.py,sha256=QYJ2wpA3IlB756ooFXTSkUVa5mOWgllAkONG3Dgqm8I,19002
|
44
44
|
janito/cli/chat_mode/toolbar.py,sha256=SzdWAJdcY1g2rTPZCPL6G5X8jO6ZQYjwko2-nw54_nU,3397
|
45
45
|
janito/cli/chat_mode/shell/autocomplete.py,sha256=lE68MaVaodbA2VfUM0_YLqQVLBJAE_BJsd5cMtwuD-g,793
|
46
46
|
janito/cli/chat_mode/shell/commands.bak.zip,sha256=I7GFjXg2ORT5NzFpicH1vQ3kchhduQsZinzqo0xO8wU,74238
|
@@ -73,7 +73,7 @@ janito/cli/chat_mode/shell/commands/utility.py,sha256=K982P-UwgPLzpEvSuSBGwiQ3zC
|
|
73
73
|
janito/cli/chat_mode/shell/commands/verbose.py,sha256=HDTe0NhdcjBuhh-eJSW8iLPDeeBO95K5iSDAMAljxa4,953
|
74
74
|
janito/cli/chat_mode/shell/commands/write.py,sha256=NHPj2xe8icUBcpxALIoZZ1zAsX6bhBFqBhnQPqq7fHs,2341
|
75
75
|
janito/cli/chat_mode/shell/commands/security/__init__.py,sha256=od-vkuI7LqmUqz2Q42YToWauRM6IPHGeNj14867yIgM,50
|
76
|
-
janito/cli/chat_mode/shell/commands/security/allowed_sites.py,sha256=
|
76
|
+
janito/cli/chat_mode/shell/commands/security/allowed_sites.py,sha256=pmyQnLD7Do_CaIITDlZ9Md7PqSpQAhRdnnVMMdQVFGk,3679
|
77
77
|
janito/cli/chat_mode/shell/session/__init__.py,sha256=uTYE_QpZFEn7v9QE5o1LdulpCWa9vmk0OsefbBGWg_c,37
|
78
78
|
janito/cli/chat_mode/shell/session/history.py,sha256=tYav6GgjAZkvWhlI_rfG6OArNqW6Wn2DTv39Hb20QYc,1262
|
79
79
|
janito/cli/chat_mode/shell/session/manager.py,sha256=MwD9reHsRaly0CyRB-S1JJ0wPKz2g8Xdj2VvlU35Hgc,1001
|
@@ -96,7 +96,7 @@ janito/cli/cli_commands/show_system_prompt.py,sha256=WQclY_bmJrHbIBRU1qx1WV4Vyoo
|
|
96
96
|
janito/cli/core/__init__.py,sha256=YH95fhgY9yBX8RgqX9dSrEkl4exjV0T4rbmJ6xUpG-Y,196
|
97
97
|
janito/cli/core/event_logger.py,sha256=1X6lR0Ax7AgF8HlPWFoY5Ystuu7Bh4ooTo78vXzeGB0,2008
|
98
98
|
janito/cli/core/getters.py,sha256=53umV7aab6WrmcCle8WqU2aYnww7a7IiqtM1YZN0YvE,3016
|
99
|
-
janito/cli/core/model_guesser.py,sha256=
|
99
|
+
janito/cli/core/model_guesser.py,sha256=557c0FckGIVmPYCgp2hBNsjsmHAiORtoxvLTKnOk8kg,2082
|
100
100
|
janito/cli/core/runner.py,sha256=gi8xke6re9AoHHNCivV50i0eUAliw8QTUdXyqMkMplM,9044
|
101
101
|
janito/cli/core/setters.py,sha256=zjSUxy6iUzcrmEunFk7dA90KqbMaq2O7LTGP8wn2HxA,5378
|
102
102
|
janito/cli/core/unsetters.py,sha256=FEw9gCt0vRvoCt0kRSNfVB2tzi_TqppJIx2nHPP59-k,2012
|
@@ -117,35 +117,35 @@ janito/event_bus/event.py,sha256=MtgcBPD7cvCuubiLIyo-BWcsNSO-941HLk6bScHTJtQ,427
|
|
117
117
|
janito/event_bus/handler.py,sha256=RhBtT1E48VEM2-k8u3HYsESw7VX5qAgiB8ZTJeKXhHc,1322
|
118
118
|
janito/event_bus/queue_bus.py,sha256=l4phun3pxXxi8ZlIq8ChYaiYDVO1PZeXoOzyi3vyu20,1558
|
119
119
|
janito/i18n/__init__.py,sha256=6zCIu6pSQpoMJvIRK9oOD3pkzbNeJik3lFDXse0X6ag,994
|
120
|
-
janito/i18n/it.py,sha256=
|
120
|
+
janito/i18n/it.py,sha256=57xW4YE1kkMz8oNO5fBqK_YllWkHT97asaThDsGsBdM,4097
|
121
121
|
janito/i18n/messages.py,sha256=fBuwOTFoygyHPkYphm6Y0r1iE8497Z4iryVAmPhMEkg,1851
|
122
122
|
janito/i18n/pt.py,sha256=NlTgpDSftUfFG7FGbs7TK54vQlJVMyaZDHGcWjelwMc,4168
|
123
123
|
janito/llm/README.md,sha256=6GRqCu_a9va5HCB1YqNqbshyWKFyAGlnXugrjom-xj8,1213
|
124
124
|
janito/llm/__init__.py,sha256=dpyVH51qVRCw-PDyAFLAxq0zd4jl5MDcuV6Cri0D-dQ,134
|
125
|
-
janito/llm/agent.py,sha256=
|
125
|
+
janito/llm/agent.py,sha256=R3jzva-Er5W1TmHXHf9APxYB51H0z1vxOF6jVda7m7U,21940
|
126
126
|
janito/llm/auth.py,sha256=8Dl_orUEPhn2X6XjkO2Nr-j1HFT2YDxk1qJl9hSFI88,2286
|
127
127
|
janito/llm/auth_utils.py,sha256=mcPWT2p2kGMhvR9QsHqk84utDejPJh3uyjrDOJ0dKYA,1068
|
128
|
-
janito/llm/cancellation_manager.py,sha256=
|
129
|
-
janito/llm/driver.py,sha256=
|
128
|
+
janito/llm/cancellation_manager.py,sha256=u-hzuuVjQmLV15YPp3cZdF8KmyQLoLv8P5ZTvgYWr7o,2194
|
129
|
+
janito/llm/driver.py,sha256=iVCYGUE5bqa_MTF6p_l2VUl_2y_-IOStNeC0IWfkA3I,10394
|
130
130
|
janito/llm/driver_config.py,sha256=OW0ae49EfgKDqaThuDjZBiaN78voNzwiZ6szERMqJos,1406
|
131
131
|
janito/llm/driver_config_builder.py,sha256=BvWGx7vaBR5NyvPY1XNAP3lAgo1uf-T25CSsIo2kkCU,1401
|
132
132
|
janito/llm/driver_input.py,sha256=Zq7IO4KdQPUraeIo6XoOaRy1IdQAyYY15RQw4JU30uA,389
|
133
|
-
janito/llm/enter_cancellation.py,sha256=
|
133
|
+
janito/llm/enter_cancellation.py,sha256=sE6yadsFGnKDQVBKenv1sF96wIcAP2LqymiUFJBlijU,3312
|
134
134
|
janito/llm/message_parts.py,sha256=QY_0kDjaxdoErDgKPRPv1dNkkYJuXIBmHWNLiOEKAH4,1365
|
135
135
|
janito/llm/model.py,sha256=EioBkdgn8hJ0iQaKN-0KbXlsrk3YKmwR9IbvoEbdVTE,1159
|
136
136
|
janito/llm/provider.py,sha256=3FbhQPrWBSEoIdIi-5DWIh0DD_CM570EFf1NcuGyGko,7961
|
137
137
|
janito/plugin_system/__init__.py,sha256=HoTBUooSTEsp_1FaBn-5BmzZX_p_982e4T_fCOeUlD0,290
|
138
138
|
janito/plugin_system/base.py,sha256=Z0PSIj7R-hAKOeCSXC2JyBqm4rlsJoZSqkqxLe-juks,4346
|
139
|
-
janito/plugin_system/core_loader.py,sha256=
|
140
|
-
janito/plugin_system/core_loader_fixed.py,sha256=
|
139
|
+
janito/plugin_system/core_loader.py,sha256=3zhKPWWSFlThzaRTLjGDPI_DVNRafMP5LZ5r7ei6Jo0,6843
|
140
|
+
janito/plugin_system/core_loader_fixed.py,sha256=3JZnEkM4i0x4k3SJhomtVevmNl4uWhozhVyh6rcMtvE,7159
|
141
141
|
janito/plugins/__init__.py,sha256=q-z28oV-0BaagZ43f__qeg13R9oA7kK7XnVEUHNRZbs,910
|
142
|
-
janito/plugins/auto_loader.py,sha256
|
142
|
+
janito/plugins/auto_loader.py,sha256=-uVDTKQToGCw1nqwAxrt4IDvgP3z3pvZoC5EXFWNm_k,2288
|
143
143
|
janito/plugins/auto_loader_fixed.py,sha256=3JnGDp1enombEHsR8spRDpVrD6tSPdudysWvhyuk5Ec,2304
|
144
144
|
janito/plugins/builtin.py,sha256=kbIOVmqucJKyISC5kWcgda_6IhHGA6yWoxUghc1Qtk0,3409
|
145
145
|
janito/plugins/config.py,sha256=ex5f1XsKPEgIO4DgJCohPzMKAQoUdx1OdSVU0FlSr5o,2331
|
146
|
-
janito/plugins/core_adapter.py,sha256=
|
146
|
+
janito/plugins/core_adapter.py,sha256=tFi9VYvb15n3yUGDF7ihALbjL7pz_PDeeEgu_3JFqTQ,4430
|
147
147
|
janito/plugins/discovery.py,sha256=IGQAFPzzzZjlpMzPNdChD7ZJrCYN8QmvXPsvLBOSSjY,10120
|
148
|
-
janito/plugins/discovery_core.py,sha256=
|
148
|
+
janito/plugins/discovery_core.py,sha256=3pL8kinyFuz1owqIpZDYYIvj3RrJVJHulUa36Aqsc6g,1617
|
149
149
|
janito/plugins/example_plugin.py,sha256=1B0PYOSFsb2ya2VCwHr1pMJC9ivUJ7t9TtQkc8lkaGU,3136
|
150
150
|
janito/plugins/manager.py,sha256=R1B-2sUD5YFLOTnp4Pfx1wZ-3Hzff--PqaOJHfllc5g,8155
|
151
151
|
janito/plugins/core/__init__.py,sha256=74-nOHG97Jo7cSm_sOLwYYhS0maB1kgKdB69-bmi03k,144
|
@@ -164,7 +164,7 @@ janito/plugins/core/codeanalyzer/tools/search_text/traverse_directory.py,sha256=
|
|
164
164
|
janito/plugins/core/filemanager/__init__.py,sha256=waUhGQ2OL59Ooes4cQOOlQdBsFQSIffevJkcZq_kaCQ,3241
|
165
165
|
janito/plugins/core/filemanager/tools/copy_file.py,sha256=SBJm19Ipe5dqRE1Mxl6JSrn4bNmfObVnDr5b1mcEu6c,3682
|
166
166
|
janito/plugins/core/filemanager/tools/create_directory.py,sha256=LxwqQEsnOrEphCIoaMRRx9P9bu0MzidP3Fc5q6letxc,2584
|
167
|
-
janito/plugins/core/filemanager/tools/create_file.py,sha256=
|
167
|
+
janito/plugins/core/filemanager/tools/create_file.py,sha256=MDMTt3ocp1Ejo3vo7K5Ht2cMPObXiQTr5OTtLv9qOuw,3821
|
168
168
|
janito/plugins/core/filemanager/tools/delete_text_in_file.py,sha256=uEeedRxXAR7_CqUc_qhbEdM0OzRi_pgnP-iDjs2Zvjk,5087
|
169
169
|
janito/plugins/core/filemanager/tools/find_files.py,sha256=Zbag3aP34vc7ffJh8bOqAwXj3KiZhV--uzTVHtNb-fI,6250
|
170
170
|
janito/plugins/core/filemanager/tools/move_file.py,sha256=LMGm8bn3NNyIPJG4vrlO09smXQcgzA09EwoooZxkIA8,4695
|
@@ -203,9 +203,9 @@ janito/plugins/dev/visualization/tools/read_chart.py,sha256=qQebp_MEE_x2AL_pl85u
|
|
203
203
|
janito/plugins/tools/__init__.py,sha256=vNqUVWA0guwAYuPgdmiDsjmgibj9siP0e61pfTHZ8-8,271
|
204
204
|
janito/plugins/tools/ask_user.py,sha256=7Wgl_9XEPWty3qTG_xcQdwJWypXRorMv3WYM_AZDrBY,4050
|
205
205
|
janito/plugins/tools/copy_file.py,sha256=A0LxkN9b4eDBD7Ww_4LO412kldbx-DlrUELUB-27jOk,3672
|
206
|
-
janito/plugins/tools/core_tools_plugin.py,sha256=
|
206
|
+
janito/plugins/tools/core_tools_plugin.py,sha256=QgRE3KcbF-KgRR5y-ADYeuTTLDlenxuKM-68wliVfbs,2683
|
207
207
|
janito/plugins/tools/create_directory.py,sha256=f8fccqwRR3xj_IJ7KZacsxBo2k754bLgVyAefC4jsnI,2574
|
208
|
-
janito/plugins/tools/create_file.py,sha256=
|
208
|
+
janito/plugins/tools/create_file.py,sha256=8yv1Mkxsg9KCE7o8B2e0fQdvqMcmBHohRV2z5AQ8fIs,6417
|
209
209
|
janito/plugins/tools/decorators.py,sha256=BRAjjo4NF4_JxwPPVrrF2wtzsJXuZJkwv_QhZgPFMS4,382
|
210
210
|
janito/plugins/tools/delete_text_in_file.py,sha256=nZb-QuJopA3NDfOW3BEsG6Aj9EaMlfpuEYiG9aGp4z4,5070
|
211
211
|
janito/plugins/tools/fetch_url.py,sha256=hqtllaqx5rgZ-5wAih6-R1tvX5sIFUHy3DTP68JImQM,18202
|
@@ -257,7 +257,7 @@ janito/plugins/web/webtools/__init__.py,sha256=vGFtbZvV2DnooPmw4B8hHd0UgpVfNugLs
|
|
257
257
|
janito/plugins/web/webtools/tools/fetch_url.py,sha256=VjB89FjLNrqLmOVL6wm1RHyixB3n-RViC0DJjW33iRM,17804
|
258
258
|
janito/plugins/web/webtools/tools/open_html_in_browser.py,sha256=XqICIwVx5vEE77gHkaNAC-bAeEEy0DBmDksATiL-sRY,2101
|
259
259
|
janito/plugins/web/webtools/tools/open_url.py,sha256=V3Sv7iLynUreLjVl5-bl-XFH_LzpTeBrS8-cvzp_7rM,1552
|
260
|
-
janito/providers/__init__.py,sha256=
|
260
|
+
janito/providers/__init__.py,sha256=LZcyllhmGyOXQ8duQA2Qbg0fSrahog5ATNZppNOxFK0,571
|
261
261
|
janito/providers/dashscope.bak.zip,sha256=BwXxRmZreEivvRtmqbr5BR62IFVlNjAf4y6DrF2BVJo,5998
|
262
262
|
janito/providers/registry.py,sha256=Ygwv9eVrTXOKhv0EKxSWQXO5WMHvajWE2Q_Lc3p7dKo,730
|
263
263
|
janito/providers/alibaba/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -290,6 +290,9 @@ janito/providers/openai/__init__.py,sha256=f0m16-sIqScjL9Mp4A0CQBZx6H3PTEy0cnE08
|
|
290
290
|
janito/providers/openai/model_info.py,sha256=VTkq3xcx2vk0tXlFVHQxKeFzl-DL1T1J2elVOEwCdHI,4265
|
291
291
|
janito/providers/openai/provider.py,sha256=PPr_qmSe5GyysnZCxhjeUVhE2LWKjKOSRel-8aaxq_U,4761
|
292
292
|
janito/providers/openai/schema_generator.py,sha256=hTqeLcPTR8jeKn5DUUpo7b-EZ-V-g1WwXiX7MbHnFzE,2234
|
293
|
+
janito/providers/together/__init__.py,sha256=8JguGMgLW_QUJ-G6VIypp_Uq6avi3LGwKWpEiyGRWOU,33
|
294
|
+
janito/providers/together/model_info.py,sha256=4EsluZgPfZW68Uc9o5vDnUmo-hQAGIs5eTDWuR24kPg,2407
|
295
|
+
janito/providers/together/provider.py,sha256=BiM8p8rlqPem_PHdOyXq08J3LZFrAKtP7PDqDSToLdI,3847
|
293
296
|
janito/providers/zai/__init__.py,sha256=qtIr9_QBFaXG8xB6cRDGhS7se6ir11CWseI9azLMRBo,24
|
294
297
|
janito/providers/zai/model_info.py,sha256=ldwD8enpxXv1G-YsDw4YJn31YsVueQ4vj5HgoYvnPxo,1183
|
295
298
|
janito/providers/zai/provider.py,sha256=aKqDTdcwWk-FT70wTbTrTzlWx2NwRWkLoB64upiliU8,5066
|
@@ -304,11 +307,10 @@ janito/tools/__init__.py,sha256=PoMIw_JgsEGP5SO77mqsZFl0Z-p2W2WnyHaaAKSnirk,1961
|
|
304
307
|
janito/tools/base.py,sha256=R38A9xWYh3JRYZMDSom2d1taNDy9J7HpLbZo9X2wH_o,316
|
305
308
|
janito/tools/cli_initializer.py,sha256=KJbUL6_iAsaeBZl_AVrdtczSZRQBJ9RPZufHJVKwAtU,2632
|
306
309
|
janito/tools/disabled_tools.py,sha256=Tx__16wtMWZ9z34cYLdH1gukwot5MCL-9kLjd5MPX6Y,2110
|
307
|
-
janito/tools/function_adapter.py,sha256=kjU15jy2gLmKw__BRFe99lRrLCXoHdcgVMFf2W4LEw0,4870
|
308
310
|
janito/tools/initialize.py,sha256=BSwzCPCmis2n4q5W3tWBEr4MgVS4tAwBjfKoNM4CefI,2002
|
309
311
|
janito/tools/inspect_registry.py,sha256=Jo7PrMPRKLuR-j_mBAk9PBcTzeJf1eQrS1ChGofgQk0,538
|
310
312
|
janito/tools/loop_protection.py,sha256=WQ2Cqt459vXvrO0T1EqkEHynHlRkPzfaC83RSmXzjkM,4718
|
311
|
-
janito/tools/loop_protection_decorator.py,sha256=
|
313
|
+
janito/tools/loop_protection_decorator.py,sha256=ZCccrg24B_titDeOhaEORPq8wnRyLf1bdb8YEHK25lo,4957
|
312
314
|
janito/tools/outline_file.bak.zip,sha256=EeI2cBXCwTdWVgJDNiroxKeYlkjwo6NLKeXz3J-2iZI,15607
|
313
315
|
janito/tools/path_security.py,sha256=40b0hV0X3449Dht93A04Q3c9AYSsBQsBFy2BjzM83lA,8214
|
314
316
|
janito/tools/path_utils.py,sha256=Rg5GE4kiu7rky6I2KTtivW6wPXzc9Qmq0_lOjwkPYlI,832
|
@@ -325,9 +327,9 @@ janito/tools/url_whitelist.py,sha256=0CPLkHTp5HgnwgjxwgXnJmwPeZQ30q4j3YjW59hiUUE
|
|
325
327
|
janito/tools/adapters/__init__.py,sha256=H25uYM2ETMLKpKPPEPAu9-AFjxkKfSyfx3pnoXSQlVA,255
|
326
328
|
janito/tools/adapters/local/__init__.py,sha256=1DVnka4iEQp8Xrs7rJVVx45fPpuVahjTFmuJhv-gN8s,249
|
327
329
|
janito/tools/adapters/local/adapter.py,sha256=u4nLHTaYdwZXMi1J8lsKvlG6rOmdq9xjey_3zeyCG4k,8707
|
328
|
-
janito-3.
|
329
|
-
janito-3.
|
330
|
-
janito-3.
|
331
|
-
janito-3.
|
332
|
-
janito-3.
|
333
|
-
janito-3.
|
330
|
+
janito-3.2.0.dist-info/licenses/LICENSE,sha256=dXV4fOF2ZErugtN8l_Nrj5tsRTYgtjE3cgiya0UfBio,11356
|
331
|
+
janito-3.2.0.dist-info/METADATA,sha256=FgU9kTrodtpQrm-Ky5X_IArx59u80QV--sW2HHTmw1M,2265
|
332
|
+
janito-3.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
333
|
+
janito-3.2.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
|
334
|
+
janito-3.2.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
|
335
|
+
janito-3.2.0.dist-info/RECORD,,
|
janito/tools/function_adapter.py
DELETED
@@ -1,142 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Function-to-Tool adapter for core plugins.
|
3
|
-
|
4
|
-
This module provides a way to wrap function-based tools into proper ToolBase classes.
|
5
|
-
"""
|
6
|
-
|
7
|
-
import inspect
|
8
|
-
from typing import Any, Dict, List, Optional, get_type_hints
|
9
|
-
from janito.tools.tool_base import ToolBase, ToolPermissions
|
10
|
-
|
11
|
-
|
12
|
-
class FunctionToolAdapter(ToolBase):
|
13
|
-
"""Adapter that wraps a function into a ToolBase class."""
|
14
|
-
|
15
|
-
def __init__(self, func, tool_name: str = None, description: str = None):
|
16
|
-
super().__init__()
|
17
|
-
self._func = func
|
18
|
-
self.tool_name = tool_name or getattr(func, "tool_name", func.__name__)
|
19
|
-
self._description = description or func.__doc__ or f"Tool: {self.tool_name}"
|
20
|
-
self.permissions = ToolPermissions(read=True, write=True, execute=True)
|
21
|
-
|
22
|
-
def run(
|
23
|
-
self,
|
24
|
-
path: str = None,
|
25
|
-
content: str = None,
|
26
|
-
overwrite: bool = None,
|
27
|
-
sources: str = None,
|
28
|
-
target: str = None,
|
29
|
-
recursive: bool = None,
|
30
|
-
from_line: int = None,
|
31
|
-
to_line: int = None,
|
32
|
-
search_text: str = None,
|
33
|
-
replacement_text: str = None,
|
34
|
-
use_regex: bool = None,
|
35
|
-
case_sensitive: bool = None,
|
36
|
-
max_depth: int = None,
|
37
|
-
include_gitignored: bool = None,
|
38
|
-
timeout: int = None,
|
39
|
-
require_confirmation: bool = None,
|
40
|
-
data: dict = None,
|
41
|
-
title: str = None,
|
42
|
-
width: int = None,
|
43
|
-
height: int = None,
|
44
|
-
query: str = None,
|
45
|
-
paths: str = None,
|
46
|
-
src_path: str = None,
|
47
|
-
dest_path: str = None,
|
48
|
-
code: str = None,
|
49
|
-
pattern: str = None,
|
50
|
-
) -> str:
|
51
|
-
"""Execute the wrapped function."""
|
52
|
-
# Build kwargs from non-None parameters
|
53
|
-
import inspect
|
54
|
-
|
55
|
-
sig = inspect.signature(self._func)
|
56
|
-
filtered_kwargs = {}
|
57
|
-
|
58
|
-
# Map parameter names to their actual values
|
59
|
-
param_map = {
|
60
|
-
"path": path,
|
61
|
-
"content": content,
|
62
|
-
"overwrite": overwrite,
|
63
|
-
"sources": sources,
|
64
|
-
"target": target,
|
65
|
-
"recursive": recursive,
|
66
|
-
"from_line": from_line,
|
67
|
-
"to_line": to_line,
|
68
|
-
"search_text": search_text,
|
69
|
-
"replacement_text": replacement_text,
|
70
|
-
"use_regex": use_regex,
|
71
|
-
"case_sensitive": case_sensitive,
|
72
|
-
"max_depth": max_depth,
|
73
|
-
"include_gitignored": include_gitignored,
|
74
|
-
"timeout": timeout,
|
75
|
-
"require_confirmation": require_confirmation,
|
76
|
-
"data": data,
|
77
|
-
"title": title,
|
78
|
-
"width": width,
|
79
|
-
"height": height,
|
80
|
-
"query": query,
|
81
|
-
"paths": paths,
|
82
|
-
"src_path": src_path,
|
83
|
-
"dest_path": dest_path,
|
84
|
-
"code": code,
|
85
|
-
"pattern": pattern,
|
86
|
-
}
|
87
|
-
|
88
|
-
# Only include parameters that exist in the function signature
|
89
|
-
for name, param in sig.parameters.items():
|
90
|
-
if name in param_map and param_map[name] is not None:
|
91
|
-
filtered_kwargs[name] = param_map[name]
|
92
|
-
|
93
|
-
result = self._func(**filtered_kwargs)
|
94
|
-
return str(result) if result is not None else ""
|
95
|
-
|
96
|
-
def get_signature(self) -> Dict[str, Any]:
|
97
|
-
"""Get function signature for documentation."""
|
98
|
-
sig = inspect.signature(self._func)
|
99
|
-
type_hints = get_type_hints(self._func)
|
100
|
-
|
101
|
-
params = {}
|
102
|
-
for name, param in sig.parameters.items():
|
103
|
-
param_info = {
|
104
|
-
"type": str(type_hints.get(name, Any)),
|
105
|
-
"default": (
|
106
|
-
param.default if param.default != inspect.Parameter.empty else None
|
107
|
-
),
|
108
|
-
"required": param.default == inspect.Parameter.empty,
|
109
|
-
}
|
110
|
-
params[name] = param_info
|
111
|
-
|
112
|
-
return {
|
113
|
-
"name": self.tool_name,
|
114
|
-
"description": self._description,
|
115
|
-
"parameters": params,
|
116
|
-
"return_type": str(type_hints.get("return", Any)),
|
117
|
-
}
|
118
|
-
|
119
|
-
|
120
|
-
def create_function_tool(func, tool_name: str = None, description: str = None) -> type:
|
121
|
-
"""
|
122
|
-
Create a ToolBase class from a function.
|
123
|
-
|
124
|
-
Args:
|
125
|
-
func: The function to wrap
|
126
|
-
tool_name: Optional custom tool name
|
127
|
-
description: Optional custom description
|
128
|
-
|
129
|
-
Returns:
|
130
|
-
A ToolBase subclass that wraps the function
|
131
|
-
"""
|
132
|
-
# Resolve tool_name in outer scope
|
133
|
-
resolved_tool_name = tool_name or getattr(func, "tool_name", func.__name__)
|
134
|
-
|
135
|
-
class DynamicFunctionTool(FunctionToolAdapter):
|
136
|
-
permissions = ToolPermissions(read=True, write=True, execute=True)
|
137
|
-
tool_name = resolved_tool_name
|
138
|
-
|
139
|
-
def __init__(self):
|
140
|
-
super().__init__(func, DynamicFunctionTool.tool_name, description)
|
141
|
-
|
142
|
-
return DynamicFunctionTool
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|