diff --git a/smb_tool.py b/smb_tool.py index ee65490..ba47acc 100644 --- a/smb_tool.py +++ b/smb_tool.py @@ -543,6 +543,328 @@ class Tools: await emitter.success_update(success) return result + + # ========================================================================= + # Tool documentation + # ========================================================================= + + def get_tool_info( + self, + __user__: dict, + ) -> str: + """ + Return the SMB tool operating guide, safety rules and current capabilities. + + This function is intended to help Open WebUI instruct the model how to use + the tool safely and correctly. + + No passwords, usernames, server names, share names, domains, credentials, + file contents, or other secret values are returned. + """ + + try: + uv = self._user_valves(__user__) + + create_allowed = bool( + self.valves.enabled + and self.valves.allow_create_files + and uv.allow_write_new_files + ) + modify_allowed = bool( + self.valves.enabled + and self.valves.allow_modify_files + and uv.allow_modify_existing_files + ) + delete_allowed = bool( + self.valves.enabled + and self.valves.allow_delete_paths + and uv.allow_delete_existing_paths + ) + directory_ops_allowed = bool( + self.valves.enabled + and self.valves.allow_directory_operations + and uv.allow_directory_operations + ) + move_copy_allowed = bool( + self.valves.enabled + and self.valves.allow_move_copy + and uv.allow_move_copy_operations + ) + recursive_delete_allowed = bool( + delete_allowed + and directory_ops_allowed + and self.valves.allow_recursive_delete + ) + + info = { + "tool": "SMB File Operations Tool", + "version": "0.1.0", + "purpose": ( + "Provide controlled SMB2/SMB3 file operations inside the " + "current user's configured SMB share and optional root_path." + ), + "path_model": { + "paths_are_relative": True, + "logical_root": ( + "All tool paths are relative to the configured SMB share " + "and optional UserValves.root_path." + ), + "absolute_paths_allowed": False, + "unc_paths_allowed": False, + "parent_traversal_allowed": False, + "alternate_data_streams_allowed_by_admin": ( + self.valves.allow_alternate_data_streams + ), + }, + "current_user_capabilities": { + "tool_enabled_by_admin": self.valves.enabled, + "smb_connection_configured": bool( + uv.server.strip() and uv.share.strip() + ), + "authentication_identity_configured": bool( + uv.username.strip() or uv.password + ), + "root_path_configured": bool(uv.root_path.strip()), + "smb_encryption_requested": uv.encrypt, + "create_new_files_allowed": create_allowed, + "modify_existing_files_allowed": modify_allowed, + "delete_existing_paths_allowed": delete_allowed, + "directory_operations_allowed": directory_ops_allowed, + "move_copy_operations_allowed": move_copy_allowed, + "recursive_delete_allowed": recursive_delete_allowed, + }, + "administrator_limits": { + "max_read_bytes": self.valves.max_read_bytes, + "max_write_bytes": self.valves.max_write_bytes, + "max_list_entries": self.valves.max_list_entries, + "max_search_results": self.valves.max_search_results, + "max_search_depth": self.valves.max_search_depth, + }, + "safety_rules": [ + ( + "Use get_tool_info when capabilities or safe operating " + "rules are unclear." + ), + ( + "Never invent a path when the target is uncertain. " + "Use list_directory, search_files or stat_path first." + ), + ( + "Treat all paths as relative to the configured SMB " + "share/root_path. Do not construct UNC, drive-letter or " + "absolute paths." + ), + ( + "Do not attempt '..' path traversal. The tool rejects " + "parent-directory traversal." + ), + ( + "Read a file before modifying it when the existing " + "contents or exact target text matter." + ), + ( + "Prefer update_file for small exact text changes instead " + "of rewriting an entire existing text file." + ), + ( + "When using update_file for a sensitive or targeted " + "change, set expected_replacements when the expected " + "number of matches is known." + ), + ( + "Do not set overwrite=true unless replacing an existing " + "destination is explicitly intended." + ), + ( + "Do not use create_if_missing=true with append_file " + "unless creating a missing file is explicitly intended." + ), + ( + "Use create_parents=true only when missing destination " + "directories should intentionally be created." + ), + ( + "Deletion requires both administrator permission and " + "current-user permission." + ), + ( + "Recursive directory deletion additionally requires the " + "administrator recursive-delete master switch." + ), + ( + "Before moving, copying, overwriting or deleting an " + "important path, use stat_path or list_directory when " + "necessary to verify the target." + ), + ( + "Large reads should be performed in chunks with offset " + "and max_bytes. Administrator limits always take precedence." + ), + ( + "Use as_base64=true for binary reads and " + "content_is_base64=true for binary writes." + ), + ( + "Credentials, usernames, passwords, domains, SMB server " + "names and share names are not returned by get_tool_info." + ), + ], + "recommended_workflow": [ + ( + "Call test_connection when SMB connectivity or the current " + "configuration needs to be verified." + ), + ( + "Use list_directory to inspect a known directory." + ), + ( + "Use search_files when the location of a file is unknown." + ), + ( + "Use stat_path to verify file/directory type, size and " + "timestamps before an operation when relevant." + ), + ( + "Use read_file before editing when current contents matter." + ), + ( + "Use write_file for new files; leave overwrite=false unless " + "replacement is intended." + ), + ( + "Use update_file for exact text replacement in existing " + "text files." + ), + ( + "Use append_file only when adding data to the end of a " + "file is semantically correct." + ), + ( + "Use make_directory for intentional directory creation." + ), + ( + "Use copy_file or move_path only when move/copy capability " + "is enabled for the current user." + ), + ( + "Use delete_path only when deletion is explicitly required " + "and permitted." + ), + ], + "functions": { + "get_tool_info": ( + "Return operating instructions, safety rules, limits and " + "effective current-user capabilities." + ), + "test_connection": ( + "Test SMB connectivity, authentication and access to the " + "configured logical root." + ), + "list_directory": ( + "List files and directories in a relative SMB directory, " + "optionally using an SMB wildcard pattern." + ), + "stat_path": ( + "Return metadata for a relative file or directory." + ), + "read_file": ( + "Read text or binary/base64 file data, with offset and " + "chunk-size support." + ), + "search_files": ( + "Recursively search for file/directory names using " + "wildcard patterns within administrator limits." + ), + "write_file": ( + "Create a new file or explicitly overwrite an existing " + "file when permissions allow." + ), + "append_file": ( + "Append text or binary data to an existing file, or " + "optionally create it when permitted." + ), + "update_file": ( + "Perform controlled exact-text replacement in an existing " + "text file." + ), + "make_directory": ( + "Create a directory and optionally missing parent " + "directories when permitted." + ), + "copy_file": ( + "Copy a file inside the configured SMB logical root." + ), + "move_path": ( + "Rename or move a file/directory inside the configured " + "SMB logical root." + ), + "delete_path": ( + "Delete a file or directory when user/admin permissions " + "allow; recursive deletion has an additional admin gate." + ), + }, + "examples": [ + { + "goal": "Find a report when its location is unknown", + "workflow": [ + "search_files(pattern='report*')", + "stat_path(path='')", + "read_file(path='')", + ], + }, + { + "goal": "Safely change one configuration value", + "workflow": [ + "read_file(path='config/app.conf')", + ( + "update_file(path='config/app.conf', " + "old_text='', " + "new_text='', " + "expected_replacements=1)" + ), + ], + }, + { + "goal": "Create a new text document", + "workflow": [ + ( + "write_file(path='notes/new-note.txt', " + "content='', overwrite=False)" + ) + ], + }, + { + "goal": "Read a large file in chunks", + "workflow": [ + ( + "read_file(path='', offset=0, " + "max_bytes=)" + ), + ( + "Continue with offset increased by the returned " + "bytes_returned while truncated=true." + ), + ], + }, + ], + } + + return self._json(info) + + except Exception as exc: + return self._json( + { + "tool": "SMB File Operations Tool", + "version": "0.1.0", + "available": False, + "error": self._error_text(exc), + "note": ( + "No credentials or secret configuration values are " + "included in this response." + ), + } + ) + # --------------------------------------------------------------------- # Read-only operations # ---------------------------------------------------------------------