diff --git a/navi/tools/filesystem.py b/navi/tools/filesystem.py index 0dedabc..5b287da 100644 --- a/navi/tools/filesystem.py +++ b/navi/tools/filesystem.py @@ -75,6 +75,8 @@ inside user_data//. This prevents users from accessing each other's files or random OS directories. """ + if not path_str or path_str.strip() == "": + return None try: p = Path(path_str) except Exception: @@ -368,6 +370,12 @@ path = _check_path(raw_path) if path is None: + if not raw_path or raw_path.strip() == "": + return ToolResult( + success=False, + output="'path' is required. For 'write' action use 'path' (not 'destination').", + error="missing_path", + ) return ToolResult( success=False, output=( diff --git a/navi/tools/terminal.py b/navi/tools/terminal.py index 94264c2..4b1d22b 100644 --- a/navi/tools/terminal.py +++ b/navi/tools/terminal.py @@ -23,7 +23,8 @@ from .base import Tool, ToolResult, current_user_id, current_user_role -_TIMEOUT = 300 +_DEFAULT_TIMEOUT = 20 +_MAX_TIMEOUT = 300 _MAX_OUTPUT_CHARS = 5_000 # Substrings that make a command line dangerous for non-admin users. @@ -104,7 +105,7 @@ }, "timeout": { "type": "integer", - "description": f"Timeout in seconds (default {_TIMEOUT})", + "description": f"Timeout in seconds (default {_DEFAULT_TIMEOUT}, max {_MAX_TIMEOUT}). Set higher when installing packages or running long tasks.", }, }, "required": ["command"], @@ -113,7 +114,11 @@ async def execute(self, params: dict) -> ToolResult: command = params["command"].strip() working_dir = params.get("working_dir") or None - timeout = int(params.get("timeout") or _TIMEOUT) + raw_timeout = params.get("timeout") + if raw_timeout is not None: + timeout = max(1, min(int(raw_timeout), _MAX_TIMEOUT)) + else: + timeout = _DEFAULT_TIMEOUT if not command: return ToolResult(success=False, output="Empty command.", error="empty_command")